diff options
Diffstat (limited to 'phpBB/includes/template')
-rw-r--r-- | phpBB/includes/template/compile.php | 23 | ||||
-rw-r--r-- | phpBB/includes/template/filter.php | 202 | ||||
-rw-r--r-- | phpBB/includes/template/locator.php | 56 | ||||
-rw-r--r-- | phpBB/includes/template/template.php | 116 |
4 files changed, 288 insertions, 109 deletions
diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 82b301c1a2..fcdaf7abda 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -35,16 +35,23 @@ class phpbb_template_compile /** * Constructor. * - * @param bool @allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag) + * @param bool $allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag) + * @param array $style_names Name of style to which the template being compiled belongs and parents in style tree order * @param phpbb_style_resource_locator $locator Resource locator * @param string $phpbb_root_path Path to phpBB root directory + * @param phpbb_extension_manager $extension_manager Extension manager to use for finding template fragments in extensions; if null, template events will not be invoked + * @param phpbb_user $user Current user */ - public function __construct($allow_php, $locator, $phpbb_root_path) + public function __construct($allow_php, $style_names, $locator, $phpbb_root_path, $extension_manager = null, $user = null) { $this->filter_params = array( 'allow_php' => $allow_php, + 'style_names' => $style_names, 'locator' => $locator, - 'phpbb_root_path' => $phpbb_root_path + 'phpbb_root_path' => $phpbb_root_path, + 'extension_manager' => $extension_manager, + 'user' => $user, + 'template_compile' => $this, ); } @@ -58,6 +65,9 @@ class phpbb_template_compile */ public function compile_file_to_file($source_file, $compiled_file) { + $lock = new phpbb_lock_flock($compiled_file); + $lock->acquire(); + $source_handle = @fopen($source_file, 'rb'); $destination_handle = @fopen($compiled_file, 'wb'); @@ -66,16 +76,15 @@ class phpbb_template_compile return false; } - @flock($destination_handle, LOCK_EX); - $this->compile_stream_to_stream($source_handle, $destination_handle); @fclose($source_handle); - @flock($destination_handle, LOCK_UN); @fclose($destination_handle); phpbb_chmod($compiled_file, CHMOD_READ | CHMOD_WRITE); + $lock->release(); + clearstatcache(); return true; @@ -118,7 +127,7 @@ class phpbb_template_compile * * @param resource $source_stream Source stream * @param resource $dest_stream Destination stream - * @return void + * @return null */ private function compile_stream_to_stream($source_stream, $dest_stream) { diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index abee32c8f7..f73ad28ba1 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -88,6 +88,37 @@ class phpbb_template_filter extends php_user_filter private $phpbb_root_path; /** + * Name of the style that the template being compiled and/or rendered + * belongs to, and its parents, in inheritance tree order. + * + * Used to invoke style-specific template events. + * + * @var array + */ + private $style_names; + + /** + * Extension manager. + * + * @var phpbb_extension_manager + */ + private $extension_manager; + + /** + * Current user + * + * @var phpbb_user + */ + private $user; + + /** + * Template compiler. + * + * @var phpbb_template_compile + */ + private $template_compile; + + /** * Stream filter * * Is invoked for evey chunk of the stream, allowing us @@ -138,8 +169,10 @@ class phpbb_template_filter extends php_user_filter /** * Initializer, called on creation. * - * Get the allow_php option, root directory and locator from params, + * Get the allow_php option, style_names, root directory and locator from params, * which are passed to stream_filter_append. + * + * @return boolean Returns true */ public function onCreate() { @@ -148,6 +181,13 @@ class phpbb_template_filter extends php_user_filter $this->allow_php = $this->params['allow_php']; $this->locator = $this->params['locator']; $this->phpbb_root_path = $this->params['phpbb_root_path']; + $this->style_names = $this->params['style_names']; + $this->extension_manager = $this->params['extension_manager']; + if (isset($this->params['user'])) + { + $this->user = $this->params['user']; + } + $this->template_compile = $this->params['template_compile']; return true; } @@ -229,7 +269,9 @@ class phpbb_template_filter extends php_user_filter } /** - * Callback for replacing matched tokens with PHP code + * Callback for replacing matched tokens with compiled template code. + * + * Compiled template code is an HTML stream with embedded PHP. * * @param array $matches Regular expression matches * @return string compiled template code @@ -317,6 +359,10 @@ class phpbb_template_filter extends php_user_filter return '<!-- ENDPHP -->'; break; + case 'EVENT': + return '<?php ' . $this->compile_tag_event($matches[2]) . '?>'; + break; + default: return $matches[0]; break; @@ -362,6 +408,43 @@ class phpbb_template_filter extends php_user_filter } /** + * Parse paths of the form {FOO}/a/{BAR}/b + * + * Note: this method assumes at least one variable in the path, this should + * be checked before this method is called. + * + * @param string $path The path to parse + * @param string $include_type The type of template function to call + * @return string An appropriately formatted string to include in the + * template or an empty string if an expression like S_FIRST_ROW was + * incorrectly used + */ + private function parse_dynamic_path($path, $include_type) + { + $matches = array(); + $replace = array(); + $is_expr = true; + + preg_match_all('#\{((?:' . self::REGEX_NS . '\.)*)(\$)?(' . self::REGEX_VAR . ')\}#', $path, $matches); + foreach ($matches[0] as $var_str) + { + $tmp_is_expr = false; + $var = $this->get_varref($var_str, $tmp_is_expr); + $is_expr = $is_expr && $tmp_is_expr; + $replace[] = "' . $var . '"; + } + + if (!$is_expr) + { + return " \$_template->$include_type('" . str_replace($matches[0], $replace, $path) . "', true);"; + } + else + { + return ''; + } + } + + /** * Compile variables * * @param string $text_blocks Variable reference in source template @@ -774,15 +857,9 @@ class phpbb_template_filter extends php_user_filter private function compile_tag_include($tag_args) { // Process dynamic includes - if ($tag_args[0] == '{') + if (strpos($tag_args, '{') !== false) { - $var = $this->get_varref($tag_args, $is_expr); - - // Make sure someone didn't try to include S_FIRST_ROW or similar - if (!$is_expr) - { - return "if (isset($var)) { \$_template->_tpl_include($var); }"; - } + return $this->parse_dynamic_path($tag_args, '_tpl_include'); } return "\$_template->_tpl_include('$tag_args');"; @@ -796,10 +873,106 @@ class phpbb_template_filter extends php_user_filter */ private function compile_tag_include_php($tag_args) { + if (strpos($tag_args, '{') !== false) + { + return $this->parse_dynamic_path($tag_args, '_php_include'); + } + return "\$_template->_php_include('$tag_args');"; } /** + * Compile EVENT tag. + * + * $tag_args should be a single string identifying the event. + * The event name can contain letters, numbers and underscores only. + * If an invalid event name is specified, an E_USER_ERROR will be + * triggered. + * + * Event tags are only functional when the template engine has + * an instance of the extension manager. Extension manager would + * be called upon to find all extensions listening for the specified + * event, and to obtain additional template fragments. All such + * template fragments will be compiled and included in the generated + * compiled template code for the current template being compiled. + * + * The above means that whenever an extension is enabled or disabled, + * template cache should be cleared in order to update the compiled + * template code for the active set of template event listeners. + * + * This also means that extensions cannot return different template + * fragments at different times. Once templates are compiled, changing + * such template fragments would have no effect. + * + * @param string $tag_args EVENT tag arguments, as a string - for EVENT this is the event name + * @return string compiled template code + */ + private function compile_tag_event($tag_args) + { + if (!preg_match('/^\w+$/', $tag_args)) + { + // The event location is improperly formatted, + if ($this->user) + { + trigger_error($this->user->lang('ERR_TEMPLATE_EVENT_LOCATION', $tag_args), E_USER_ERROR); + } + else + { + trigger_error(sprintf('The specified template event location <em>[%s]</em> is improperly formatted.', $tag_args), E_USER_ERROR); + } + } + $location = $tag_args; + + if ($this->extension_manager) + { + $finder = $this->extension_manager->get_finder(); + + $files = $finder + ->extension_prefix($location) + ->extension_suffix('.html') + ->extension_directory("/styles/all/template") + ->get_files(); + + foreach ($this->style_names as $style_name) + { + $more_files = $finder + ->extension_prefix($location) + ->extension_suffix('.html') + ->extension_directory("/styles/" . $style_name . "/template") + ->get_files(); + if (!empty($more_files)) + { + $files = array_merge($files, $more_files); + break; + } + } + + $all_compiled = ''; + foreach ($files as $file) + { + $compiled = $this->template_compile->compile_file($file); + + if ($compiled === false) + { + if ($this->user) + { + trigger_error($this->user->lang('ERR_TEMPLATE_COMPILATION', phpbb_filter_root_path($file)), E_USER_ERROR); + } + else + { + trigger_error(sprintf('The file could not be compiled: %s', phpbb_filter_root_path($file)), E_USER_ERROR); + } + } + + $all_compiled .= $compiled; + } + // Need spaces inside php tags as php cannot grok + // < ?php? > sans the spaces + return ' ?' . '>' . $all_compiled . '<?php '; + } + } + + /** * parse expression * This is from Smarty */ @@ -883,14 +1056,9 @@ class phpbb_template_filter extends php_user_filter private function compile_tag_include_js($tag_args) { // Process dynamic includes - if ($tag_args[0] == '{') + if (strpos($tag_args, '{') !== false) { - $var = $this->get_varref($tag_args, $is_expr); - if (!$is_expr) - { - return " \$_template->_js_include($var, true);"; - } - return ''; + return $this->parse_dynamic_path($tag_args, '_js_include'); } // Locate file diff --git a/phpBB/includes/template/locator.php b/phpBB/includes/template/locator.php index 01c79eec4e..f6fd20bcc2 100644 --- a/phpBB/includes/template/locator.php +++ b/phpBB/includes/template/locator.php @@ -39,7 +39,7 @@ interface phpbb_template_locator * Sets the template filenames for handles. $filename_array * should be a hash of handle => filename pairs. * - * @param array $filname_array Should be a hash of handle => filename pairs. + * @param array $filename_array Should be a hash of handle => filename pairs. */ public function set_filenames(array $filename_array); @@ -66,7 +66,7 @@ interface phpbb_template_locator * returns actually exists, it is faster than get_source_file_for_handle. * * Use get_source_file_for_handle to obtain the actual path that is - * guaranteed to exist (which might come from the parent style + * guaranteed to exist (which might come from the parent style * directory if primary style has parent styles). * * This function will trigger an error if the handle was never @@ -99,12 +99,54 @@ interface phpbb_template_locator public function get_source_file_for_handle($handle, $find_all = false); /** - * Locates source file path, accounting for styles tree and verifying that - * the path exists. + * Obtains a complete filesystem path for a file in a style. * - * Unlike previous functions, this function works without template handle - * and it can search for more than one file. If more than one file name is - * specified, it will return location of file that it finds first. + * This function traverses the style tree (selected style and + * its parents in order, if inheritance is being used) and finds + * the first file on the filesystem matching specified relative path, + * or the first of the specified paths if more than one path is given. + * + * This function can be used to determine filesystem path of any + * file under any style, with the consequence being that complete + * relative to the style directory path must be provided as an argument. + * + * In particular, this function can be used to locate templates + * and javascript files. + * + * For locating templates get_first_template_location should be used + * as it prepends the configured template path to the template basename. + * + * Note: "selected style" is whatever style the style resource locator + * is configured for. + * + * The return value then will be a path, relative to the current + * directory or absolute, to the first existing file in the selected + * style or its closest parent. + * + * If the selected style does not have the file being searched, + * (and if inheritance is involved, none of the parents have it either), + * false will be returned. + * + * Multiple files can be specified, in which case the first file in + * the list that can be found on the filesystem is returned. + * + * If multiple files are specified and inheritance is involved, + * first each of the specified files is checked in the selected style, + * then each of the specified files is checked in the immediate parent, + * etc. + * + * Specifying true for $return_default will cause the function to + * return the first path which was checked for existence in the event + * that the template file was not found, instead of false. + * This is always a path in the selected style itself, not any of its + * parents. + * + * If $return_full_path is false, then instead of returning a usable + * path (when the file is found) the file's path relative to the style + * directory will be returned. This is the same path as was given to + * the function as a parameter. This can be used to check which of the + * files specified in $files exists. Naturally this requires passing + * more than one file in $files. * * @param array $files List of files to locate. * @param bool $return_default Determines what to return if file does not diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index 5d3ce4c82b..bbec768613 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -75,10 +75,21 @@ class phpbb_template private $locator; /** - * Location of templates directory within style directories - * @var string + * Extension manager. + * + * @var phpbb_extension_manager + */ + private $extension_manager; + + /** + * Name of the style that the template being compiled and/or rendered + * belongs to, and its parents, in inheritance tree order. + * + * Used to invoke style-specific template events. + * + * @var array */ - public $template_path = 'template/'; + private $style_names; /** * Constructor. @@ -87,22 +98,23 @@ class phpbb_template * @param user $user current user * @param phpbb_template_locator $locator template locator * @param phpbb_template_context $context template context + * @param phpbb_extension_manager $extension_manager extension manager, if null then template events will not be invoked */ - public function __construct($phpbb_root_path, $php_ext, $config, $user, phpbb_template_locator $locator, phpbb_template_context $context) + public function __construct($phpbb_root_path, $php_ext, $config, $user, phpbb_template_locator $locator, phpbb_template_context $context, phpbb_extension_manager $extension_manager = null) { $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; $this->config = $config; $this->user = $user; $this->locator = $locator; - $this->template_path = $this->locator->template_path; $this->context = $context; + $this->extension_manager = $extension_manager; } /** * Sets the template filenames for handles. * - * @param array $filname_array Should be a hash of handle => filename pairs. + * @param array $filename_array Should be a hash of handle => filename pairs. */ public function set_filenames(array $filename_array) { @@ -112,6 +124,18 @@ class phpbb_template } /** + * Sets the style names corresponding to style hierarchy being compiled + * and/or rendered. + * + * @param array $style_names List of style names in inheritance tree order + * @return null + */ + public function set_style_names(array $style_names) + { + $this->style_names = $style_names; + } + + /** * Clears all variables and blocks assigned to this template. */ public function destroy() @@ -250,7 +274,7 @@ class phpbb_template * If template cache is writable the compiled php code will be stored * on filesystem and template will not be subsequently recompiled. * If template cache is not writable template source will be recompiled - * every time it is needed. DEBUG_EXTRA define and load_tplcompile + * every time it is needed. DEBUG define and load_tplcompile * configuration setting may be used to force templates to be always * recompiled. * @@ -268,7 +292,7 @@ class phpbb_template { $output_file = $this->_compiled_file_for_handle($handle); - $recompile = defined('DEBUG_EXTRA') || + $recompile = defined('DEBUG') || !file_exists($output_file) || @filesize($output_file) === 0; @@ -289,7 +313,7 @@ class phpbb_template return new phpbb_template_renderer_include($output_file, $this); } - $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->locator, $this->phpbb_root_path); + $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->style_names, $this->locator, $this->phpbb_root_path, $this->extension_manager, $this->user); if ($compile->compile_file_to_file($source_file, $output_file) !== false) { @@ -459,74 +483,6 @@ class phpbb_template } /** - * Obtains filesystem path for a template file. - * - * The simplest use is specifying a single template file as a string - * in the first argument. This template file should be a basename - * of a template file in the selected style, or its parent styles - * if template inheritance is being utilized. - * - * Note: "selected style" is whatever style the style resource locator - * is configured for. - * - * The return value then will be a path, relative to the current - * directory or absolute, to the template file in the selected style - * or its closest parent. - * - * If the selected style does not have the template file being searched, - * (and if inheritance is involved, none of the parents have it either), - * false will be returned. - * - * Specifying true for $return_default will cause the function to - * return the first path which was checked for existence in the event - * that the template file was not found, instead of false. - * This is the path in the selected style itself, not any of its - * parents. - * - * $files can be given an array of templates instead of a single - * template. When given an array, the function will try to resolve - * each template in the array to a path, and will return the first - * path that exists, or false if none exist. - * - * If $return_full_path is false, then instead of returning a usable - * path (when the template is found) only the template's basename - * will be returned. This can be used to check which of the templates - * specified in $files exists, provided different file names are - * used for different templates. - * - * @param string or array $files List of templates to locate. If there is only - * one template, $files can be a string to make code easier to read. - * @param bool $return_default Determines what to return if template does not - * exist. If true, function will return location where template is - * supposed to be. If false, function will return false. - * @param bool $return_full_path If true, function will return full path - * to template. If false, function will return template file name. - * This parameter can be used to check which one of set of template - * files is available. - * @return string or boolean Source template path if template exists or $return_default is - * true. False if template does not exist and $return_default is false - */ - public function locate($files, $return_default = false, $return_full_path = true) - { - // add template path prefix - $templates = array(); - if (is_string($files)) - { - $templates[] = $this->template_path . $files; - } - else - { - foreach ($files as $file) - { - $templates[] = $this->template_path . $file; - } - } - - // use resource locator to find files - return $this->locator->get_first_file_location($templates, $return_default, $return_full_path); - } - - /** * Include JS file * * @param string $file file name @@ -538,7 +494,11 @@ class phpbb_template // Locate file if ($locate) { - $file = $this->locator->get_first_file_location(array($file), true, true); + $located = $this->locator->get_first_file_location(array($file), false, true); + if ($located) + { + $file = $located; + } } else if ($relative) { |