From 4091f873eaa108cebd3192ede979ce61ead09238 Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 18 Oct 2010 21:25:52 +0800 Subject: [ticket/6712] Bump does not create new topic icon on index. Handle the topic bumping process more properly. PHPBB3-6712 --- phpBB/includes/functions_posting.php | 91 ++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 6fd87db663..041b549cd6 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -2611,4 +2611,95 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u return $url; } +/* +* Handle topic bumping +*/ +function bump_topic($forum_id, $topic_id, &$post_data, $current_time = false) +{ + global $config, $db, $user, $phpEx, $phpbb_root_path; + + if ($current_time === false) + { + $current_time = time(); + } + + // Begin bumping + $db->sql_transaction('begin'); + + // Update the topic's last post post_time + $sql = 'UPDATE ' . POSTS_TABLE . " + SET post_time = $current_time + WHERE post_id = {$post_data['topic_last_post_id']} + AND topic_id = $topic_id"; + $db->sql_query($sql); + + // Sync the topic's last post time, the rest of the topic's last post data isn't changed + $sql = 'UPDATE ' . TOPICS_TABLE . " + SET topic_last_post_time = $current_time, + topic_bumped = 1, + topic_bumper = " . $user->data['user_id'] . " + WHERE topic_id = $topic_id"; + $db->sql_query($sql); + + // Update the forum's last post info + $sql = 'UPDATE ' . FORUMS_TABLE . " + SET forum_last_post_id = " . $post_data['topic_last_post_id'] . ", + forum_last_poster_id = " . $post_data['topic_last_poster_id'] . ", + forum_last_post_subject = '" . $db->sql_escape($post_data['topic_last_post_subject']) . "', + forum_last_post_time = $current_time, + forum_last_poster_name = '" . $db->sql_escape($post_data['topic_last_poster_name']) . "', + forum_last_poster_colour = '" . $db->sql_escape($post_data['topic_last_poster_colour']) . "' + WHERE forum_id = $forum_id"; + $db->sql_query($sql); + + // Update bumper's time of the last posting to prevent flood + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_lastpost_time = $current_time + WHERE user_id = " . $user->data['user_id']; + $db->sql_query($sql); + + $db->sql_transaction('commit'); + + // Mark this topic as posted to + markread('post', $forum_id, $topic_id, $current_time); + + // Mark this topic as read + markread('topic', $forum_id, $topic_id, $current_time); + + // Update forum tracking info + if ($config['load_db_lastread'] && $user->data['is_registered']) + { + $sql = 'SELECT mark_time + FROM ' . FORUMS_TRACK_TABLE . ' + WHERE user_id = ' . $user->data['user_id'] . ' + AND forum_id = ' . $forum_id; + $result = $db->sql_query($sql); + $f_mark_time = (int) $db->sql_fetchfield('mark_time'); + $db->sql_freeresult($result); + } + else if ($config['load_anon_lastread'] || $user->data['is_registered']) + { + $f_mark_time = false; + } + + if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered']) + { + // Update forum info + $sql = 'SELECT forum_last_post_time + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . $forum_id; + $result = $db->sql_query($sql); + $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time'); + $db->sql_freeresult($result); + + update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time, false); + } + + add_log('mod', $forum_id, $topic_id, 'LOG_BUMP_TOPIC', $post_data['topic_title']); + + $url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&p={$post_data['topic_last_post_id']}") . "#p{$post_data['topic_last_post_id']}"; + + return $url; +} + ?> \ No newline at end of file -- cgit v1.2.1 From 5ab4dc298327d3a8d51387959d6905c6bb24fd99 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 5 Mar 2011 22:16:50 +0100 Subject: [ticket/10042] Add mt_rand() wrapper which allows swapping $min and $max. PHPBB3-10042 --- phpBB/includes/functions.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 398a02380b..259b3b0481 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -244,6 +244,22 @@ function unique_id($extra = 'c') return substr($val, 4, 16); } +/** +* Wrapper for mt_rand() which allows swapping $min and $max parameters. +* +* PHP does not allow us to swap the order of the arguments for mt_rand() anymore. +* (since PHP 5.3.4, see http://bugs.php.net/46587) +* +* @param int $min Lowest value to be returned +* @param int $max Highest value to be returned +* +* @return int Random integer between $min and $max (or $max and $min) +*/ +function phpbb_mt_rand($min, $max) +{ + return ($min > $max) ? mt_rand($max, $min) : mt_rand($min, $max); +} + /** * Return formatted string for filesizes * -- cgit v1.2.1 From c6c2a23ecb10b4b54e7e9b703d14e8c7cda6ad55 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 5 Mar 2011 22:20:23 +0100 Subject: [ticket/10042] GD CAPTCHA: Round offset to the next pixel. PHPBB3-10042 --- phpBB/includes/captcha/captcha_gd.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/captcha/captcha_gd.php b/phpBB/includes/captcha/captcha_gd.php index 96e39af85b..7a3f4f46ab 100644 --- a/phpBB/includes/captcha/captcha_gd.php +++ b/phpBB/includes/captcha/captcha_gd.php @@ -77,7 +77,7 @@ class captcha { $denom = ($code_len - $i); $denom = max(1.3, $denom); - $offset[$i] = mt_rand(0, (1.5 * $width_avail) / $denom); + $offset[$i] = mt_rand(0, (int) round((1.5 * $width_avail) / $denom)); $width_avail -= $offset[$i]; } -- cgit v1.2.1 From 18daf6345f64e59f651c43a3150d9e139ac2a4cc Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 5 Mar 2011 22:21:45 +0100 Subject: [ticket/10042] GD CAPTCHA: Call phpbb_mt_rand() where required. PHPBB3-10042 --- phpBB/includes/captcha/captcha_gd.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/captcha/captcha_gd.php b/phpBB/includes/captcha/captcha_gd.php index 7a3f4f46ab..6d859a4ecc 100644 --- a/phpBB/includes/captcha/captcha_gd.php +++ b/phpBB/includes/captcha/captcha_gd.php @@ -77,7 +77,7 @@ class captcha { $denom = ($code_len - $i); $denom = max(1.3, $denom); - $offset[$i] = mt_rand(0, (int) round((1.5 * $width_avail) / $denom)); + $offset[$i] = phpbb_mt_rand(0, (int) round((1.5 * $width_avail) / $denom)); $width_avail -= $offset[$i]; } -- cgit v1.2.1 From d1bd5962c75fc87469694ae93829a5800c30c6cc Mon Sep 17 00:00:00 2001 From: rxu Date: Sun, 3 Apr 2011 01:00:21 +0800 Subject: [ticket/6712] Pass $post_data by the value instead of by the reference. PHPBB3-6712 --- phpBB/includes/functions_posting.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 041b549cd6..ab346afb38 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -2614,7 +2614,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u /* * Handle topic bumping */ -function bump_topic($forum_id, $topic_id, &$post_data, $current_time = false) +function bump_topic($forum_id, $topic_id, $post_data, $current_time = false) { global $config, $db, $user, $phpEx, $phpbb_root_path; -- cgit v1.2.1 From ee6167879ecba11dea945f129c026ce0f3cf7514 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 17 Mar 2011 01:20:44 +0100 Subject: [ticket/9802] Fix redundant str_replace call. No need to replace ' ' with ' '. PHPBB3-9802 --- phpBB/includes/session.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index d803f8d799..9ab53d38ab 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -221,7 +221,7 @@ class session // if the forwarded for header shall be checked we have to validate its contents if ($config['forwarded_for_check']) { - $this->forwarded_for = preg_replace('#[ ]{2,}#', ' ', str_replace(array(',', ' '), ' ', $this->forwarded_for)); + $this->forwarded_for = preg_replace('#[ ]{2,}#', ' ', str_replace(',', ' ', $this->forwarded_for)); // split the list of IPs $ips = explode(' ', $this->forwarded_for); @@ -268,7 +268,7 @@ class session // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars((string) $_SERVER['REMOTE_ADDR']) : ''; - $this->ip = preg_replace('#[ ]{2,}#', ' ', str_replace(array(',', ' '), ' ', $this->ip)); + $this->ip = preg_replace('#[ ]{2,}#', ' ', str_replace(',', ' ', $this->ip)); // split the list of IPs $ips = explode(' ', $this->ip); -- cgit v1.2.1 From fd805358592162cf05c8808caca0bdf788fb7088 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 17 Mar 2011 01:29:10 +0100 Subject: [ticket/9802] Remove redundant character class definition from preg_replace. PHPBB3-9802 --- phpBB/includes/session.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index 9ab53d38ab..e1e315035b 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -221,7 +221,7 @@ class session // if the forwarded for header shall be checked we have to validate its contents if ($config['forwarded_for_check']) { - $this->forwarded_for = preg_replace('#[ ]{2,}#', ' ', str_replace(',', ' ', $this->forwarded_for)); + $this->forwarded_for = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->forwarded_for)); // split the list of IPs $ips = explode(' ', $this->forwarded_for); @@ -268,7 +268,7 @@ class session // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars((string) $_SERVER['REMOTE_ADDR']) : ''; - $this->ip = preg_replace('#[ ]{2,}#', ' ', str_replace(',', ' ', $this->ip)); + $this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip)); // split the list of IPs $ips = explode(' ', $this->ip); -- cgit v1.2.1 From bef2540d9ce3b429837c7e67c5f3f7f254aa1920 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 19 Apr 2011 13:46:00 +0200 Subject: [ticket/9802] Fix tiny logic bug in loop determining REMOTE_ADDR. When $ip is empty() it was assigned to $this->ip. PHPBB3-9802 --- phpBB/includes/session.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index e1e315035b..f2aa47d84e 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -271,7 +271,7 @@ class session $this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip)); // split the list of IPs - $ips = explode(' ', $this->ip); + $ips = explode(' ', trim($this->ip)); // Default IP if REMOTE_ADDR is invalid $this->ip = '127.0.0.1'; @@ -279,7 +279,7 @@ class session foreach ($ips as $ip) { // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly - if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) + if (!preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) { // Just break break; -- cgit v1.2.1 From 5ca7121ed2f698963387f5f9fb7ffe16d3781447 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 19 Apr 2011 13:53:09 +0200 Subject: [ticket/9802] Only check for IPv4-mapped address when address is IPv6. PHPBB3-9802 --- phpBB/includes/session.php | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index f2aa47d84e..b2772696f1 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -278,26 +278,31 @@ class session foreach ($ips as $ip) { - // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly - if (!preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) + if (preg_match(get_preg_expression('ipv4'), $ip)) { - // Just break - break; + $this->ip = $ip; } - - // Quick check for IPv4-mapped address in IPv6 - if (stripos($ip, '::ffff:') === 0) + else if (preg_match(get_preg_expression('ipv6'), $ip)) { - $ipv4 = substr($ip, 7); - - if (preg_match(get_preg_expression('ipv4'), $ipv4)) + // Quick check for IPv4-mapped address in IPv6 + if (stripos($ip, '::ffff:') === 0) { - $ip = $ipv4; + $ipv4 = substr($ip, 7); + + if (preg_match(get_preg_expression('ipv4'), $ipv4)) + { + $ip = $ipv4; + } } - } - // Use the last in chain - $this->ip = $ip; + $this->ip = $ip; + } + else + { + // We want to use the last valid address in the chain + // Leave foreach loop when address is invalid + break; + } } $this->load = false; -- cgit v1.2.1 From d1f1d8ade7ab98bde70451874c94bb35584f9192 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 19 Apr 2011 14:10:23 +0200 Subject: [ticket/9802] Remove unnecessary htmlspecialchars() call on REMOTE_ADDR. The value in $_SERVER['REMOTE_ADDR'] is either validated to be a valid IP address or is replaced by our default value. Valid IP addresses do not contain HTML special characters, thus the htmlspecialchars() call is unnecessary. PHPBB3-9802 --- phpBB/includes/session.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index b2772696f1..79d94e7780 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -267,7 +267,7 @@ class session // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. - $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars((string) $_SERVER['REMOTE_ADDR']) : ''; + $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? (string) $_SERVER['REMOTE_ADDR'] : ''; $this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip)); // split the list of IPs -- cgit v1.2.1 From 9cb6a69861b2ef1ca9a23ffe773ca3be4f9e4461 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 22 Apr 2011 11:01:07 +0200 Subject: [ticket/10146] Firebird: 1 <= precision <= 18 ==> Cast to DECIMAL(18, 0). PHPBB3-10146 --- phpBB/includes/functions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 585e23b2ee..ca5a483536 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -175,7 +175,8 @@ function set_config_count($config_name, $increment, $is_dynamic = false) switch ($db->sql_layer) { case 'firebird': - $sql_update = 'CAST(CAST(config_value as DECIMAL(255, 0)) + ' . (int) $increment . ' as VARCHAR(255))'; + // Precision must be from 1 to 18 + $sql_update = 'CAST(CAST(config_value as DECIMAL(18, 0)) + ' . (int) $increment . ' as VARCHAR(255))'; break; case 'postgres': -- cgit v1.2.1 From 2d11e1c095b7cf6197b7ce21bde806ad2cc178d8 Mon Sep 17 00:00:00 2001 From: "Marek A. Ruszczynski" Date: Mon, 7 Mar 2011 16:59:41 +0100 Subject: [feature/template-engine] Improved template engine. PHPBB3-9726 --- phpBB/includes/functions_template.php | 812 ---------------------------- phpBB/includes/template.php | 287 +++++++--- phpBB/includes/template_compile.php | 982 ++++++++++++++++++++++++++++++++++ 3 files changed, 1204 insertions(+), 877 deletions(-) delete mode 100644 phpBB/includes/functions_template.php create mode 100644 phpBB/includes/template_compile.php (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_template.php b/phpBB/includes/functions_template.php deleted file mode 100644 index 8c58c33b0d..0000000000 --- a/phpBB/includes/functions_template.php +++ /dev/null @@ -1,812 +0,0 @@ -template = &$template; - } - - /** - * Load template source from file - * @access private - */ - function _tpl_load_file($handle, $store_in_db = false) - { - // Try and open template for read - if (!file_exists($this->template->files[$handle])) - { - trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR); - } - - $this->template->compiled_code[$handle] = $this->compile(trim(@file_get_contents($this->template->files[$handle]))); - - // Actually compile the code now. - $this->compile_write($handle, $this->template->compiled_code[$handle]); - - // Store in database if required... - if ($store_in_db) - { - global $db, $user; - - $sql_ary = array( - 'template_id' => $this->template->files_template[$handle], - 'template_filename' => $this->template->filename[$handle], - 'template_included' => '', - 'template_mtime' => time(), - 'template_data' => trim(@file_get_contents($this->template->files[$handle])), - ); - - $sql = 'INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - } - } - - /** - * Remove any PHP tags that do not belong, these regular expressions are derived from - * the ones that exist in zend_language_scanner.l - * @access private - */ - function remove_php_tags(&$code) - { - // This matches the information gathered from the internal PHP lexer - $match = array( - '#<([\?%])=?.*?\1>#s', - '#.*?#s', - '#<\?php(?:\r\n?|[ \n\t]).*?\?>#s' - ); - - $code = preg_replace($match, '', $code); - } - - /** - * The all seeing all doing compile method. Parts are inspired by or directly from Smarty - * @access private - */ - function compile($code, $no_echo = false, $echo_var = '') - { - global $config; - - if ($echo_var) - { - global $$echo_var; - } - - // Remove any "loose" php ... we want to give admins the ability - // to switch on/off PHP for a given template. Allowing unchecked - // php is a no-no. There is a potential issue here in that non-php - // content may be removed ... however designers should use entities - // if they wish to display < and > - $this->remove_php_tags($code); - - // Pull out all block/statement level elements and separate plain text - preg_match_all('#(.*?)#s', $code, $matches); - $php_blocks = $matches[1]; - $code = preg_replace('#.*?#s', '', $code); - - preg_match_all('##', $code, $matches); - $include_blocks = $matches[1]; - $code = preg_replace('##', '', $code); - - preg_match_all('##', $code, $matches); - $includephp_blocks = $matches[1]; - $code = preg_replace('##', '', $code); - - preg_match_all('##', $code, $blocks, PREG_SET_ORDER); - - $text_blocks = preg_split('##', $code); - - for ($i = 0, $j = sizeof($text_blocks); $i < $j; $i++) - { - $this->compile_var_tags($text_blocks[$i]); - } - $compile_blocks = array(); - - for ($curr_tb = 0, $tb_size = sizeof($blocks); $curr_tb < $tb_size; $curr_tb++) - { - $block_val = &$blocks[$curr_tb]; - - switch ($block_val[1]) - { - case 'BEGIN': - $this->block_else_level[] = false; - $compile_blocks[] = 'compile_tag_block($block_val[2]) . ' ?>'; - break; - - case 'BEGINELSE': - $this->block_else_level[sizeof($this->block_else_level) - 1] = true; - $compile_blocks[] = ''; - break; - - case 'END': - array_pop($this->block_names); - $compile_blocks[] = 'block_else_level)) ? '}' : '}}') . ' ?>'; - break; - - case 'IF': - $compile_blocks[] = 'compile_tag_if($block_val[2], false) . ' ?>'; - break; - - case 'ELSE': - $compile_blocks[] = ''; - break; - - case 'ELSEIF': - $compile_blocks[] = 'compile_tag_if($block_val[2], true) . ' ?>'; - break; - - case 'ENDIF': - $compile_blocks[] = ''; - break; - - case 'DEFINE': - $compile_blocks[] = 'compile_tag_define($block_val[2], true) . ' ?>'; - break; - - case 'UNDEFINE': - $compile_blocks[] = 'compile_tag_define($block_val[2], false) . ' ?>'; - break; - - case 'INCLUDE': - $temp = array_shift($include_blocks); - - // Dynamic includes - // Cheap match rather than a full blown regexp, we already know - // the format of the input so just use string manipulation. - if ($temp[0] == '{') - { - $file = false; - - if ($temp[1] == '$') - { - $var = substr($temp, 2, -1); - //$file = $this->template->_tpldata['DEFINE']['.'][$var]; - $temp = "\$this->_tpldata['DEFINE']['.']['$var']"; - } - else - { - $var = substr($temp, 1, -1); - //$file = $this->template->_rootref[$var]; - $temp = "\$this->_rootref['$var']"; - } - } - else - { - $file = $temp; - } - - $compile_blocks[] = 'compile_tag_include($temp) . ' ?>'; - - // No point in checking variable includes - if ($file) - { - $this->template->_tpl_include($file, false); - } - break; - - case 'INCLUDEPHP': - $compile_blocks[] = ($config['tpl_allow_php']) ? 'compile_tag_include_php(array_shift($includephp_blocks)) . ' ?>' : ''; - break; - - case 'PHP': - $compile_blocks[] = ($config['tpl_allow_php']) ? '' : ''; - break; - - default: - $this->compile_var_tags($block_val[0]); - $trim_check = trim($block_val[0]); - $compile_blocks[] = (!$no_echo) ? ((!empty($trim_check)) ? $block_val[0] : '') : ((!empty($trim_check)) ? $block_val[0] : ''); - break; - } - } - - $template_php = ''; - for ($i = 0, $size = sizeof($text_blocks); $i < $size; $i++) - { - $trim_check_text = trim($text_blocks[$i]); - $template_php .= (!$no_echo) ? (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : '') : (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : ''); - } - - // Remove unused opening/closing tags - $template_php = str_replace(' ?>([\r\n])#', '?>\1\1', $template_php); - - // There will be a number of occasions where we switch into and out of - // PHP mode instantaneously. Rather than "burden" the parser with this - // we'll strip out such occurences, minimising such switching - if ($no_echo) - { - return "\$$echo_var .= '" . $template_php . "'"; - } - - return $template_php; - } - - /** - * Compile variables - * @access private - */ - function compile_var_tags(&$text_blocks) - { - // change template varrefs into PHP varrefs - $varrefs = array(); - - // This one will handle varrefs WITH namespaces - preg_match_all('#\{((?:[a-z0-9\-_]+\.)+)(\$)?([A-Z0-9\-_]+)\}#', $text_blocks, $varrefs, PREG_SET_ORDER); - - foreach ($varrefs as $var_val) - { - $namespace = $var_val[1]; - $varname = $var_val[3]; - $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]); - - $text_blocks = str_replace($var_val[0], $new, $text_blocks); - } - - // This will handle the remaining root-level varrefs - // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array - if (strpos($text_blocks, '{L_') !== false) - { - $text_blocks = preg_replace('#\{L_([A-Z0-9\-_]+)\}#', "_rootref['L_\\1'])) ? \$this->_rootref['L_\\1'] : ((isset(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '{ \\1 }')); ?>", $text_blocks); - } - - // Handle addslashed language variables prefixed with LA_ - // If a template variable already exist, it will be used in favor of it... - if (strpos($text_blocks, '{LA_') !== false) - { - $text_blocks = preg_replace('#\{LA_([A-Z0-9\-_]+)\}#', "_rootref['LA_\\1'])) ? \$this->_rootref['LA_\\1'] : ((isset(\$this->_rootref['L_\\1'])) ? addslashes(\$this->_rootref['L_\\1']) : ((isset(\$user->lang['\\1'])) ? addslashes(\$user->lang['\\1']) : '{ \\1 }'))); ?>", $text_blocks); - } - - // Handle remaining varrefs - $text_blocks = preg_replace('#\{([A-Z0-9\-_]+)\}#', "_rootref['\\1'])) ? \$this->_rootref['\\1'] : ''; ?>", $text_blocks); - $text_blocks = preg_replace('#\{\$([A-Z0-9\-_]+)\}#', "_tpldata['DEFINE']['.']['\\1'])) ? \$this->_tpldata['DEFINE']['.']['\\1'] : ''; ?>", $text_blocks); - - return; - } - - /** - * Compile blocks - * @access private - */ - function compile_tag_block($tag_args) - { - $no_nesting = false; - - // Is the designer wanting to call another loop in a loop? - if (strpos($tag_args, '!') === 0) - { - // Count the number of ! occurrences (not allowed in vars) - $no_nesting = substr_count($tag_args, '!'); - $tag_args = substr($tag_args, $no_nesting); - } - - // Allow for control of looping (indexes start from zero): - // foo(2) : Will start the loop on the 3rd entry - // foo(-2) : Will start the loop two entries from the end - // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth - // foo(3,-4) : Will start the loop on the fourth entry and end it four from last - if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match)) - { - $tag_args = $match[1]; - - if ($match[2] < 0) - { - $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')'; - } - else - { - $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')'; - } - - if (strlen($match[3]) < 1 || $match[3] == -1) - { - $loop_end = '$_' . $tag_args . '_count'; - } - else if ($match[3] >= 0) - { - $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')'; - } - else //if ($match[3] < -1) - { - $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1); - } - } - else - { - $loop_start = 0; - $loop_end = '$_' . $tag_args . '_count'; - } - - $tag_template_php = ''; - array_push($this->block_names, $tag_args); - - if ($no_nesting !== false) - { - // We need to implode $no_nesting times from the end... - $block = array_slice($this->block_names, -$no_nesting); - } - else - { - $block = $this->block_names; - } - - if (sizeof($block) < 2) - { - // Block is not nested. - $tag_template_php = '$_' . $tag_args . "_count = (isset(\$this->_tpldata['$tag_args'])) ? sizeof(\$this->_tpldata['$tag_args']) : 0;"; - $varref = "\$this->_tpldata['$tag_args']"; - } - else - { - // This block is nested. - // Generate a namespace string for this block. - $namespace = implode('.', $block); - - // Get a reference to the data array for this block that depends on the - // current indices of all parent blocks. - $varref = $this->generate_block_data_ref($namespace, false); - - // Create the for loop code to iterate over this block. - $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;'; - } - - $tag_template_php .= 'if ($_' . $tag_args . '_count) {'; - - /** - * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory - * - * if (!$offset) - * { - * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){'; - * } - * - */ - - $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){'; - $tag_template_php .= '$_'. $tag_args . '_val = &' . $varref . '[$_'. $tag_args. '_i];'; - - return $tag_template_php; - } - - /** - * Compile IF tags - much of this is from Smarty with - * some adaptions for our block level methods - * @access private - */ - function compile_tag_if($tag_args, $elseif) - { - // Tokenize args for 'if' tag. - preg_match_all('/(?: - "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | - \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | - [(),] | - [^\s(),]+)/x', $tag_args, $match); - - $tokens = $match[0]; - $is_arg_stack = array(); - - for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) - { - $token = &$tokens[$i]; - - switch ($token) - { - case '!==': - case '===': - case '<<': - case '>>': - case '|': - case '^': - case '&': - case '~': - case ')': - case ',': - case '+': - case '-': - case '*': - case '/': - case '@': - break; - - case '==': - case 'eq': - $token = '=='; - break; - - case '!=': - case '<>': - case 'ne': - case 'neq': - $token = '!='; - break; - - case '<': - case 'lt': - $token = '<'; - break; - - case '<=': - case 'le': - case 'lte': - $token = '<='; - break; - - case '>': - case 'gt': - $token = '>'; - break; - - case '>=': - case 'ge': - case 'gte': - $token = '>='; - break; - - case '&&': - case 'and': - $token = '&&'; - break; - - case '||': - case 'or': - $token = '||'; - break; - - case '!': - case 'not': - $token = '!'; - break; - - case '%': - case 'mod': - $token = '%'; - break; - - case '(': - array_push($is_arg_stack, $i); - break; - - case 'is': - $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; - $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); - - $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); - - array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens); - - $i = $is_arg_start; - - // no break - - default: - if (preg_match('#^((?:[a-z0-9\-_]+\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs)) - { - $token = (!empty($varrefs[1])) ? $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']' : (($varrefs[2]) ? '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$this->_rootref[\'' . $varrefs[3] . '\']'); - } - else if (preg_match('#^\.((?:[a-z0-9\-_]+\.?)+)$#s', $token, $varrefs)) - { - // Allow checking if loops are set with .loopname - // It is also possible to check the loop count by doing for example - $blocks = explode('.', $varrefs[1]); - - // If the block is nested, we have a reference that we can grab. - // If the block is not nested, we just go and grab the block from _tpldata - if (sizeof($blocks) > 1) - { - $block = array_pop($blocks); - $namespace = implode('.', $blocks); - $varref = $this->generate_block_data_ref($namespace, true); - - // Add the block reference for the last child. - $varref .= "['" . $block . "']"; - } - else - { - $varref = '$this->_tpldata'; - - // Add the block reference for the last child. - $varref .= "['" . $blocks[0] . "']"; - } - $token = "sizeof($varref)"; - } - else if (!empty($token)) - { - $token = '(' . $token . ')'; - } - - break; - } - } - - // If there are no valid tokens left or only control/compare characters left, we do skip this statement - if (!sizeof($tokens) || str_replace(array(' ', '=', '!', '<', '>', '&', '|', '%', '(', ')'), '', implode('', $tokens)) == '') - { - $tokens = array('false'); - } - return (($elseif) ? '} else if (' : 'if (') . (implode(' ', $tokens) . ') { '); - } - - /** - * Compile DEFINE tags - * @access private - */ - function compile_tag_define($tag_args, $op) - { - preg_match('#^((?:[a-z0-9\-_]+\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (\'?)([^\']*)(\'?))?$#', $tag_args, $match); - - if (empty($match[2]) || (!isset($match[4]) && $op)) - { - return ''; - } - - if (!$op) - { - return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');'; - } - - // Are we a string? - if ($match[3] && $match[5]) - { - $match[4] = str_replace(array('\\\'', '\\\\', '\''), array('\'', '\\', '\\\''), $match[4]); - - // Compile reference, we allow template variables in defines... - $match[4] = $this->compile($match[4]); - - // Now replace the php code - $match[4] = "'" . str_replace(array(''), array("' . ", " . '"), $match[4]) . "'"; - } - else - { - preg_match('#true|false|\.#i', $match[4], $type); - - switch (strtolower($type[0])) - { - case 'true': - case 'false': - $match[4] = strtoupper($match[4]); - break; - - case '.': - $match[4] = doubleval($match[4]); - break; - - default: - $match[4] = intval($match[4]); - break; - } - } - - return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $match[4] . ';'; - } - - /** - * Compile INCLUDE tag - * @access private - */ - function compile_tag_include($tag_args) - { - // Process dynamic includes - if ($tag_args[0] == '$') - { - return "if (isset($tag_args)) { \$this->_tpl_include($tag_args); }"; - } - - return "\$this->_tpl_include('$tag_args');"; - } - - /** - * Compile INCLUDE_PHP tag - * @access private - */ - function compile_tag_include_php($tag_args) - { - return "\$this->_php_include('$tag_args');"; - } - - /** - * parse expression - * This is from Smarty - * @access private - */ - function _parse_is_expr($is_arg, $tokens) - { - $expr_end = 0; - $negate_expr = false; - - if (($first_token = array_shift($tokens)) == 'not') - { - $negate_expr = true; - $expr_type = array_shift($tokens); - } - else - { - $expr_type = $first_token; - } - - switch ($expr_type) - { - case 'even': - if (@$tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!(($is_arg / $expr_arg) % $expr_arg)"; - } - else - { - $expr = "!($is_arg & 1)"; - } - break; - - case 'odd': - if (@$tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "(($is_arg / $expr_arg) % $expr_arg)"; - } - else - { - $expr = "($is_arg & 1)"; - } - break; - - case 'div': - if (@$tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!($is_arg % $expr_arg)"; - } - break; - } - - if ($negate_expr) - { - $expr = "!($expr)"; - } - - array_splice($tokens, 0, $expr_end, $expr); - - return $tokens; - } - - /** - * Generates a reference to the given variable inside the given (possibly nested) - * block namespace. This is a string of the form: - * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' - * It's ready to be inserted into an "echo" line in one of the templates. - * NOTE: expects a trailing "." on the namespace. - * @access private - */ - function generate_block_varref($namespace, $varname, $echo = true, $defop = false) - { - // Strip the trailing period. - $namespace = substr($namespace, 0, -1); - - // Get a reference to the data block for this namespace. - $varref = $this->generate_block_data_ref($namespace, true, $defop); - // Prepend the necessary code to stick this in an echo line. - - // Append the variable reference. - $varref .= "['$varname']"; - $varref = ($echo) ? "" : ((isset($varref)) ? $varref : ''); - - return $varref; - } - - /** - * Generates a reference to the array of data values for the given - * (possibly nested) block namespace. This is a string of the form: - * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] - * - * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. - * NOTE: does not expect a trailing "." on the blockname. - * @access private - */ - function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) - { - // Get an array of the blocks involved. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - // DEFINE is not an element of any referenced variable, we must use _tpldata to access it - if ($defop) - { - $varref = '$this->_tpldata[\'DEFINE\']'; - // Build up the string with everything but the last child. - for ($i = 0; $i < $blockcount; $i++) - { - $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]'; - } - // Add the block reference for the last child. - $varref .= "['" . $blocks[$blockcount] . "']"; - // Add the iterator for the last child if requried. - if ($include_last_iterator) - { - $varref .= '[$_' . $blocks[$blockcount] . '_i]'; - } - return $varref; - } - else if ($include_last_iterator) - { - return '$_'. $blocks[$blockcount] . '_val'; - } - else - { - return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']'; - } - } - - /** - * Write compiled file to cache directory - * @access private - */ - function compile_write($handle, $data) - { - global $phpEx; - - $filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . $phpEx; - - $data = "' . $data); - - if ($fp = @fopen($filename, 'wb')) - { - @flock($fp, LOCK_EX); - @fwrite ($fp, $data); - @flock($fp, LOCK_UN); - @fclose($fp); - - phpbb_chmod($filename, CHMOD_READ | CHMOD_WRITE); - } - - return; - } -} diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 643a86cde9..47262eaccf 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -16,40 +16,75 @@ if (!defined('IN_PHPBB')) exit; } +/** +* @todo +* IMG_ for image substitution? +* {IMG_[key]:[alt]:[type]} +* {IMG_ICON_CONTACT:CONTACT:full} -> $user->img('icon_contact', 'CONTACT', 'full'); +* +* More in-depth... +* yadayada +*/ + /** * Base Template class. * @package phpBB3 */ -class template +class phpbb_template { - /** variable that holds all the data we'll be substituting into + public $phpbb_required = array('user', 'config'); + public $phpbb_optional = array(); + + /** + * variable that holds all the data we'll be substituting into * the compiled templates. Takes form: * --> $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value * if it's a root-level variable, it'll be like this: * --> $this->_tpldata[.][0][varname] == value + * @var array + */ + private $_tpldata = array('.' => array(0 => array())); + + /** + * @var array Reference to template->_tpldata['.'][0] + */ + private $_rootref; + + /** + * @var string Root dir for template. */ - var $_tpldata = array('.' => array(0 => array())); - var $_rootref; - - // Root dir and hash of filenames for each template handle. - var $root = ''; - var $cachepath = ''; - var $files = array(); - var $filename = array(); - var $files_inherit = array(); - var $files_template = array(); - var $inherit_root = ''; - var $orig_tpl_storedb; - var $orig_tpl_inherits_id; + private $root = ''; + + /** + * @var string Path of the cache directory for the template + */ + public $cachepath = ''; + + /** + * @var array Hash of handle => file path pairs + */ + public $files = array(); + + /** + * @var array Hash of handle => filename pairs + */ + public $filename = array(); + + public $files_inherit = array(); + public $files_template = array(); + public $inherit_root = ''; + + public $orig_tpl_storedb; + public $orig_tpl_inherits_id; // this will hash handle names to the compiled/uncompiled code for that handle. - var $compiled_code = array(); + public $compiled_code = array(); /** * Set template location * @access public */ - function set_template() + public function set_template() { global $phpbb_root_path, $user; @@ -89,8 +124,11 @@ class template /** * Set custom template location (able to use directory outside of phpBB) * @access public + * @param string $template_path Path to template directory + * @param string $template_name Name of template + * @param string $fallback_template_path Path to fallback template */ - function set_custom_template($template_path, $template_name, $fallback_template_path = false) + public function set_custom_template($template_path, $template_name, $fallback_template_path = false) { global $phpbb_root_path, $user; @@ -131,13 +169,10 @@ class template * Sets the template filenames for handles. $filename_array * should be a hash of handle => filename pairs. * @access public + * @param array $filname_array Should be a hash of handle => filename pairs. */ - function set_filenames($filename_array) + public function set_filenames(array $filename_array) { - if (!is_array($filename_array)) - { - return false; - } foreach ($filename_array as $handle => $filename) { if (empty($filename)) @@ -161,17 +196,26 @@ class template * Destroy template data set * @access public */ - function destroy() + public function destroy() { $this->_tpldata = array('.' => array(0 => array())); $this->_rootref = &$this->_tpldata['.'][0]; } + /** + * destroy method kept for compatibility. + */ + public function __destruct() + { + $this->destroy(); + } + /** * Reset/empty complete block * @access public + * @param string $blockname Name of block to destroy */ - function destroy_block_vars($blockname) + public function destroy_block_vars($blockname) { if (strpos($blockname, '.') !== false) { @@ -200,12 +244,15 @@ class template /** * Display handle * @access public + * @param string $handle Handle to display + * @param bool $include_once Allow multiple inclusions + * @return bool True on success, false on failure */ - function display($handle, $include_once = true) + public function display($handle, $include_once = true) { global $user, $phpbb_hook; - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once, $this)) + if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once)) { if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__))) { @@ -221,13 +268,23 @@ class template } } - if ($filename = $this->_tpl_load($handle)) + $_tpldata = &$this->_tpldata; + $_rootref = &$this->_rootref; + $_lang = &$user->lang; + + if (($filename = $this->_tpl_load($handle)) !== false) { ($include_once) ? include_once($filename) : include($filename); } + else if (($code = $this->_tpl_eval($handle)) !== false) + { + $code = ' ?> ' . $code . ' ' . $this->compiled_code[$handle] . 'display($handle, $include_once); @@ -256,8 +318,11 @@ class template /** * Load a compiled template if possible, if not, recompile it * @access private + * @param string $handle Handle of the template to load + * @return string|bool Return filename on success otherwise false + * @uses template_compile is used to compile uncached templates */ - function _tpl_load(&$handle) + private function _tpl_load($handle) { global $user, $phpEx, $config; @@ -276,7 +341,9 @@ class template $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0; $recompile = false; - if (!file_exists($filename) || @filesize($filename) === 0) + $recompile = (!file_exists($filename) || @filesize($filename) === 0 || ($config['load_tplcompile'] && @filemtime($filename) < @filemtime($this->files[$handle]))) ? true : false; + + if (defined('DEBUG_EXTRA')) { $recompile = true; } @@ -288,7 +355,7 @@ class template $this->files[$handle] = $this->files_inherit[$handle]; $this->files_template[$handle] = $user->theme['template_inherits_id']; } - $recompile = (@filemtime($filename) < filemtime($this->files[$handle])) ? true : false; + $recompile = (@filemtime($filename) < @filemtime($this->files[$handle])) ? true : false; } // Recompile page if the original template is newer, otherwise load the compiled version @@ -296,33 +363,59 @@ class template { return $filename; } + + // Inheritance - we point to another template file for this one. Equality is also used for store_db + if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) + { + $this->files[$handle] = $this->files_inherit[$handle]; + $this->files_template[$handle] = $user->theme['template_inherits_id']; + } - global $db, $phpbb_root_path; + // If we don't have a file assigned to this handle, die. + if (!isset($this->files[$handle])) + { + trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR); + } - if (!class_exists('template_compile')) + if (!class_exists('phpbb_template_compile')) { - include($phpbb_root_path . 'includes/functions_template.' . $phpEx); + include 'template_compile.php'; } + + $compile = new phpbb_template_compile($this); - // Inheritance - we point to another template file for this one. Equality is also used for store_db - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) + if ($compile->_tpl_load_file($handle) === false) { - $this->files[$handle] = $this->files_inherit[$handle]; - $this->files_template[$handle] = $user->theme['template_inherits_id']; + return false; } + + return $filename; + } - $compile = new template_compile($this); + /** + * This code should only run when some high level error prevents us from writing to the cache. + * @access private + * @param string $handle Template handle to compile + * @return string|bool Return compiled code on success otherwise false + * @uses template_compile is used to compile template + */ + private function _tpl_eval($handle) + { + if (!class_exists('phpbb_template_compile')) + { + include 'template_compile.php'; + } + + $compile = new phpbb_template_compile($this); // If we don't have a file assigned to this handle, die. if (!isset($this->files[$handle])) { - trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR); + trigger_error("template->_tpl_eval(): No file specified for handle $handle", E_USER_ERROR); } - // Just compile if no user object is present (happens within the installer) - if (!$user) + if (($code = $compile->_tpl_gen_src($handle)) === false) { - $compile->_tpl_load_file($handle); return false; } @@ -337,6 +430,8 @@ class template } $ids[] = $user->theme['template_id']; + global $db; + foreach ($ids as $id) { $sql = 'SELECT * @@ -381,7 +476,7 @@ class template $this->files_template[$row['template_filename']] = $user->theme['template_id']; } - if ($force_reload || $row['template_mtime'] < filemtime($file)) + if ($force_reload || $row['template_mtime'] < @filemtime($file)) { if ($row['template_filename'] == $this->filename[$handle]) { @@ -441,8 +536,9 @@ class template /** * Assign key variable pairs from an array * @access public + * @param array $vararray A hash of variable name => value pairs */ - function assign_vars($vararray) + public function assign_vars(array $vararray) { foreach ($vararray as $key => $val) { @@ -455,8 +551,10 @@ class template /** * Assign a single variable to a single key * @access public + * @param string $varname Variable name + * @param string $varval Value to assign to variable */ - function assign_var($varname, $varval) + public function assign_var($varname, $varval) { $this->_rootref[$varname] = $varval; @@ -466,8 +564,10 @@ class template /** * Assign key variable pairs from an array to a specified block * @access public + * @param string $blockname Name of block to assign $vararray to + * @param array $vararray A hash of variable name => value pairs */ - function assign_block_vars($blockname, $vararray) + public function assign_block_vars($blockname, array $vararray) { if (strpos($blockname, '.') !== false) { @@ -558,18 +658,51 @@ class template * @return bool false on error, true on success * @access public */ - function alter_block_array($blockname, $vararray, $key = false, $mode = 'insert') + public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') { if (strpos($blockname, '.') !== false) { - // Nested blocks are not supported - return false; + // Nested block. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $block = &$this->_tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + if (($pos = strpos($blocks[$i], '[')) !== false) + { + $name = substr($blocks[$i], 0, $pos); + + if (strpos($blocks[$i], '[]') === $pos) + { + $index = sizeof($block[$name]) - 1; + } + else + { + $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1); + } + } + else + { + $name = $blocks[$i]; + $index = sizeof($block[$name]) - 1; + } + $block = &$block[$name]; + $block = &$block[$index]; + } + + $block = &$block[$blocks[$i]]; // Traverse the last block + } + else + { + // Top-level block. + $block = &$this->_tpldata[$blockname]; } // Change key to zero (change first position) if false and to last position if true if ($key === false || $key === true) { - $key = ($key === false) ? 0 : sizeof($this->_tpldata[$blockname]); + $key = ($key === false) ? 0 : sizeof($block); } // Get correct position if array given @@ -579,7 +712,7 @@ class template list($search_key, $search_value) = @each($key); $key = NULL; - foreach ($this->_tpldata[$blockname] as $i => $val_ary) + foreach ($block as $i => $val_ary) { if ($val_ary[$search_key] === $search_value) { @@ -612,15 +745,13 @@ class template } // Re-position template blocks - for ($i = sizeof($this->_tpldata[$blockname]); $i > $key; $i--) + for ($i = sizeof($block); $i > $key; $i--) { - $this->_tpldata[$blockname][$i] = $this->_tpldata[$blockname][$i-1]; - $this->_tpldata[$blockname][$i]['S_ROW_COUNT'] = $i; + $block[$i] = $block[$i-1]; } // Insert vararray at given position - $vararray['S_ROW_COUNT'] = $key; - $this->_tpldata[$blockname][$key] = $vararray; + $block[$key] = $vararray; return true; } @@ -628,12 +759,13 @@ class template // Which block to change? if ($mode == 'change') { - if ($key == sizeof($this->_tpldata[$blockname])) + if ($key == sizeof($block)) { $key--; } - $this->_tpldata[$blockname][$key] = array_merge($this->_tpldata[$blockname][$key], $vararray); + $block[$key] = array_merge($block[$key], $vararray); + return true; } @@ -643,8 +775,11 @@ class template /** * Include a separate template * @access private + * @param string $filename Template filename to include + * @param bool $include True to include the file, false to just load it + * @uses template_compile is used to compile uncached templates */ - function _tpl_include($filename, $include = true) + private function _tpl_include($filename, $include = true) { $handle = $filename; $this->filename[$handle] = $filename; @@ -654,18 +789,31 @@ class template $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename; } - $filename = $this->_tpl_load($handle); + $filename = $this->_tpl_load($handle); if ($include) { global $user; + $_tpldata = &$this->_tpldata; + $_rootref = &$this->_rootref; + $_lang = &$user->lang; + if ($filename) { include($filename); return; } - eval(' ?>' . $this->compiled_code[$handle] . '_tpl_gen_src($handle)) !== false) + { + $code = ' ?> ' . $code . ' '; + + const REGEX_TOKENS = '~|{((?:[a-z][a-z_0-9]+\.)*\\$?[A-Z][A-Z_0-9]+)}~'; + + /** + * @var array + */ + private $block_names = array(); + + /** + * @var array + */ + private $block_else_level = array(); + + /** + * @var string + */ + private $chunk; + + /** + * @var bool + */ + private $in_php; + + public function filter($in, $out, &$consumed, $closing) + { + $written = false; + + while ($bucket = stream_bucket_make_writeable($in)) + { + $consumed += $bucket->datalen; + + $data = $this->chunk . $bucket->data; + $last_nl = strrpos($data, "\n"); + $this->chunk = substr($data, $last_nl); + $data = substr($data, 0, $last_nl); + + if (!strlen($data)) + { + continue; + } + + $written = true; + + $bucket->data = $this->compile($data); + $bucket->datalen = strlen($bucket->data); + stream_bucket_append($out, $bucket); + } + + if ($closing && strlen($this->chunk)) + { + $written = true; + $bucket = stream_bucket_new($this->stream, $this->compile($this->chunk)); + stream_bucket_append($out, $bucket); + } + + return $written ? PSFS_PASS_ON : PSFS_FEED_ME; + } + + public function onCreate() + { + $this->chunk = ''; + $this->in_php = false; + return true; + } + + private function compile($data) + { + $block_start_in_php = $this->in_php; + + $data = preg_replace('#<(?:[\\?%]|script)#s', '', $data); + $data = preg_replace_callback(self::REGEX_TOKENS, array($this, 'replace'), $data); + + global $config; + + // Remove php + if (!$config['tpl_allow_php']) + { + if ($block_start_in_php + && $this->in_php + && strpos($data, '') === false + && strpos($data, '') === false) + { + // This is just php code + return ''; + } + $data = preg_replace('~^.*?~', '', $data); + $data = preg_replace('~.*?~', '', $data); + $data = preg_replace('~.*?$~', '', $data); + } + + "?>/**/"; + + /* + Preserve whitespace. + PHP removes a newline after the closing tag (if it's there). This is by design. + + + Consider the following template: + + + some content + + + If we were to simply preserve all whitespace, we could simply replace all "?>" tags + with "?>\n". + Doing that, would add additional newlines to the compiled tempalte in place of the + IF and ENDIF statements. These newlines are unwanted (and one is conditional). + The IF and ENDIF are usually on their own line for ease of reading. + + This replacement preserves newlines only for statements that aren't the only statement on a line. + It will NOT preserve newlines at the end of statements in the above examle. + It will preserve newlines in situations like: + + inline content + + + */ +//* + $data = preg_replace('~(?).)+(?)$~m', "$1\n", $data); + $data = str_replace('/**/?>', "?>\n", $data); + $data = str_replace('?>in_php && $matches[1] != 'ENDPHP') + { + return ''; + } + + if (isset($matches[3])) + { + return $this->compile_var_tags($matches[0]); + } + + global $config; + + switch ($matches[1]) + { + case 'BEGIN': + $this->block_else_level[] = false; + return 'compile_tag_block($matches[2]) . ' ?>'; + break; + + case 'BEGINELSE': + $this->block_else_level[sizeof($this->block_else_level) - 1] = true; + return ''; + break; + + case 'END': + array_pop($this->block_names); + return 'block_else_level)) ? '}' : '}}') . ' ?>'; + break; + + case 'IF': + return 'compile_tag_if($matches[2], false) . ' ?>'; + break; + + case 'ELSE': + return ''; + break; + + case 'ELSEIF': + return 'compile_tag_if($matches[2], true) . ' ?>'; + break; + + case 'ENDIF': + return ''; + break; + + case 'DEFINE': + return 'compile_tag_define($matches[2], true) . ' ?>'; + break; + + case 'UNDEFINE': + return 'compile_tag_define($matches[2], false) . ' ?>'; + break; + + case 'INCLUDE': + return 'compile_tag_include($matches[2]) . ' ?>'; + break; + + case 'INCLUDEPHP': + return ($config['tpl_allow_php']) ? 'compile_tag_include_php($matches[2]) . ' ?>' : ''; + break; + + case 'PHP': + if ($config['tpl_allow_php']) + { + $this->in_php = true; + return ''; + break; + + case 'ENDPHP': + if ($config['tpl_allow_php']) + { + $this->in_php = false; + return ' ?>'; + } + return ''; + break; + + default: + return $matches[0]; + break; + + } + return ''; + } + + /** + * Compile variables + * @access private + */ + private function compile_var_tags(&$text_blocks) + { + // change template varrefs into PHP varrefs + $varrefs = array(); + + // This one will handle varrefs WITH namespaces + preg_match_all('#\{((?:' . self::REGEX_NS . '\.)+)(\$)?(' . self::REGEX_VAR . ')\}#', $text_blocks, $varrefs, PREG_SET_ORDER); + + foreach ($varrefs as $var_val) + { + $namespace = $var_val[1]; + $varname = $var_val[3]; + $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]); + + $text_blocks = str_replace($var_val[0], $new, $text_blocks); + } + + // Handle special language tags L_ and LA_ + $this->compile_language_tags($text_blocks); + + // This will handle the remaining root-level varrefs + $text_blocks = preg_replace('#\{(' . self::REGEX_VAR . ')\}#', "", $text_blocks); + $text_blocks = preg_replace('#\{\$(' . self::REGEX_VAR . ')\}#', "", $text_blocks); + + return $text_blocks; + } + + /** + * Handles special language tags L_ and LA_ + */ + private function compile_language_tags(&$text_blocks) + { + // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array + if (strpos($text_blocks, '{L_') !== false) + { + $text_blocks = preg_replace('#\{L_(' . self::REGEX_VAR . ')\}#', "", $text_blocks); + } + + // Handle addslashed language variables prefixed with LA_ + // If a template variable already exist, it will be used in favor of it... + if (strpos($text_blocks, '{LA_') !== false) + { + $text_blocks = preg_replace('#\{LA_(' . self::REGEX_VAR . '+)\}#', "", $text_blocks); + } + } + + /** + * Compile blocks + * @access private + */ + private function compile_tag_block($tag_args) + { + $no_nesting = false; + + // Is the designer wanting to call another loop in a loop? + // + // + // + // + // 'loop2' is actually on the same nesting level as 'loop' you assign + // variables to it with template->assign_block_vars('loop2', array(...)) + if (strpos($tag_args, '!') === 0) + { + // Count the number if ! occurrences (not allowed in vars) + $no_nesting = substr_count($tag_args, '!'); + $tag_args = substr($tag_args, $no_nesting); + } + + // Allow for control of looping (indexes start from zero): + // foo(2) : Will start the loop on the 3rd entry + // foo(-2) : Will start the loop two entries from the end + // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth + // foo(3,-4) : Will start the loop on the fourth entry and end it four from last + $match = array(); + + if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match)) + { + $tag_args = $match[1]; + + if ($match[2] < 0) + { + $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')'; + } + else + { + $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')'; + } + + if (!isset($match[3]) || strlen($match[3]) < 1 || $match[3] == -1) + { + $loop_end = '$_' . $tag_args . '_count'; + } + else if ($match[3] >= 0) + { + $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')'; + } + else //if ($match[3] < -1) + { + $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1); + } + } + else + { + $loop_start = 0; + $loop_end = '$_' . $tag_args . '_count'; + } + + $tag_template_php = ''; + array_push($this->block_names, $tag_args); + + if ($no_nesting !== false) + { + // We need to implode $no_nesting times from the end... + $block = array_slice($this->block_names, -$no_nesting); + } + else + { + $block = $this->block_names; + } + + if (sizeof($block) < 2) + { + // Block is not nested. + $tag_template_php = '$_' . $tag_args . "_count = (isset(\$_tpldata['$tag_args'])) ? sizeof(\$_tpldata['$tag_args']) : 0;"; + $varref = "\$_tpldata['$tag_args']"; + } + else + { + // This block is nested. + // Generate a namespace string for this block. + $namespace = implode('.', $block); + + // Get a reference to the data array for this block that depends on the + // current indices of all parent blocks. + $varref = $this->generate_block_data_ref($namespace, false); + + // Create the for loop code to iterate over this block. + $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;'; + } + + $tag_template_php .= 'if ($_' . $tag_args . '_count) {'; + + /** + * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory + * + * if (!$offset) + * { + * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){'; + * } + * + */ + + $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){'; + $tag_template_php .= '$_' . $tag_args . '_val = &' . $varref . '[$_' . $tag_args . '_i];'; + + return $tag_template_php; + } + + /** + * Compile a general expression - much of this is from Smarty with + * some adaptions for our block level methods + * @access private + */ + private function compile_expression($tag_args, &$vars = array()) + { + $match = array(); + preg_match_all('/(?: + "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | + \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | + [(),] | + [^\s(),]+)/x', $tag_args, $match); + + $tokens = $match[0]; + $is_arg_stack = array(); + + for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) + { + $token = &$tokens[$i]; + + switch ($token) + { + case '!==': + case '===': + case '<<': + case '>>': + case '|': + case '^': + case '&': + case '~': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '@': + break; + + case '==': + case 'eq': + $token = '=='; + break; + + case '!=': + case '<>': + case 'ne': + case 'neq': + $token = '!='; + break; + + case '<': + case 'lt': + $token = '<'; + break; + + case '<=': + case 'le': + case 'lte': + $token = '<='; + break; + + case '>': + case 'gt': + $token = '>'; + break; + + case '>=': + case 'ge': + case 'gte': + $token = '>='; + break; + + case '&&': + case 'and': + $token = '&&'; + break; + + case '||': + case 'or': + $token = '||'; + break; + + case '!': + case 'not': + $token = '!'; + break; + + case '%': + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; + $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens); + + $i = $is_arg_start; + + // no break + + default: + $varrefs = array(); + if (preg_match('#^((?:' . self::REGEX_NS . '\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs)) + { + if (!empty($varrefs[1])) + { + $namespace = substr($varrefs[1], 0, -1); + $namespace = (strpos($namespace, '.') === false) ? $namespace : strrchr($namespace, '.'); + + // S_ROW_COUNT is deceptive, it returns the current row number not the number of rows + // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM + switch ($varrefs[3]) + { + case 'S_ROW_NUM': + case 'S_ROW_COUNT': + $token = "\$_${namespace}_i"; + break; + + case 'S_NUM_ROWS': + $token = "\$_${namespace}_count"; + break; + + case 'S_FIRST_ROW': + $token = "(\$_${namespace}_i == 0)"; + break; + + case 'S_LAST_ROW': + $token = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; + break; + + case 'S_BLOCK_NAME': + $token = "'$namespace'"; + break; + + default: + $token = $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']'; + $vars[$token] = true; + break; + } + } + else + { + $token = ($varrefs[2]) ? '$_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$_rootref[\'' . $varrefs[3] . '\']'; + $vars[$token] = true; + } + + } + else if (preg_match('#^\.((?:' . self::REGEX_NS . '\.?)+)$#s', $token, $varrefs)) + { + // Allow checking if loops are set with .loopname + // It is also possible to check the loop count by doing for example + $blocks = explode('.', $varrefs[1]); + + // If the block is nested, we have a reference that we can grab. + // If the block is not nested, we just go and grab the block from _tpldata + if (sizeof($blocks) > 1) + { + $block = array_pop($blocks); + $namespace = implode('.', $blocks); + $varref = $this->generate_block_data_ref($namespace, true); + + // Add the block reference for the last child. + $varref .= "['" . $block . "']"; + } + else + { + $varref = '$_tpldata'; + + // Add the block reference for the last child. + $varref .= "['" . $blocks[0] . "']"; + } + $token = "isset($varref) && sizeof($varref)"; + } + + break; + } + } + + return $tokens; + } + + + private function compile_tag_if($tag_args, $elseif) + { + $vars = array(); + + $tokens = $this->compile_expression($tag_args, $vars); + + $tpl = ($elseif) ? '} else if (' : 'if ('; + + if (!empty($vars)) + { + $tpl .= '(isset(' . implode(') && isset(', array_keys($vars)) . ')) && '; + } + + $tpl .= implode(' ', $tokens); + $tpl .= ') { '; + + return $tpl; + } + + /** + * Compile DEFINE tags + * @access private + */ + private function compile_tag_define($tag_args, $op) + { + $match = array(); + preg_match('#^((?:' . self::REGEX_NS . '\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (.*?))?$#', $tag_args, $match); + + if (empty($match[2]) || (!isset($match[3]) && $op)) + { + return ''; + } + + if (!$op) + { + return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');'; + } + + $parsed_statement = implode(' ', $this->compile_expression($match[3])); + + return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $parsed_statement . ';'; + } + + /** + * Compile INCLUDE tag + * @access private + */ + private function compile_tag_include($tag_args) + { + return "\$this->_tpl_include('$tag_args');"; + } + + /** + * Compile INCLUDE_PHP tag + * @access private + */ + private function compile_tag_include_php($tag_args) + { + return "include('$tag_args');"; + } + + /** + * parse expression + * This is from Smarty + * @access private + */ + private function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') + { + $negate_expr = true; + $expr_type = array_shift($tokens); + } + else + { + $expr_type = $first_token; + } + + switch ($expr_type) + { + case 'even': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(($is_arg / $expr_arg) & 1)"; + } + else + { + $expr = "!($is_arg & 1)"; + } + break; + + case 'odd': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(($is_arg / $expr_arg) & 1)"; + } + else + { + $expr = "($is_arg & 1)"; + } + break; + + case 'div': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % $expr_arg)"; + } + break; + } + + if ($negate_expr) + { + if ($expr[0] == '!') + { + // Negated expression, de-negate it. + $expr = substr($expr, 1); + } + else + { + $expr = "!($expr)"; + } + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + /** + * Generates a reference to the given variable inside the given (possibly nested) + * block namespace. This is a string of the form: + * ' . $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' + * It's ready to be inserted into an "echo" line in one of the templates. + * + * @access private + * @param string $namespace Namespace to access (expects a trailing "." on the namespace) + * @param string $varname Variable name to use + * @param bool $echo If true return an echo statement, otherwise a reference to the internal variable + * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable + * @return string Code to access variable or echo it if $echo is true + */ + private function generate_block_varref($namespace, $varname, $echo = true, $defop = false) + { + // Strip the trailing period. + $namespace = substr($namespace, 0, -1); + + $expr = true; + $isset = false; + + // S_ROW_COUNT is deceptive, it returns the current row number now the number of rows + // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM + switch ($varname) + { + case 'S_ROW_NUM': + case 'S_ROW_COUNT': + $varref = "\$_${namespace}_i"; + break; + + case 'S_NUM_ROWS': + $varref = "\$_${namespace}_count"; + break; + + case 'S_FIRST_ROW': + $varref = "(\$_${namespace}_i == 0)"; + break; + + case 'S_LAST_ROW': + $varref = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; + break; + + case 'S_BLOCK_NAME': + $varref = "'$namespace'"; + break; + + default: + // Get a reference to the data block for this namespace. + $varref = $this->generate_block_data_ref($namespace, true, $defop); + // Prepend the necessary code to stick this in an echo line. + + // Append the variable reference. + $varref .= "['$varname']"; + + $expr = false; + $isset = true; + break; + } + // @todo Test the !$expr more + $varref = ($echo) ? '' : (($expr || isset($varref)) ? $varref : ''); + + return $varref; + } + + /** + * Generates a reference to the array of data values for the given + * (possibly nested) block namespace. This is a string of the form: + * $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] + * + * @access private + * @param string $blockname Block to access (does not expect a trailing "." on the blockname) + * @param bool $include_last_iterator If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. + * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable + * @return string Code to access variable + */ + private function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) + { + // Get an array of the blocks involved. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + // DEFINE is not an element of any referenced variable, we must use _tpldata to access it + if ($defop) + { + $varref = '$_tpldata[\'DEFINE\']'; + // Build up the string with everything but the last child. + for ($i = 0; $i < $blockcount; $i++) + { + $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]'; + } + // Add the block reference for the last child. + $varref .= "['" . $blocks[$blockcount] . "']"; + // Add the iterator for the last child if requried. + if ($include_last_iterator) + { + $varref .= '[$_' . $blocks[$blockcount] . '_i]'; + } + return $varref; + } + else if ($include_last_iterator) + { + return '$_'. $blocks[$blockcount] . '_val'; + } + else + { + return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']'; + } + } +} + +stream_filter_register('phpbb_template', 'phpbb_template_filter'); + +/** +* Extension of template class - Functions needed for compiling templates only. +* +* psoTFX, phpBB Development Team - Completion of file caching, decompilation +* routines and implementation of conditionals/keywords and associated changes +* +* The interface was inspired by PHPLib templates, and the template file (formats are +* quite similar) +* +* The keyword/conditional implementation is currently based on sections of code from +* the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released +* (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code +* derived from an LGPL application may be relicenced under the GPL, this applies +* to this source +* +* DEFINE directive inspired by a request by Cyberalien +* +* @package phpBB3 +* @uses template_filter As a PHP stream filter to perform compilation of templates +*/ +class phpbb_template_compile +{ + /** + * @var phpbb_template Reference to the {@link phpbb_template template} object performing compilation + */ + private $template; + + /** + * Constructor + * @param phpbb_template $template {@link phpbb_template Template} object performing compilation + */ + public function __construct(phpbb_template $template) + { + $this->template = $template; + } + + /** + * Load template source from file + * @access public + * @param string $handle Template handle we wish to load + * @return bool Return true on success otherwise false + */ + public function _tpl_load_file($handle) + { + // Try and open template for read + if (!file_exists($this->template->files[$handle])) + { + trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR); + } + + // Actually compile the code now. + return $this->compile_write($handle, $this->template->files[$handle]); + } + + /** + * Load template source from file + * @access public + * @param string $handle Template handle we wish to compile + * @return string|bool Return compiled code on successful compilation otherwise false + */ + public function _tpl_gen_src($handle) + { + // Try and open template for read + if (!file_exists($this->template->files[$handle])) + { + trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR); + } + + // Actually compile the code now. + return $this->compile_gen($this->template->files[$handle]); + } + + /** + * Write compiled file to cache directory + * @access private + * @param string $handle Template handle to compile + * @param string $source_file Source template file + * @return bool Return true on success otherwise false + */ + private function compile_write($handle, $source_file) + { + global $system, $phpEx; + + $filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . $phpEx; + + $source_handle = @fopen($source_file, 'rb'); + $destination_handle = @fopen($filename, 'wb'); + + if (!$source_handle || !$destination_handle) + { + return false; + } + + @flock($destination_handle, LOCK_EX); + + stream_filter_append($source_handle, 'phpbb_template'); + stream_copy_to_stream($source_handle, $destination_handle); + + @fclose($source_handle); + @flock($destination_handle, LOCK_UN); + @fclose($destination_handle); + + phpbb_chmod($filename, CHMOD_READ | CHMOD_WRITE); + + clearstatcache(); + + return true; + } + + /** + * Generate source for eval() + * @access private + * @param string $source_file Source template file + * @return string|bool Return compiled code on successful compilation otherwise false + */ + private function compile_gen($source_file) + { + $source_handle = @fopen($source_file, 'rb'); + $destination_handle = @fopen('php://temp' ,'r+b'); + + if (!$source_handle || !$destination_handle) + { + return false; + } + + stream_filter_append($source_handle, 'phpbb_template'); + stream_copy_to_stream($source_handle, $destination_handle); + + @fclose($source_handle); + + rewind($destination_handle); + return stream_get_contents($destination_handle); + } +} + +?> \ No newline at end of file -- cgit v1.2.1 From 4f3e966fdc4bc241b8941ee9598d8c397f03f6a3 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 23 Apr 2011 22:47:22 -0400 Subject: [feature/template-engine] Delete ?>, add newline at EOF. PHPBB3-9726 --- phpBB/includes/template.php | 2 +- phpBB/includes/template_compile.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 47262eaccf..5eebeeae34 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -844,4 +844,4 @@ class phpbb_template class template extends phpbb_template { // dirty hack -} \ No newline at end of file +} diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php index 64dd8117a0..d9eda1d8c2 100644 --- a/phpBB/includes/template_compile.php +++ b/phpBB/includes/template_compile.php @@ -978,5 +978,3 @@ class phpbb_template_compile return stream_get_contents($destination_handle); } } - -?> \ No newline at end of file -- cgit v1.2.1 From 203187a8410c411b0bdd90729e19c257ec3a7820 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 24 Apr 2011 00:22:41 -0400 Subject: [feature/template-engine] Fix recompilation logic. Do not change $recompile from true to false - any recompilation condition alone is sufficient to force recompilation. Also uncomment the nonexistent file test which passes with this fix. PHPBB3-9726 --- phpBB/includes/template.php | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 5eebeeae34..5d0e8416a4 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -343,19 +343,22 @@ class phpbb_template $recompile = false; $recompile = (!file_exists($filename) || @filesize($filename) === 0 || ($config['load_tplcompile'] && @filemtime($filename) < @filemtime($this->files[$handle]))) ? true : false; - if (defined('DEBUG_EXTRA')) - { - $recompile = true; - } - else if ($config['load_tplcompile']) + if (!$recompile) { - // No way around it: we need to check inheritance here - if ($user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) + if (defined('DEBUG_EXTRA')) { - $this->files[$handle] = $this->files_inherit[$handle]; - $this->files_template[$handle] = $user->theme['template_inherits_id']; + $recompile = true; + } + else if ($config['load_tplcompile']) + { + // No way around it: we need to check inheritance here + if ($user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) + { + $this->files[$handle] = $this->files_inherit[$handle]; + $this->files_template[$handle] = $user->theme['template_inherits_id']; + } + $recompile = (@filemtime($filename) < @filemtime($this->files[$handle])) ? true : false; } - $recompile = (@filemtime($filename) < @filemtime($this->files[$handle])) ? true : false; } // Recompile page if the original template is newer, otherwise load the compiled version -- cgit v1.2.1 From f29f32e0d67e88a271702264c37852406f4013d8 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 24 Apr 2011 00:44:19 -0400 Subject: [feature/template-engine] Allow leading underscores in variable names. Subsilver uses ._file in overall_header. PHPBB3-9726 --- phpBB/includes/template_compile.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php index d9eda1d8c2..92695a54fa 100644 --- a/phpBB/includes/template_compile.php +++ b/phpBB/includes/template_compile.php @@ -23,13 +23,13 @@ if (!defined('IN_PHPBB')) */ class phpbb_template_filter extends php_user_filter { - const REGEX_NS = '[a-z][a-z_0-9]+'; + const REGEX_NS = '[a-z_][a-z_0-9]+'; - const REGEX_VAR = '[A-Z][A-Z_0-9]+'; + const REGEX_VAR = '[A-Z_][A-Z_0-9]+'; const REGEX_TAG = ''; - const REGEX_TOKENS = '~|{((?:[a-z][a-z_0-9]+\.)*\\$?[A-Z][A-Z_0-9]+)}~'; + const REGEX_TOKENS = '~|{((?:[a-z_][a-z_0-9]+\.)*\\$?[A-Z][A-Z_0-9]+)}~'; /** * @var array -- cgit v1.2.1 From 321ecf427356f2d503818089c7b0e008e5a73c2c Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 24 Apr 2011 01:18:09 -0400 Subject: [feature/template-engine] Delete class_exists checks, rely on autoloading. PHPBB3-9726 --- phpBB/includes/template.php | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 5d0e8416a4..30ede2f242 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -380,11 +380,6 @@ class phpbb_template trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR); } - if (!class_exists('phpbb_template_compile')) - { - include 'template_compile.php'; - } - $compile = new phpbb_template_compile($this); if ($compile->_tpl_load_file($handle) === false) @@ -404,11 +399,6 @@ class phpbb_template */ private function _tpl_eval($handle) { - if (!class_exists('phpbb_template_compile')) - { - include 'template_compile.php'; - } - $compile = new phpbb_template_compile($this); // If we don't have a file assigned to this handle, die. -- cgit v1.2.1 From c8db531fcb11cdeeefcae88b05c2674b74e2d824 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 24 Apr 2011 01:59:40 -0400 Subject: [feature/template-engine] Removed a useless space. PHPBB3-9726 --- phpBB/includes/template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 30ede2f242..24d7aeadd0 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -782,7 +782,7 @@ class phpbb_template $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename; } - $filename = $this->_tpl_load($handle); + $filename = $this->_tpl_load($handle); if ($include) { -- cgit v1.2.1 From 81962d1d8ff083dd366c77e7d3858fd2c9ed7d43 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Tue, 23 Nov 2010 16:09:09 +0100 Subject: [ticket/9924] Pass template instance into $template->display hook This is a cherry-pick of 053cf790a93e9cfb521f484901d79c72783f868f which appears to have been partially reverted here. PHPBB3-9924 --- phpBB/includes/template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 24d7aeadd0..2b4c7a09f7 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -252,7 +252,7 @@ class phpbb_template { global $user, $phpbb_hook; - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once)) + if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once, $this)) { if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__))) { -- cgit v1.2.1 From a2c75f60537ccf6a424c7f066eafbffc13c0c38d Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 24 Apr 2011 21:18:18 -0400 Subject: [feature/template-engine] Deleted $template from phpbb_template_compile class. phpbb_template_compile is now much simpler. It takes complete file paths as inputs, either source template path or source template path and output compiled template path. The number of methods also went down to two - compile template and returned compiled text or compile and write to file. phpbb_compile class is responsible for determining source and compiled paths. It already had all the data necessary for this, now the code is in the same place as the data it uses. PHPBB3-9726 --- phpBB/includes/template.php | 67 +++++++++++++++++------- phpBB/includes/template_compile.php | 100 +++++++++--------------------------- 2 files changed, 73 insertions(+), 94 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 2b4c7a09f7..e1e96791c9 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -366,7 +366,7 @@ class phpbb_template { return $filename; } - + // Inheritance - we point to another template file for this one. Equality is also used for store_db if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) { @@ -374,20 +374,54 @@ class phpbb_template $this->files_template[$handle] = $user->theme['template_inherits_id']; } + $source_file = $this->_source_file_for_handle($handle); + + $compile = new phpbb_template_compile($this); + + if ($compile->compile_write($source_file, $this->_compiled_file_for_handle($handle)) === false) + { + return false; + } + + return $filename; + } + + /** + * Resolves template handle $handle to source file path. + * @access private + * @param string $handle Template handle (i.e. "friendly" template name) + * @return string Source file path + */ + private function _source_file_for_handle($handle) + { // If we don't have a file assigned to this handle, die. if (!isset($this->files[$handle])) { - trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR); + trigger_error("_source_file_for_handle(): No file specified for handle $handle", E_USER_ERROR); } - $compile = new phpbb_template_compile($this); + $source_file = $this->files[$handle]; - if ($compile->_tpl_load_file($handle) === false) + // Try and open template for reading + if (!file_exists($source_file)) { - return false; + trigger_error("_source_file_for_handle(): File $source_file does not exist", E_USER_ERROR); } - - return $filename; + return $source_file; + } + + /** + * Determines compiled file path for handle $handle. + * @access private + * @param string $handle Template handle (i.e. "friendly" template name) + * @return string Compiled file path + */ + private function _compiled_file_for_handle($handle) + { + global $phpEx; + + $compiled_file = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; + return $compiled_file; } /** @@ -401,13 +435,9 @@ class phpbb_template { $compile = new phpbb_template_compile($this); - // If we don't have a file assigned to this handle, die. - if (!isset($this->files[$handle])) - { - trigger_error("template->_tpl_eval(): No file specified for handle $handle", E_USER_ERROR); - } + $source_file = $this->_source_file_for_handle($handle); - if (($code = $compile->_tpl_gen_src($handle)) === false) + if (($code = $compile->compile_gen($source_file)) === false) { return false; } @@ -473,13 +503,13 @@ class phpbb_template { if ($row['template_filename'] == $this->filename[$handle]) { - $compile->_tpl_load_file($handle, true); + $compile->compile_write($source_file, $this->_compiled_file_for_handle($handle)); } else { $this->files[$row['template_filename']] = $file; $this->filename[$row['template_filename']] = $row['template_filename']; - $compile->_tpl_load_file($row['template_filename'], true); + $compile->compile_write($this->_source_file_for_handle($row['template_filename']), $this->_compiled_file_for_handle($row['template_filename'])); unset($this->compiled_code[$row['template_filename']]); unset($this->files[$row['template_filename']]); unset($this->filename[$row['template_filename']]); @@ -515,14 +545,14 @@ class phpbb_template $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id']; } // Try to load from filesystem and instruct to insert into the styles table... - $compile->_tpl_load_file($handle, true); + $compile->compile_write($source_file, $this->_compiled_file_for_handle($handle)); return false; } return false; } - $compile->_tpl_load_file($handle); + $compile->compile_write($source_file, $this->_compiled_file_for_handle($handle)); return false; } @@ -801,7 +831,8 @@ class phpbb_template { $compile = new phpbb_template_compile($this); - if (($code = $compile->_tpl_gen_src($handle)) !== false) + $source_file = $this->_source_file_for_handle($handle); + if (($code = $compile->compile_gen($source_file)) !== false) { $code = ' ?> ' . $code . ' in_php; - + $data = preg_replace('#<(?:[\\?%]|script)#s', '', $data); $data = preg_replace_callback(self::REGEX_TOKENS, array($this, 'replace'), $data); global $config; - + // Remove php if (!$config['tpl_allow_php']) { @@ -117,33 +117,33 @@ class phpbb_template_filter extends php_user_filter $data = preg_replace('~.*?~', '', $data); $data = preg_replace('~.*?$~', '', $data); } - + "?>/**/"; - + /* Preserve whitespace. PHP removes a newline after the closing tag (if it's there). This is by design. - - + + Consider the following template: - + some content - + If we were to simply preserve all whitespace, we could simply replace all "?>" tags with "?>\n". Doing that, would add additional newlines to the compiled tempalte in place of the IF and ENDIF statements. These newlines are unwanted (and one is conditional). The IF and ENDIF are usually on their own line for ease of reading. - + This replacement preserves newlines only for statements that aren't the only statement on a line. It will NOT preserve newlines at the end of statements in the above examle. It will preserve newlines in situations like: - + inline content - - + + */ //* $data = preg_replace('~(?).)+(?)$~m', "$1\n", $data); @@ -158,7 +158,7 @@ class phpbb_template_filter extends php_user_filter { return ''; } - + if (isset($matches[3])) { return $this->compile_var_tags($matches[0]); @@ -558,7 +558,7 @@ class phpbb_template_filter extends php_user_filter $token = ($varrefs[2]) ? '$_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$_rootref[\'' . $varrefs[3] . '\']'; $vars[$token] = true; } - + } else if (preg_match('#^\.((?:' . self::REGEX_NS . '\.?)+)$#s', $token, $varrefs)) { @@ -867,70 +867,17 @@ stream_filter_register('phpbb_template', 'phpbb_template_filter'); class phpbb_template_compile { /** - * @var phpbb_template Reference to the {@link phpbb_template template} object performing compilation - */ - private $template; - - /** - * Constructor - * @param phpbb_template $template {@link phpbb_template Template} object performing compilation - */ - public function __construct(phpbb_template $template) - { - $this->template = $template; - } - - /** - * Load template source from file + * Compiles template in $source_file and writes compiled template to + * cache directory * @access public - * @param string $handle Template handle we wish to load - * @return bool Return true on success otherwise false - */ - public function _tpl_load_file($handle) - { - // Try and open template for read - if (!file_exists($this->template->files[$handle])) - { - trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR); - } - - // Actually compile the code now. - return $this->compile_write($handle, $this->template->files[$handle]); - } - - /** - * Load template source from file - * @access public - * @param string $handle Template handle we wish to compile - * @return string|bool Return compiled code on successful compilation otherwise false - */ - public function _tpl_gen_src($handle) - { - // Try and open template for read - if (!file_exists($this->template->files[$handle])) - { - trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR); - } - - // Actually compile the code now. - return $this->compile_gen($this->template->files[$handle]); - } - - /** - * Write compiled file to cache directory - * @access private * @param string $handle Template handle to compile * @param string $source_file Source template file * @return bool Return true on success otherwise false */ - private function compile_write($handle, $source_file) + public function compile_write($source_file, $compiled_file) { - global $system, $phpEx; - - $filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . $phpEx; - $source_handle = @fopen($source_file, 'rb'); - $destination_handle = @fopen($filename, 'wb'); + $destination_handle = @fopen($compiled_file, 'wb'); if (!$source_handle || !$destination_handle) { @@ -946,7 +893,7 @@ class phpbb_template_compile @flock($destination_handle, LOCK_UN); @fclose($destination_handle); - phpbb_chmod($filename, CHMOD_READ | CHMOD_WRITE); + phpbb_chmod($compiled_file, CHMOD_READ | CHMOD_WRITE); clearstatcache(); @@ -954,12 +901,13 @@ class phpbb_template_compile } /** - * Generate source for eval() - * @access private + * Compiles a template located at $source_file. + * Returns PHP source suitable for eval(). + * @access public * @param string $source_file Source template file * @return string|bool Return compiled code on successful compilation otherwise false */ - private function compile_gen($source_file) + public function compile_gen($source_file) { $source_handle = @fopen($source_file, 'rb'); $destination_handle = @fopen('php://temp' ,'r+b'); -- cgit v1.2.1 From 5c3ebb3465eee36f9147a517d4f50f4032cd04d5 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 24 Apr 2011 21:22:43 -0400 Subject: [feature/template-engine] Deleted silencing of notices. The code is now supposed to be notice-free, therefore there is no need to have the notices silenced. PHPBB3-9726 --- phpBB/includes/template.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index e1e96791c9..109f7a29ee 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -260,6 +260,7 @@ class phpbb_template } } + /* if (defined('IN_ERROR_HANDLER')) { if ((E_NOTICE & error_reporting()) == E_NOTICE) @@ -267,6 +268,7 @@ class phpbb_template error_reporting(error_reporting() ^ E_NOTICE); } } + */ $_tpldata = &$this->_tpldata; $_rootref = &$this->_rootref; -- cgit v1.2.1 From 5afc0b9b905814718ed0292fa5cc7342786c1fca Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 24 Apr 2011 22:46:34 -0400 Subject: [feature/template-engine] Corrected an off-by-one error in nested namespaces. This error resulted in a dot from the namespace being placed into variable reference in compiled template code, thus creating bogus compiled template code. PHPBB3-9726 --- phpBB/includes/template_compile.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php index 07e497eca4..cba402f83b 100644 --- a/phpBB/includes/template_compile.php +++ b/phpBB/includes/template_compile.php @@ -520,7 +520,11 @@ class phpbb_template_filter extends php_user_filter if (!empty($varrefs[1])) { $namespace = substr($varrefs[1], 0, -1); - $namespace = (strpos($namespace, '.') === false) ? $namespace : strrchr($namespace, '.'); + $dot_pos = strrchr($namespace, '.'); + if ($dot_pos !== false) + { + $namespace = substr($dot_pos, 1); + } // S_ROW_COUNT is deceptive, it returns the current row number not the number of rows // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM -- cgit v1.2.1 From f97411b91143a0c75ef0ecec3ff03fc36a879728 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 25 Apr 2011 13:03:55 -0400 Subject: [feature/template-engine] Corrected miscompilation of loop size constructs. PHPBB3-9726 --- phpBB/includes/template_compile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php index cba402f83b..9a8bc05343 100644 --- a/phpBB/includes/template_compile.php +++ b/phpBB/includes/template_compile.php @@ -588,7 +588,7 @@ class phpbb_template_filter extends php_user_filter // Add the block reference for the last child. $varref .= "['" . $blocks[0] . "']"; } - $token = "isset($varref) && sizeof($varref)"; + $token = "(isset($varref) ? sizeof($varref) : 0)"; } break; -- cgit v1.2.1 From 427a5122d55f06c861277297411f7e39a03a703c Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Tue, 26 Apr 2011 02:09:51 +0200 Subject: [feature/template-engine] Fix negative variable expressions compile_tag_if had the flawed approach of adding an isset statement for all variables to the beginning of the if. This fails for negative expressions, and checking those takes a considerable effort. The easier solution is to make the variable expression itself conditional, defaulting to null if it is not set. Thanks to naderman for the solution. PHPBB3-9726 --- phpBB/includes/template_compile.php | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php index 9a8bc05343..3f8a028e25 100644 --- a/phpBB/includes/template_compile.php +++ b/phpBB/includes/template_compile.php @@ -408,7 +408,7 @@ class phpbb_template_filter extends php_user_filter * some adaptions for our block level methods * @access private */ - private function compile_expression($tag_args, &$vars = array()) + private function compile_expression($tag_args) { $match = array(); preg_match_all('/(?: @@ -553,14 +553,14 @@ class phpbb_template_filter extends php_user_filter default: $token = $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']'; - $vars[$token] = true; + $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; break; } } else { $token = ($varrefs[2]) ? '$_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$_rootref[\'' . $varrefs[3] . '\']'; - $vars[$token] = true; + $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; } } @@ -601,17 +601,10 @@ class phpbb_template_filter extends php_user_filter private function compile_tag_if($tag_args, $elseif) { - $vars = array(); - - $tokens = $this->compile_expression($tag_args, $vars); + $tokens = $this->compile_expression($tag_args); $tpl = ($elseif) ? '} else if (' : 'if ('; - if (!empty($vars)) - { - $tpl .= '(isset(' . implode(') && isset(', array_keys($vars)) . ')) && '; - } - $tpl .= implode(' ', $tokens); $tpl .= ') { '; -- cgit v1.2.1 From 909ee59871402aa8dc7fa4e540d2f7e5da1628fc Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 26 Apr 2011 12:10:52 -0400 Subject: [feature/template-engine] Removed $this from new phpbb_template_compile calls. The compile class no longer takes template as a parameter. PHPBB3-9726 --- phpBB/includes/template.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 109f7a29ee..ae68f5fad3 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -378,7 +378,7 @@ class phpbb_template $source_file = $this->_source_file_for_handle($handle); - $compile = new phpbb_template_compile($this); + $compile = new phpbb_template_compile(); if ($compile->compile_write($source_file, $this->_compiled_file_for_handle($handle)) === false) { @@ -435,7 +435,7 @@ class phpbb_template */ private function _tpl_eval($handle) { - $compile = new phpbb_template_compile($this); + $compile = new phpbb_template_compile(); $source_file = $this->_source_file_for_handle($handle); @@ -831,7 +831,7 @@ class phpbb_template } else { - $compile = new phpbb_template_compile($this); + $compile = new phpbb_template_compile(); $source_file = $this->_source_file_for_handle($handle); if (($code = $compile->compile_gen($source_file)) !== false) -- cgit v1.2.1 From e6eb11bb1168236cbaba0263d322170dc2c7bdcd Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 00:03:49 -0400 Subject: [ticket/10003] Ported d7d96223e7bae7cd60b13c6e7896d95838c3633c to db_tools. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index f4b181c6ad..f22ddc2ee8 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -1371,24 +1371,29 @@ class phpbb_db_tools switch ($this->sql_layer) { case 'firebird': + // Does not support AFTER statement, only POSITION (and there you need the column position) $statements[] = 'ALTER TABLE ' . $table_name . ' ADD "' . strtoupper($column_name) . '" ' . $column_data['column_type_sql']; break; case 'mssql': case 'mssqlnative': + // Does not support AFTER, only through temporary table $statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default']; break; case 'mysql_40': case 'mysql_41': - $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql']; + $after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : ''; + $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after; break; case 'oracle': + // Does not support AFTER, only through temporary table $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql']; break; case 'postgres': + // Does not support AFTER, only through temporary table if (version_compare($this->db->sql_server_info(true), '8.0', '>=')) { $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; @@ -2120,4 +2125,4 @@ class phpbb_db_tools } } -?> \ No newline at end of file +?> -- cgit v1.2.1 From 3cb1b90ca6afcf0533f8f398f2a3f4066b697ed3 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 00:34:24 -0400 Subject: [ticket/10003] Ported 96a30afcca3ebd832c9b3083bb5c9a9f2a2dc54b to db_tools. This change is somewhat questionable, maybe it should be reviewed. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index f22ddc2ee8..d9ff811e34 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -681,10 +681,12 @@ class phpbb_db_tools { foreach ($columns as $column_name => $column_data) { - // Only add the column if it does not exist yet, else change it (to be consistent) + // Only add the column if it does not exist yet if ($column_exists = $this->sql_column_exists($table, $column_name)) { - $result = $this->sql_column_change($table, $column_name, $column_data, true); + continue; + // This is commented out here because it can take tremendous time on updates +// $result = $this->sql_column_change($table, $column_name, $column_data, true); } else { -- cgit v1.2.1 From 9f34aa0b79456f5d2d60f62361f483c76a3f89dd Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 00:39:36 -0400 Subject: [ticket/10003] Ported 54c22ae52a0e18232cac8fed342ea52f2e2a793d to db_tools. This diff applied cleanly. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 110 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index d9ff811e34..a793a2f313 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -697,7 +697,8 @@ class phpbb_db_tools { if ($column_exists) { - $sqlite_data[$table]['change_columns'][] = $result; + continue; +// $sqlite_data[$table]['change_columns'][] = $result; } else { @@ -719,6 +720,11 @@ class phpbb_db_tools { foreach ($indexes as $index_name) { + if (!$this->sql_index_exists($table, $index_name)) + { + continue; + } + $result = $this->sql_index_drop($table, $index_name); if ($this->return_statements) @@ -779,6 +785,11 @@ class phpbb_db_tools { foreach ($index_array as $index_name => $column) { + if ($this->sql_index_exists($table, $index_name)) + { + continue; + } + $result = $this->sql_create_unique_index($table, $index_name, $column); if ($this->return_statements) @@ -796,6 +807,11 @@ class phpbb_db_tools { foreach ($index_array as $index_name => $column) { + if ($this->sql_index_exists($table, $index_name)) + { + continue; + } + $result = $this->sql_create_index($table, $index_name, $column); if ($this->return_statements) @@ -1104,6 +1120,98 @@ class phpbb_db_tools } } + /** + * Check if a specified index exists in table + * + * @param string $table_name Table to check the index at + * @param string $index_name The index name to check + * + * @return bool True if index exists, else false + */ + function sql_index_exists($table_name, $index_name) + { + if ($this->sql_layer == 'mssql') + { + $sql = "EXEC sp_statistics '$table_name'"; + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + if ($row['TYPE'] == 3) + { + if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) + { + $this->db->sql_freeresult($result); + return true; + } + } + } + $this->db->sql_freeresult($result); + + return false; + } + + switch ($this->sql_layer) + { + case 'firebird': + $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name + FROM RDB\$INDICES + WHERE RDB\$RELATION_NAME = " . strtoupper($table_name) . " + AND RDB\$UNIQUE_FLAG IS NULL + AND RDB\$FOREIGN_KEY IS NULL"; + $col = 'index_name'; + break; + + case 'postgres': + $sql = "SELECT ic.relname as index_name + FROM pg_class bc, pg_class ic, pg_index i + WHERE (bc.oid = i.indrelid) + AND (ic.oid = i.indexrelid) + AND (bc.relname = '" . $table_name . "') + AND (i.indisunique != 't') + AND (i.indisprimary != 't')"; + $col = 'index_name'; + break; + + case 'mysql_40': + case 'mysql_41': + $sql = 'SHOW KEYS + FROM ' . $table_name; + $col = 'Key_name'; + break; + + case 'oracle': + $sql = "SELECT index_name + FROM user_indexes + WHERE table_name = '" . $table_name . "' + AND generated = 'N'"; + break; + + case 'sqlite': + $sql = "PRAGMA index_info('" . $table_name . "');"; + $col = 'name'; + break; + } + + $result = $this->db->sql_query($sql); + while ($row = $this->db->sql_fetchrow($result)) + { + if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) + { + continue; + } + + if (strtolower($row[$col]) == strtolower($index_name)) + { + $this->db->sql_freeresult($result); + return true; + } + } + $this->db->sql_freeresult($result); + + return false; + } + /** * Private method for performing sql statements (either execute them or return them) * @access private -- cgit v1.2.1 From 761e3dd36f3b42fdaac99ba76f8d214b47983c05 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 01:07:46 -0400 Subject: [ticket/10003] Ported 023760c8b2402418310a3717db8349cac0342e42 to db_tools. This was painful. Git wanted to patch hunks in wrong places. Hopefully I got it right. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 143 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 6 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index a793a2f313..f72498af9b 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -785,7 +785,7 @@ class phpbb_db_tools { foreach ($index_array as $index_name => $column) { - if ($this->sql_index_exists($table, $index_name)) + if ($this->sql_unique_index_exists($table, $index_name)) { continue; } @@ -1121,7 +1121,7 @@ class phpbb_db_tools } /** - * Check if a specified index exists in table + * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. * * @param string $table_name Table to check the index at * @param string $index_name The index name to check @@ -1156,7 +1156,7 @@ class phpbb_db_tools case 'firebird': $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name FROM RDB\$INDICES - WHERE RDB\$RELATION_NAME = " . strtoupper($table_name) . " + WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "' AND RDB\$UNIQUE_FLAG IS NULL AND RDB\$FOREIGN_KEY IS NULL"; $col = 'index_name'; @@ -1183,12 +1183,14 @@ class phpbb_db_tools case 'oracle': $sql = "SELECT index_name FROM user_indexes - WHERE table_name = '" . $table_name . "' - AND generated = 'N'"; + WHERE table_name = '" . strtoupper($table_name) . "' + AND generated = 'N' + AND uniqueness = 'NONUNIQUE'"; + $col = 'index_name'; break; case 'sqlite': - $sql = "PRAGMA index_info('" . $table_name . "');"; + $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; } @@ -1201,6 +1203,135 @@ class phpbb_db_tools continue; } + // These DBMS prefix index name with the table name + switch ($this->sql_layer) + { + case 'firebird': + case 'oracle': + case 'postgres': + case 'sqlite': + $row[$col] = substr($row[$col], strlen($table_name) + 1); + break; + } + + if (strtolower($row[$col]) == strtolower($index_name)) + { + $this->db->sql_freeresult($result); + return true; + } + } + $this->db->sql_freeresult($result); + + return false; + } + + /** + * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. + * + * @param string $table_name Table to check the index at + * @param string $index_name The index name to check + * + * @return bool True if index exists, else false + */ + function sql_unique_index_exists($table_name, $index_name) + { + if ($this->sql_layer == 'mssql') + { + $sql = "EXEC sp_statistics '$table_name'"; + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + // Usually NON_UNIQUE is the column we want to check, but we allow for both + if ($row['TYPE'] == 3) + { + if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) + { + $this->db->sql_freeresult($result); + return true; + } + } + } + $this->db->sql_freeresult($result); + return false; + } + + switch ($this->sql_layer) + { + case 'firebird': + $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name + FROM RDB\$INDICES + WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "' + AND RDB\$UNIQUE_FLAG IS NOT NULL + AND RDB\$FOREIGN_KEY IS NULL"; + $col = 'index_name'; + break; + + case 'postgres': + $sql = "SELECT ic.relname as index_name, i.indisunique + FROM pg_class bc, pg_class ic, pg_index i + WHERE (bc.oid = i.indrelid) + AND (ic.oid = i.indexrelid) + AND (bc.relname = '" . $table_name . "') + AND (i.indisprimary != 't')"; + $col = 'index_name'; + break; + + case 'mysql_40': + case 'mysql_41': + $sql = 'SHOW KEYS + FROM ' . $table_name; + $col = 'Key_name'; + break; + + case 'oracle': + $sql = "SELECT index_name, table_owner + FROM user_indexes + WHERE table_name = '" . strtoupper($table_name) . "' + AND generated = 'N' + AND uniqueness = 'UNIQUE' + AND index_name LIKE 'U_%'"; + $col = 'index_name'; + break; + + case 'sqlite': + $sql = "PRAGMA index_list('" . $table_name . "') WHERE unique = 1;"; + $col = 'name'; + break; + } + + $result = $this->db->sql_query($sql); + while ($row = $this->db->sql_fetchrow($result)) + { + if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY')) + { + continue; + } + + if ($this->sql_layer == 'sqlite' && !$row['unique']) + { + continue; + } + + if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't') + { + continue; + } + + // These DBMS prefix index name with the table name + switch ($this->sql_layer) + { + case 'oracle': + $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1); + break; + + case 'firebird': + case 'postgres': + case 'sqlite': + $row[$col] = substr($row[$col], strlen($table_name) + 1); + break; + } + if (strtolower($row[$col]) == strtolower($index_name)) { $this->db->sql_freeresult($result); -- cgit v1.2.1 From 55ff5da70b6598218b032725f73de7c4f94a7c89 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 01:25:46 -0400 Subject: [ticket/10003] Ported 5553cfc2ed81ba9eb571804c431def962720b39e to db_tools. The diff in database_update was only partially relevant. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index f72498af9b..01061c77b1 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -1289,13 +1289,12 @@ class phpbb_db_tools FROM user_indexes WHERE table_name = '" . strtoupper($table_name) . "' AND generated = 'N' - AND uniqueness = 'UNIQUE' - AND index_name LIKE 'U_%'"; + AND uniqueness = 'UNIQUE'"; $col = 'index_name'; break; case 'sqlite': - $sql = "PRAGMA index_list('" . $table_name . "') WHERE unique = 1;"; + $sql = "PRAGMA index_list('" . $table_name . "');"; $col = 'name'; break; } @@ -1322,7 +1321,15 @@ class phpbb_db_tools switch ($this->sql_layer) { case 'oracle': - $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1); + // Two cases here... prefixed with U_[table_owner] and not prefixed with table_name + if (strpos($row[$col], 'U_') === 0) + { + $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1); + } + else if (strpos($row[$col], strtoupper($table_name)) === 0) + { + $row[$col] = substr($row[$col], strlen($table_name) + 1); + } break; case 'firebird': @@ -2203,6 +2210,7 @@ class phpbb_db_tools } else { + // TODO: try to change pkey without removing trigger, generator or constraints. ATM this query may fail. $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type']; } break; -- cgit v1.2.1 From 85549fad8324afc6e9358e98d75b8fdcc5faa416 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 01:46:01 -0400 Subject: [ticket/10003] Ported 1802b9ff9286a7fc24493e71b3432816cbdbfcd8 to db_tools. Most of it was already in db_tools, these changes could have applied to code that did not exist in db_tools at the time of the commit. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index 01061c77b1..fd09ccde3f 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -1130,7 +1130,7 @@ class phpbb_db_tools */ function sql_index_exists($table_name, $index_name) { - if ($this->sql_layer == 'mssql') + if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') { $sql = "EXEC sp_statistics '$table_name'"; $result = $this->db->sql_query($sql); @@ -1235,7 +1235,7 @@ class phpbb_db_tools */ function sql_unique_index_exists($table_name, $index_name) { - if ($this->sql_layer == 'mssql') + if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') { $sql = "EXEC sp_statistics '$table_name'"; $result = $this->db->sql_query($sql); -- cgit v1.2.1 From 1e2c19f4b443692b18a3a167dc464f63b19da47f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 29 Apr 2011 02:16:02 -0400 Subject: [ticket/10003] Delete EOL at EOF for the benefit of 3.0 modifications. PHPBB3-10003 --- phpBB/includes/db/db_tools.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index fd09ccde3f..483ceee043 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -2374,4 +2374,4 @@ class phpbb_db_tools } } -?> +?> \ No newline at end of file -- cgit v1.2.1 From 820f22f784d55edf22db5f065cba739308b37ed2 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 30 Apr 2011 13:20:27 -0400 Subject: [ticket/9693] Removed useless $auth globalizations. PHPBB3-9693 --- phpBB/includes/functions_posting.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 0bb0ef8722..7630e05695 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -21,7 +21,7 @@ if (!defined('IN_PHPBB')) */ function generate_smilies($mode, $forum_id) { - global $auth, $db, $user, $config, $template; + global $db, $user, $config, $template; global $phpEx, $phpbb_root_path; $start = request_var('start', 0); @@ -803,7 +803,7 @@ function posting_gen_inline_attachments(&$attachment_data) */ function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true) { - global $template, $config, $phpbb_root_path, $phpEx, $user, $auth; + global $template, $config, $phpbb_root_path, $phpEx, $user; // Some default template variables $template->assign_vars(array( -- cgit v1.2.1 From 8155bc5a9dbbe5ad6a9ceb722baf4587db8f3689 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 30 Apr 2011 15:39:19 -0400 Subject: [ticket/10067] Clarify language for user activation options in ACP. PHPBB3-10067 --- phpBB/includes/acp/acp_board.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index a5e80e1f6d..8f7d08cc8f 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -770,12 +770,18 @@ class acp_board global $user, $config; $radio_ary = array(USER_ACTIVATION_DISABLE => 'ACC_DISABLE', USER_ACTIVATION_NONE => 'ACC_NONE'); + $radio_text = h_radio('config[require_activation]', $radio_ary, $value, $key); if ($config['email_enable']) { - $radio_ary += array(USER_ACTIVATION_SELF => 'ACC_USER', USER_ACTIVATION_ADMIN => 'ACC_ADMIN'); + $radio_ary = array(USER_ACTIVATION_SELF => 'ACC_USER', USER_ACTIVATION_ADMIN => 'ACC_ADMIN'); + // With longer labels the four options no longer fit + // onto a single line. Separate them onto two lines. + // This also requires two h_radio calls to generate HTML. + $radio_text .= '

'; + $radio_text .= h_radio('config[require_activation]', $radio_ary, $value, $key); } - return h_radio('config[require_activation]', $radio_ary, $value, $key); + return $radio_text; } /** -- cgit v1.2.1 From 5254ec27959d8a4b2e6af61d0d28080a81ff86b5 Mon Sep 17 00:00:00 2001 From: rxu Date: Sun, 1 May 2011 13:38:39 +0800 Subject: [ticket/6712] Add phpbb_ function name prefix, more docs, rename current_time PHPBB3-6712 --- phpBB/includes/functions_posting.php | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index ab346afb38..7713c07bc0 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -2611,16 +2611,27 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u return $url; } -/* +/** * Handle topic bumping +* @param int $forum_id The ID of the forum the topic is being bumped belongs to +* @param int $topic_id The ID of the topic is being bumping +* @param array $post_data Passes some topic parameters: +* - 'topic_title' +* - 'topic_last_post_id' +* - 'topic_last_poster_id' +* - 'topic_last_post_subject' +* - 'topic_last_poster_name' +* - 'topic_last_poster_colour' +* @param int $bump_time The time at which topic was bumped, usually it is a current time as obtained via time(). +* @return string An URL to the bumped topic, example: ./viewtopic.php?forum_id=1&topic_id=2&p=3#p3 */ -function bump_topic($forum_id, $topic_id, $post_data, $current_time = false) +function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false) { global $config, $db, $user, $phpEx, $phpbb_root_path; - if ($current_time === false) + if ($bump_time === false) { - $current_time = time(); + $bump_time = time(); } // Begin bumping @@ -2628,14 +2639,14 @@ function bump_topic($forum_id, $topic_id, $post_data, $current_time = false) // Update the topic's last post post_time $sql = 'UPDATE ' . POSTS_TABLE . " - SET post_time = $current_time + SET post_time = $bump_time WHERE post_id = {$post_data['topic_last_post_id']} AND topic_id = $topic_id"; $db->sql_query($sql); // Sync the topic's last post time, the rest of the topic's last post data isn't changed $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_last_post_time = $current_time, + SET topic_last_post_time = $bump_time, topic_bumped = 1, topic_bumper = " . $user->data['user_id'] . " WHERE topic_id = $topic_id"; @@ -2646,7 +2657,7 @@ function bump_topic($forum_id, $topic_id, $post_data, $current_time = false) SET forum_last_post_id = " . $post_data['topic_last_post_id'] . ", forum_last_poster_id = " . $post_data['topic_last_poster_id'] . ", forum_last_post_subject = '" . $db->sql_escape($post_data['topic_last_post_subject']) . "', - forum_last_post_time = $current_time, + forum_last_post_time = $bump_time, forum_last_poster_name = '" . $db->sql_escape($post_data['topic_last_poster_name']) . "', forum_last_poster_colour = '" . $db->sql_escape($post_data['topic_last_poster_colour']) . "' WHERE forum_id = $forum_id"; @@ -2654,17 +2665,17 @@ function bump_topic($forum_id, $topic_id, $post_data, $current_time = false) // Update bumper's time of the last posting to prevent flood $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lastpost_time = $current_time + SET user_lastpost_time = $bump_time WHERE user_id = " . $user->data['user_id']; $db->sql_query($sql); $db->sql_transaction('commit'); // Mark this topic as posted to - markread('post', $forum_id, $topic_id, $current_time); + markread('post', $forum_id, $topic_id, $bump_time); // Mark this topic as read - markread('topic', $forum_id, $topic_id, $current_time); + markread('topic', $forum_id, $topic_id, $bump_time); // Update forum tracking info if ($config['load_db_lastread'] && $user->data['is_registered']) -- cgit v1.2.1 From c844a277b2a6e4ad6232925fa78868cd945fc8a1 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 1 May 2011 03:09:49 -0400 Subject: [feature/template-engine] Check return value of display() in assign_display(). If display() failed, propagate the failure out of assign_display(). PHPBB3-9726 --- phpBB/includes/template.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index ae68f5fad3..b07e77989c 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -304,7 +304,11 @@ class phpbb_template public function assign_display($handle, $template_var = '', $return_content = true, $include_once = false) { ob_start(); - $this->display($handle, $include_once); + $result = $this->display($handle, $include_once); + if ($result === false) + { + return false; + } $contents = ob_get_clean(); if ($return_content) -- cgit v1.2.1 From 234b891a4be11dc0f20d93dd272242ad20344aa0 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 1 May 2011 03:14:11 -0400 Subject: [feature/template-engine] Fixed description of assign_display(). This function returns false on failure, which can happen if display() failed. Document the failure return value. PHPBB3-9726 --- phpBB/includes/template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index b07e77989c..ac37dc3dd2 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -299,7 +299,7 @@ class phpbb_template * @param string $template_var Template variable to assign compiled handle to * @param bool $return_content If true return compiled handle, otherwise assign to $template_var * @param bool $include_once Allow multiple inclusions of the file - * @return bool|string If $return_content is true return string of the compiled handle, otherwise return true + * @return bool|string false on failure, otherwise if $return_content is true return string of the compiled handle, otherwise return true */ public function assign_display($handle, $template_var = '', $return_content = true, $include_once = false) { -- cgit v1.2.1 From 63ca4c2104e7c61b6f2238b13bd5428b579be9e7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 1 May 2011 03:25:22 -0400 Subject: [feature/template-engine] Close output stream in compile(). There is no need to leave the stream to the garbage collector, and the amount of data stuck in it may be substantial. PHPBB3-9726 --- phpBB/includes/template_compile.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php index 3f8a028e25..e2bb9fd869 100644 --- a/phpBB/includes/template_compile.php +++ b/phpBB/includes/template_compile.php @@ -920,6 +920,9 @@ class phpbb_template_compile @fclose($source_handle); rewind($destination_handle); - return stream_get_contents($destination_handle); + $contents = stream_get_contents($destination_handle); + @fclose($dest_handle); + + return $contents; } } -- cgit v1.2.1 From d840de560cc59cd9b6c7da7b794dc3b2756e7377 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 1 May 2011 03:28:53 -0400 Subject: [feature/template-engine] Extracted compile_stream_to_stream. PHPBB3-9726 --- phpBB/includes/template_compile.php | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php index e2bb9fd869..dfbf578b58 100644 --- a/phpBB/includes/template_compile.php +++ b/phpBB/includes/template_compile.php @@ -883,8 +883,7 @@ class phpbb_template_compile @flock($destination_handle, LOCK_EX); - stream_filter_append($source_handle, 'phpbb_template'); - stream_copy_to_stream($source_handle, $destination_handle); + $this->compile_stream_to_stream($source_handle, $destination_handle); @fclose($source_handle); @flock($destination_handle, LOCK_UN); @@ -914,8 +913,7 @@ class phpbb_template_compile return false; } - stream_filter_append($source_handle, 'phpbb_template'); - stream_copy_to_stream($source_handle, $destination_handle); + $this->compile_stream_to_stream($source_handle, $destination_handle); @fclose($source_handle); @@ -925,4 +923,21 @@ class phpbb_template_compile return $contents; } + + /** + * Compiles contents of $source_stream into $dest_stream. + * + * A stream filter is appended to $source_stream as part of the + * process. + * + * @access private + * @param resource $source_stream Source stream + * @param resource $dest_stream Destination stream + * @return void + */ + private function compile_stream_to_stream($source_stream, $dest_stream) + { + stream_filter_append($source_stream, 'phpbb_template'); + stream_copy_to_stream($source_stream, $dest_stream); + } } -- cgit v1.2.1 From 48691b53a6b3397ede4f009e8a108b14b7f7f305 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 1 May 2011 04:00:24 -0400 Subject: [feature/template-engine] Rename template_compile methods for clarity. PHPBB3-9726 --- phpBB/includes/template.php | 18 +++++++++--------- phpBB/includes/template_compile.php | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index ac37dc3dd2..dc461fb60e 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -384,7 +384,7 @@ class phpbb_template $compile = new phpbb_template_compile(); - if ($compile->compile_write($source_file, $this->_compiled_file_for_handle($handle)) === false) + if ($compile->compile_file_to_file($source_file, $this->_compiled_file_for_handle($handle)) === false) { return false; } @@ -443,7 +443,7 @@ class phpbb_template $source_file = $this->_source_file_for_handle($handle); - if (($code = $compile->compile_gen($source_file)) === false) + if (($code = $compile->compile_file($source_file)) === false) { return false; } @@ -509,13 +509,13 @@ class phpbb_template { if ($row['template_filename'] == $this->filename[$handle]) { - $compile->compile_write($source_file, $this->_compiled_file_for_handle($handle)); + $compile->compile_file_to_file($source_file, $this->_compiled_file_for_handle($handle)); } else { $this->files[$row['template_filename']] = $file; $this->filename[$row['template_filename']] = $row['template_filename']; - $compile->compile_write($this->_source_file_for_handle($row['template_filename']), $this->_compiled_file_for_handle($row['template_filename'])); + $compile->compile_file_to_file($this->_source_file_for_handle($row['template_filename']), $this->_compiled_file_for_handle($row['template_filename'])); unset($this->compiled_code[$row['template_filename']]); unset($this->files[$row['template_filename']]); unset($this->filename[$row['template_filename']]); @@ -525,7 +525,7 @@ class phpbb_template if ($row['template_filename'] == $this->filename[$handle]) { $this->compiled_code[$handle] = $compile->compile(trim($row['template_data'])); - $compile->compile_write($handle, $this->compiled_code[$handle]); + $compile->compile_file_to_file($handle, $this->compiled_code[$handle]); } else { @@ -533,7 +533,7 @@ class phpbb_template if (!file_exists($this->cachepath . str_replace('/', '.', $row['template_filename']) . '.' . $phpEx)) { $this->filename[$row['template_filename']] = $row['template_filename']; - $compile->compile_write($row['template_filename'], $compile->compile(trim($row['template_data']))); + $compile->compile_file_to_file($row['template_filename'], $compile->compile(trim($row['template_data']))); unset($this->filename[$row['template_filename']]); } } @@ -551,14 +551,14 @@ class phpbb_template $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id']; } // Try to load from filesystem and instruct to insert into the styles table... - $compile->compile_write($source_file, $this->_compiled_file_for_handle($handle)); + $compile->compile_file_to_file($source_file, $this->_compiled_file_for_handle($handle)); return false; } return false; } - $compile->compile_write($source_file, $this->_compiled_file_for_handle($handle)); + $compile->compile_file_to_file($source_file, $this->_compiled_file_for_handle($handle)); return false; } @@ -838,7 +838,7 @@ class phpbb_template $compile = new phpbb_template_compile(); $source_file = $this->_source_file_for_handle($handle); - if (($code = $compile->compile_gen($source_file)) !== false) + if (($code = $compile->compile_file($source_file)) !== false) { $code = ' ?> ' . $code . ' Date: Sun, 1 May 2011 04:03:06 -0400 Subject: [feature/template-engine] Delete template class, use phpbb_template instead. PHPBB3-9726 --- phpBB/includes/functions_messenger.php | 2 +- phpBB/includes/template.php | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index f5d102b1da..8255d4b148 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -193,7 +193,7 @@ class messenger // tpl_msg now holds a template object we can use to parse the template file if (!isset($this->tpl_msg[$template_lang . $template_file])) { - $this->tpl_msg[$template_lang . $template_file] = new template(); + $this->tpl_msg[$template_lang . $template_file] = new phpbb_template(); $tpl = &$this->tpl_msg[$template_lang . $template_file]; $fallback_template_path = false; diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index dc461fb60e..2a32af406c 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -866,12 +866,3 @@ class phpbb_template include($file); } } - -/** - * @todo remove this - * - */ -class template extends phpbb_template -{ - // dirty hack -} -- cgit v1.2.1 From 237deb12cea909822e0f2fa3c072d31adfec3fb1 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 3 May 2011 23:50:17 -0400 Subject: [feature/template-engine] Removed storedb-related logic. phpBB 3.1 will not provide the option to store templates in the database. This commit removes code that handles templates stored in database from the template engine. PHPBB3-9726 --- phpBB/includes/template.php | 126 +------------------------------------------- 1 file changed, 2 insertions(+), 124 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 2a32af406c..add52b5c30 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -74,7 +74,6 @@ class phpbb_template public $files_template = array(); public $inherit_root = ''; - public $orig_tpl_storedb; public $orig_tpl_inherits_id; // this will hash handle names to the compiled/uncompiled code for that handle. @@ -93,17 +92,11 @@ class phpbb_template $this->root = $phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template'; $this->cachepath = $phpbb_root_path . 'cache/tpl_' . str_replace('_', '-', $user->theme['template_path']) . '_'; - if ($this->orig_tpl_storedb === null) - { - $this->orig_tpl_storedb = $user->theme['template_storedb']; - } - if ($this->orig_tpl_inherits_id === null) { $this->orig_tpl_inherits_id = $user->theme['template_inherits_id']; } - $user->theme['template_storedb'] = $this->orig_tpl_storedb; $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; if ($user->theme['template_inherits_id']) @@ -156,10 +149,6 @@ class phpbb_template $this->orig_tpl_inherits_id = false; } - // the database does not store the path or name of a custom template - // so there is no way we can properly store custom templates there - $this->orig_tpl_storedb = false; - $this->_rootref = &$this->_tpldata['.'][0]; return true; @@ -337,10 +326,9 @@ class phpbb_template trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR); } - // reload these settings to have the values they had when this object was initialised + // reload this setting to have the values they had when this object was initialised // using set_template or set_custom_template, they might otherwise have been overwritten // by other template class instances in between. - $user->theme['template_storedb'] = $this->orig_tpl_storedb; $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; @@ -373,7 +361,7 @@ class phpbb_template return $filename; } - // Inheritance - we point to another template file for this one. Equality is also used for store_db + // Inheritance - we point to another template file for this one. if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) { $this->files[$handle] = $this->files_inherit[$handle]; @@ -448,116 +436,6 @@ class phpbb_template return false; } - if (isset($user->theme['template_storedb']) && $user->theme['template_storedb']) - { - $rows = array(); - $ids = array(); - // Inheritance - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id']) - { - $ids[] = $user->theme['template_inherits_id']; - } - $ids[] = $user->theme['template_id']; - - global $db; - - foreach ($ids as $id) - { - $sql = 'SELECT * - FROM ' . STYLES_TEMPLATE_DATA_TABLE . ' - WHERE template_id = ' . $id . " - AND (template_filename = '" . $db->sql_escape($this->filename[$handle]) . "' - OR template_included " . $db->sql_like_expression($db->any_char . $this->filename[$handle] . ':' . $db->any_char) . ')'; - - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $rows[$row['template_filename']] = $row; - } - $db->sql_freeresult($result); - } - - if (sizeof($rows)) - { - foreach ($rows as $row) - { - $file = $this->root . '/' . $row['template_filename']; - $force_reload = false; - if ($row['template_id'] != $user->theme['template_id']) - { - // make sure that we are not overlooking a file not in the db yet - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($file)) - { - $file = $this->inherit_root . '/' . $row['template_filename']; - $this->files[$row['template_filename']] = $file; - $this->files_inherit[$row['template_filename']] = $file; - $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id']; - } - else if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id']) - { - // Ok, we have a situation. There is a file in the subtemplate, but nothing in the DB. We have to fix that. - $force_reload = true; - $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id']; - } - } - else - { - $this->files_template[$row['template_filename']] = $user->theme['template_id']; - } - - if ($force_reload || $row['template_mtime'] < @filemtime($file)) - { - if ($row['template_filename'] == $this->filename[$handle]) - { - $compile->compile_file_to_file($source_file, $this->_compiled_file_for_handle($handle)); - } - else - { - $this->files[$row['template_filename']] = $file; - $this->filename[$row['template_filename']] = $row['template_filename']; - $compile->compile_file_to_file($this->_source_file_for_handle($row['template_filename']), $this->_compiled_file_for_handle($row['template_filename'])); - unset($this->compiled_code[$row['template_filename']]); - unset($this->files[$row['template_filename']]); - unset($this->filename[$row['template_filename']]); - } - } - - if ($row['template_filename'] == $this->filename[$handle]) - { - $this->compiled_code[$handle] = $compile->compile(trim($row['template_data'])); - $compile->compile_file_to_file($handle, $this->compiled_code[$handle]); - } - else - { - // Only bother compiling if it doesn't already exist - if (!file_exists($this->cachepath . str_replace('/', '.', $row['template_filename']) . '.' . $phpEx)) - { - $this->filename[$row['template_filename']] = $row['template_filename']; - $compile->compile_file_to_file($row['template_filename'], $compile->compile(trim($row['template_data']))); - unset($this->filename[$row['template_filename']]); - } - } - } - } - else - { - $file = $this->root . '/' . $row['template_filename']; - - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($file)) - { - $file = $this->inherit_root . '/' . $row['template_filename']; - $this->files[$row['template_filename']] = $file; - $this->files_inherit[$row['template_filename']] = $file; - $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id']; - } - // Try to load from filesystem and instruct to insert into the styles table... - $compile->compile_file_to_file($source_file, $this->_compiled_file_for_handle($handle)); - return false; - } - - return false; - } - $compile->compile_file_to_file($source_file, $this->_compiled_file_for_handle($handle)); return false; } -- cgit v1.2.1 From d06e59f63bc8213a4d679ff0c20a23dcf8cd524e Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Tue, 3 May 2011 23:53:22 -0400 Subject: [feature/template-engine] Split template execution logic into classes. Template executor interface defines a template executor object. It is an object which can execute (i.e. display/render) a template. Currently there are two implementations: * phpbb_template_executor_include includes php code from a file. * phpbb_template_executor_eval eval's php code. PHPBB3-9726 --- phpBB/includes/template.php | 107 +++++++++++---------------- phpBB/includes/template_executor.php | 15 ++++ phpBB/includes/template_executor_eval.php | 32 ++++++++ phpBB/includes/template_executor_include.php | 32 ++++++++ 4 files changed, 123 insertions(+), 63 deletions(-) create mode 100644 phpBB/includes/template_executor.php create mode 100644 phpBB/includes/template_executor_eval.php create mode 100644 phpBB/includes/template_executor_include.php (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index add52b5c30..8529b90719 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -263,22 +263,17 @@ class phpbb_template $_rootref = &$this->_rootref; $_lang = &$user->lang; - if (($filename = $this->_tpl_load($handle)) !== false) - { - ($include_once) ? include_once($filename) : include($filename); - } - else if (($code = $this->_tpl_eval($handle)) !== false) + $executor = $this->_tpl_load($handle); + + if ($executor) { - $code = ' ?> ' . $code . ' execute(); + return true; } else { - // if we could not eval AND the file exists, something horrific has occured return false; } - - return true; } /** @@ -311,11 +306,27 @@ class phpbb_template } /** - * Load a compiled template if possible, if not, recompile it + * Obtains a template executor for a template identified by specified + * handle. THe template executor can execute the template later. + * + * Template source will first be compiled into php code. + * 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 + * configuration setting may be used to force templates to be always + * recompiled. + * + * Returns an object implementing phpbb_template_executor, or null + * if template loading or compilation failed. Call execute() on the + * executor to execute the template. This will result in template + * contents sent to the output stream (unless, of course, output + * buffering is in effect). + * * @access private * @param string $handle Handle of the template to load - * @return string|bool Return filename on success otherwise false - * @uses template_compile is used to compile uncached templates + * @return phpbb_template_executor Template executor object, or null on failure + * @uses template_compile is used to compile template source */ private function _tpl_load($handle) { @@ -358,7 +369,7 @@ class phpbb_template // Recompile page if the original template is newer, otherwise load the compiled version if (!$recompile) { - return $filename; + return new phpbb_template_executor_include($filename); } // Inheritance - we point to another template file for this one. @@ -372,12 +383,21 @@ class phpbb_template $compile = new phpbb_template_compile(); - if ($compile->compile_file_to_file($source_file, $this->_compiled_file_for_handle($handle)) === false) + $output_file = $this->_compiled_file_for_handle($handle); + if ($compile->compile_file_to_file($source_file, $output_file) !== false) { - return false; + $executor = new phpbb_template_executor_include($output_file); + } + else if (($code = $compile->compile_file($source_file)) !== false) + { + $executor = new phpbb_template_executor_eval($code); + } + else + { + $executor = null; } - return $filename; + return $executor; } /** @@ -418,28 +438,6 @@ class phpbb_template return $compiled_file; } - /** - * This code should only run when some high level error prevents us from writing to the cache. - * @access private - * @param string $handle Template handle to compile - * @return string|bool Return compiled code on success otherwise false - * @uses template_compile is used to compile template - */ - private function _tpl_eval($handle) - { - $compile = new phpbb_template_compile(); - - $source_file = $this->_source_file_for_handle($handle); - - if (($code = $compile->compile_file($source_file)) === false) - { - return false; - } - - $compile->compile_file_to_file($source_file, $this->_compiled_file_for_handle($handle)); - return false; - } - /** * Assign key variable pairs from an array * @access public @@ -696,32 +694,15 @@ class phpbb_template $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename; } - $filename = $this->_tpl_load($handle); + $executor = $this->_tpl_load($handle); - if ($include) + if ($executor) { - global $user; - - $_tpldata = &$this->_tpldata; - $_rootref = &$this->_rootref; - $_lang = &$user->lang; - - if ($filename) - { - include($filename); - return; - } - else - { - $compile = new phpbb_template_compile(); - - $source_file = $this->_source_file_for_handle($handle); - if (($code = $compile->compile_file($source_file)) !== false) - { - $code = ' ?> ' . $code . ' execute(); + } + else + { + // What should we do here? } } diff --git a/phpBB/includes/template_executor.php b/phpBB/includes/template_executor.php new file mode 100644 index 0000000000..9bbb3dca0d --- /dev/null +++ b/phpBB/includes/template_executor.php @@ -0,0 +1,15 @@ +code = $code; + } + + /** + * Executes the template managed by this executor by eval'ing php code + * of the template. + */ + public function execute() + { + eval($this->code); + } +} diff --git a/phpBB/includes/template_executor_include.php b/phpBB/includes/template_executor_include.php new file mode 100644 index 0000000000..74f0593b13 --- /dev/null +++ b/phpBB/includes/template_executor_include.php @@ -0,0 +1,32 @@ +path = $path; + } + + /** + * Executes the template managed by this executor by including + * the php file containing the template. + */ + public function execute() + { + include($this->path); + } +} -- cgit v1.2.1 From b057d7439e9ed27ec0aa6cff021fd6a9df6e85eb Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 4 May 2011 01:00:40 -0400 Subject: [feature/template-engine] Removed some dead code. PHPBB3-9726 --- phpBB/includes/template_compile.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php index 553f99bd8c..1feab3b7c4 100644 --- a/phpBB/includes/template_compile.php +++ b/phpBB/includes/template_compile.php @@ -118,8 +118,6 @@ class phpbb_template_filter extends php_user_filter $data = preg_replace('~.*?$~', '', $data); } - "?>/**/"; - /* Preserve whitespace. PHP removes a newline after the closing tag (if it's there). This is by design. @@ -145,7 +143,7 @@ class phpbb_template_filter extends php_user_filter */ -//* + $data = preg_replace('~(?).)+(?)$~m', "$1\n", $data); $data = str_replace('/**/?>', "?>\n", $data); $data = str_replace('?> Date: Thu, 5 May 2011 10:49:54 +0200 Subject: [ticket/10158] Add "Return to Inbox"-link to "PM send"-message. PHPBB3-10158 --- phpBB/includes/ucp/ucp_pm_compose.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index b596e72c41..d7fe0af361 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -741,10 +741,13 @@ function compose_pm($id, $mode, $action) $msg_id = submit_pm($action, $subject, $pm_data); $return_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&p=' . $msg_id); - $return_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); + $return_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'); + $outbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); meta_refresh(3, $return_message_url); - $message = $user->lang['MESSAGE_STORED'] . '

' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '', '') . '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_OUTBOX']); + $message = $user->lang['MESSAGE_STORED'] . '

' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '', ''); + $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_INBOX']); + $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_OUTBOX']); trigger_error($message); } -- cgit v1.2.1 From d8122df3329214f8710c8af3c0ce1ed86505e810 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 5 May 2011 19:03:46 -0400 Subject: [feature/template-engine] Always call ob_end_clean. We have to stop output buffering even when rendering fails. PHPBB3-9726 --- phpBB/includes/template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 8529b90719..8d7eb57dc4 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -289,11 +289,11 @@ class phpbb_template { ob_start(); $result = $this->display($handle, $include_once); + $contents = ob_get_clean(); if ($result === false) { return false; } - $contents = ob_get_clean(); if ($return_content) { -- cgit v1.2.1 From 0501640d5db158a010741e27803191ab469834c4 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 7 May 2011 15:10:50 -0400 Subject: [feature/template-engine] Added phpbb_template_context class. Objects of this class hold variables assigned to templates. PHPBB3-9726 --- phpBB/includes/template.php | 281 ++++--------------------- phpBB/includes/template_compile.php | 2 +- phpBB/includes/template_context.php | 299 +++++++++++++++++++++++++++ phpBB/includes/template_executor.php | 4 +- phpBB/includes/template_executor_eval.php | 14 +- phpBB/includes/template_executor_include.php | 13 +- 6 files changed, 367 insertions(+), 246 deletions(-) create mode 100644 phpBB/includes/template_context.php (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 8d7eb57dc4..755e6adba9 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -36,19 +36,11 @@ class phpbb_template public $phpbb_optional = array(); /** - * variable that holds all the data we'll be substituting into - * the compiled templates. Takes form: - * --> $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value - * if it's a root-level variable, it'll be like this: - * --> $this->_tpldata[.][0][varname] == value - * @var array - */ - private $_tpldata = array('.' => array(0 => array())); - - /** - * @var array Reference to template->_tpldata['.'][0] + * @var phpbb_template_context Template context. + * Stores template data used during template rendering. + * @access private */ - private $_rootref; + private $_context; /** * @var string Root dir for template. @@ -109,7 +101,7 @@ class phpbb_template trigger_error('Template path could not be found: styles/' . $user->theme['template_path'] . '/template', E_USER_ERROR); } - $this->_rootref = &$this->_tpldata['.'][0]; + $this->_context = new phpbb_template_context(); return true; } @@ -149,7 +141,7 @@ class phpbb_template $this->orig_tpl_inherits_id = false; } - $this->_rootref = &$this->_tpldata['.'][0]; + $this->_context = new phpbb_template_context(); return true; } @@ -181,24 +173,6 @@ class phpbb_template return true; } - /** - * Destroy template data set - * @access public - */ - public function destroy() - { - $this->_tpldata = array('.' => array(0 => array())); - $this->_rootref = &$this->_tpldata['.'][0]; - } - - /** - * destroy method kept for compatibility. - */ - public function __destruct() - { - $this->destroy(); - } - /** * Reset/empty complete block * @access public @@ -206,28 +180,7 @@ class phpbb_template */ public function destroy_block_vars($blockname) { - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - $str = &$this->_tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - $str = &$str[$blocks[$i]]; - $str = &$str[sizeof($str) - 1]; - } - - unset($str[$blocks[$blockcount]]); - } - else - { - // Top-level block. - unset($this->_tpldata[$blockname]); - } - - return true; + $this->_context->destroy_block_vars($blockname); } /** @@ -239,7 +192,7 @@ class phpbb_template */ public function display($handle, $include_once = true) { - global $user, $phpbb_hook; + global $phpbb_hook; if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once, $this)) { @@ -259,15 +212,11 @@ class phpbb_template } */ - $_tpldata = &$this->_tpldata; - $_rootref = &$this->_rootref; - $_lang = &$user->lang; - $executor = $this->_tpl_load($handle); if ($executor) { - $executor->execute(); + $executor->execute($this->_context, $this->get_lang()); return true; } else @@ -276,6 +225,27 @@ class phpbb_template } } + /** + * Obtains language array. + * This is either lang property of global $user object, or if + * it is not set an empty array. + * @return array language entries + */ + public function get_lang() + { + global $user; + + if (isset($user->lang)) + { + $lang = $user->lang; + } + else + { + $lang = array(); + } + return $lang; + } + /** * Display the handle and assign the output to a template variable or return the compiled result. * @access public @@ -369,7 +339,7 @@ class phpbb_template // Recompile page if the original template is newer, otherwise load the compiled version if (!$recompile) { - return new phpbb_template_executor_include($filename); + return new phpbb_template_executor_include($filename, $this); } // Inheritance - we point to another template file for this one. @@ -386,11 +356,11 @@ class phpbb_template $output_file = $this->_compiled_file_for_handle($handle); if ($compile->compile_file_to_file($source_file, $output_file) !== false) { - $executor = new phpbb_template_executor_include($output_file); + $executor = new phpbb_template_executor_include($output_file, $this); } else if (($code = $compile->compile_file($source_file)) !== false) { - $executor = new phpbb_template_executor_eval($code); + $executor = new phpbb_template_executor_eval($code, $this); } else { @@ -447,10 +417,8 @@ class phpbb_template { foreach ($vararray as $key => $val) { - $this->_rootref[$key] = $val; + $this->assign_var($key, $val); } - - return true; } /** @@ -461,11 +429,10 @@ class phpbb_template */ public function assign_var($varname, $varval) { - $this->_rootref[$varname] = $varval; - - return true; + $this->_context->assign_var($varname, $varval); } + // Docstring is copied from phpbb_template_context method with the same name. /** * Assign key variable pairs from an array to a specified block * @access public @@ -474,67 +441,10 @@ class phpbb_template */ public function assign_block_vars($blockname, array $vararray) { - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - $str = &$this->_tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - $str = &$str[$blocks[$i]]; - $str = &$str[sizeof($str) - 1]; - } - - $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0; - $vararray['S_ROW_COUNT'] = $s_row_count; - - // Assign S_FIRST_ROW - if (!$s_row_count) - { - $vararray['S_FIRST_ROW'] = true; - } - - // Now the tricky part, we always assign S_LAST_ROW and remove the entry before - // This is much more clever than going through the complete template data on display (phew) - $vararray['S_LAST_ROW'] = true; - if ($s_row_count > 0) - { - unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']); - } - - // Now we add the block that we're actually assigning to. - // We're adding a new iteration to this block with the given - // variable assignments. - $str[$blocks[$blockcount]][] = $vararray; - } - else - { - // Top-level block. - $s_row_count = (isset($this->_tpldata[$blockname])) ? sizeof($this->_tpldata[$blockname]) : 0; - $vararray['S_ROW_COUNT'] = $s_row_count; - - // Assign S_FIRST_ROW - if (!$s_row_count) - { - $vararray['S_FIRST_ROW'] = true; - } - - // We always assign S_LAST_ROW and remove the entry before - $vararray['S_LAST_ROW'] = true; - if ($s_row_count > 0) - { - unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']); - } - - // Add a new iteration to this block with the variable assignments we were given. - $this->_tpldata[$blockname][] = $vararray; - } - - return true; + return $this->_context->assign_block_vars($blockname, $vararray); } + // Docstring is copied from phpbb_template_context method with the same name. /** * Change already assigned key variable pair (one-dimensional - single loop entry) * @@ -565,116 +475,7 @@ class phpbb_template */ public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') { - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - $block = &$this->_tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - if (($pos = strpos($blocks[$i], '[')) !== false) - { - $name = substr($blocks[$i], 0, $pos); - - if (strpos($blocks[$i], '[]') === $pos) - { - $index = sizeof($block[$name]) - 1; - } - else - { - $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1); - } - } - else - { - $name = $blocks[$i]; - $index = sizeof($block[$name]) - 1; - } - $block = &$block[$name]; - $block = &$block[$index]; - } - - $block = &$block[$blocks[$i]]; // Traverse the last block - } - else - { - // Top-level block. - $block = &$this->_tpldata[$blockname]; - } - - // Change key to zero (change first position) if false and to last position if true - if ($key === false || $key === true) - { - $key = ($key === false) ? 0 : sizeof($block); - } - - // Get correct position if array given - if (is_array($key)) - { - // Search array to get correct position - list($search_key, $search_value) = @each($key); - - $key = NULL; - foreach ($block as $i => $val_ary) - { - if ($val_ary[$search_key] === $search_value) - { - $key = $i; - break; - } - } - - // key/value pair not found - if ($key === NULL) - { - return false; - } - } - - // Insert Block - if ($mode == 'insert') - { - // Make sure we are not exceeding the last iteration - if ($key >= sizeof($this->_tpldata[$blockname])) - { - $key = sizeof($this->_tpldata[$blockname]); - unset($this->_tpldata[$blockname][($key - 1)]['S_LAST_ROW']); - $vararray['S_LAST_ROW'] = true; - } - else if ($key === 0) - { - unset($this->_tpldata[$blockname][0]['S_FIRST_ROW']); - $vararray['S_FIRST_ROW'] = true; - } - - // Re-position template blocks - for ($i = sizeof($block); $i > $key; $i--) - { - $block[$i] = $block[$i-1]; - } - - // Insert vararray at given position - $block[$key] = $vararray; - - return true; - } - - // Which block to change? - if ($mode == 'change') - { - if ($key == sizeof($block)) - { - $key--; - } - - $block[$key] = array_merge($block[$key], $vararray); - - return true; - } - - return false; + return $this->_context->alter_block_array($blockname, $vararray, $key, $mode); } /** @@ -684,7 +485,7 @@ class phpbb_template * @param bool $include True to include the file, false to just load it * @uses template_compile is used to compile uncached templates */ - private function _tpl_include($filename, $include = true) + public function _tpl_include($filename, $include = true) { $handle = $filename; $this->filename[$handle] = $filename; @@ -698,7 +499,7 @@ class phpbb_template if ($executor) { - $executor->execute(); + $executor->execute($this->_context, $this->get_lang()); } else { diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php index 1feab3b7c4..4132fb2e34 100644 --- a/phpBB/includes/template_compile.php +++ b/phpBB/includes/template_compile.php @@ -639,7 +639,7 @@ class phpbb_template_filter extends php_user_filter */ private function compile_tag_include($tag_args) { - return "\$this->_tpl_include('$tag_args');"; + return "\$_template->_tpl_include('$tag_args');"; } /** diff --git a/phpBB/includes/template_context.php b/phpBB/includes/template_context.php new file mode 100644 index 0000000000..ae898e9be1 --- /dev/null +++ b/phpBB/includes/template_context.php @@ -0,0 +1,299 @@ + $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value + * if it's a root-level variable, it'll be like this: + * --> $this->_tpldata[.][0][varname] == value + * @var array + */ + private $_tpldata = array('.' => array(0 => array())); + + /** + * @var array Reference to template->_tpldata['.'][0] + */ + private $_rootref; + + public function __construct() + { + $this->clear(); + } + + /** + * Clears template data set. + * @access public + */ + public function clear() + { + $this->_tpldata = array('.' => array(0 => array())); + $this->_rootref = &$this->_tpldata['.'][0]; + } + + /** + * Assign a single variable to a single key + * @access public + * @param string $varname Variable name + * @param string $varval Value to assign to variable + */ + public function assign_var($varname, $varval) + { + $this->_rootref[$varname] = $varval; + + return true; + } + + public function get_data_ref() + { + return $this->_tpldata; + } + + public function get_root_ref() + { + return $this->_rootref; + } + + /** + * Assign key variable pairs from an array to a specified block + * @access public + * @param string $blockname Name of block to assign $vararray to + * @param array $vararray A hash of variable name => value pairs + */ + public function assign_block_vars($blockname, array $vararray) + { + if (strpos($blockname, '.') !== false) + { + // Nested block. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $str = &$this->_tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + $str = &$str[$blocks[$i]]; + $str = &$str[sizeof($str) - 1]; + } + + $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0; + $vararray['S_ROW_COUNT'] = $s_row_count; + + // Assign S_FIRST_ROW + if (!$s_row_count) + { + $vararray['S_FIRST_ROW'] = true; + } + + // Now the tricky part, we always assign S_LAST_ROW and remove the entry before + // This is much more clever than going through the complete template data on display (phew) + $vararray['S_LAST_ROW'] = true; + if ($s_row_count > 0) + { + unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']); + } + + // Now we add the block that we're actually assigning to. + // We're adding a new iteration to this block with the given + // variable assignments. + $str[$blocks[$blockcount]][] = $vararray; + } + else + { + // Top-level block. + $s_row_count = (isset($this->_tpldata[$blockname])) ? sizeof($this->_tpldata[$blockname]) : 0; + $vararray['S_ROW_COUNT'] = $s_row_count; + + // Assign S_FIRST_ROW + if (!$s_row_count) + { + $vararray['S_FIRST_ROW'] = true; + } + + // We always assign S_LAST_ROW and remove the entry before + $vararray['S_LAST_ROW'] = true; + if ($s_row_count > 0) + { + unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']); + } + + // Add a new iteration to this block with the variable assignments we were given. + $this->_tpldata[$blockname][] = $vararray; + } + + return true; + } + + /** + * Change already assigned key variable pair (one-dimensional - single loop entry) + * + * An example of how to use this function: + * {@example alter_block_array.php} + * + * @param string $blockname the blockname, for example 'loop' + * @param array $vararray the var array to insert/add or merge + * @param mixed $key Key to search for + * + * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] + * + * int: Position [the position to change or insert at directly given] + * + * If key is false the position is set to 0 + * If key is true the position is set to the last entry + * + * @param string $mode Mode to execute (valid modes are 'insert' and 'change') + * + * If insert, the vararray is inserted at the given position (position counting from zero). + * If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new value). + * + * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array) + * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars) + * + * @return bool false on error, true on success + * @access public + */ + public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') + { + if (strpos($blockname, '.') !== false) + { + // Nested block. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $block = &$this->_tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + if (($pos = strpos($blocks[$i], '[')) !== false) + { + $name = substr($blocks[$i], 0, $pos); + + if (strpos($blocks[$i], '[]') === $pos) + { + $index = sizeof($block[$name]) - 1; + } + else + { + $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1); + } + } + else + { + $name = $blocks[$i]; + $index = sizeof($block[$name]) - 1; + } + $block = &$block[$name]; + $block = &$block[$index]; + } + + $block = &$block[$blocks[$i]]; // Traverse the last block + } + else + { + // Top-level block. + $block = &$this->_tpldata[$blockname]; + } + + // Change key to zero (change first position) if false and to last position if true + if ($key === false || $key === true) + { + $key = ($key === false) ? 0 : sizeof($block); + } + + // Get correct position if array given + if (is_array($key)) + { + // Search array to get correct position + list($search_key, $search_value) = @each($key); + + $key = NULL; + foreach ($block as $i => $val_ary) + { + if ($val_ary[$search_key] === $search_value) + { + $key = $i; + break; + } + } + + // key/value pair not found + if ($key === NULL) + { + return false; + } + } + + // Insert Block + if ($mode == 'insert') + { + // Make sure we are not exceeding the last iteration + if ($key >= sizeof($this->_tpldata[$blockname])) + { + $key = sizeof($this->_tpldata[$blockname]); + unset($this->_tpldata[$blockname][($key - 1)]['S_LAST_ROW']); + $vararray['S_LAST_ROW'] = true; + } + else if ($key === 0) + { + unset($this->_tpldata[$blockname][0]['S_FIRST_ROW']); + $vararray['S_FIRST_ROW'] = true; + } + + // Re-position template blocks + for ($i = sizeof($block); $i > $key; $i--) + { + $block[$i] = $block[$i-1]; + } + + // Insert vararray at given position + $block[$key] = $vararray; + + return true; + } + + // Which block to change? + if ($mode == 'change') + { + if ($key == sizeof($block)) + { + $key--; + } + + $block[$key] = array_merge($block[$key], $vararray); + + return true; + } + + return false; + } + + /** + * Reset/empty complete block + * @access public + * @param string $blockname Name of block to destroy + */ + public function destroy_block_vars($blockname) + { + if (strpos($blockname, '.') !== false) + { + // Nested block. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $str = &$this->_tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + $str = &$str[$blocks[$i]]; + $str = &$str[sizeof($str) - 1]; + } + + unset($str[$blocks[$blockcount]]); + } + else + { + // Top-level block. + unset($this->_tpldata[$blockname]); + } + + return true; + } +} diff --git a/phpBB/includes/template_executor.php b/phpBB/includes/template_executor.php index 9bbb3dca0d..32e4e9a7b4 100644 --- a/phpBB/includes/template_executor.php +++ b/phpBB/includes/template_executor.php @@ -10,6 +10,8 @@ interface phpbb_template_executor { /** * Executes the template managed by this executor. + * @param phpbb_template_context $context Template context to use + * @param array $lang Language entries to use */ - public function execute(); + public function execute($context, $lang); } diff --git a/phpBB/includes/template_executor_eval.php b/phpBB/includes/template_executor_eval.php index 27bdf95b52..af7d68fef3 100644 --- a/phpBB/includes/template_executor_eval.php +++ b/phpBB/includes/template_executor_eval.php @@ -13,20 +13,30 @@ class phpbb_template_executor_eval implements phpbb_template_executor /** * Constructor. Stores provided code for future evaluation. + * Template includes are delegated to template object $template. * * @param string $code php code of the template + * @param phpbb_template $template template object */ - public function __construct($code) + public function __construct($code, $template) { $this->code = $code; + $this->template = $template; } /** * Executes the template managed by this executor by eval'ing php code * of the template. + * @param phpbb_template_context $context Template context to use + * @param array $lang Language entries to use */ - public function execute() + public function execute($context, $lang) { + $_template = &$this->template; + $_tpldata = &$context->get_data_ref(); + $_rootref = &$context->get_root_ref(); + $_lang = &$lang; + eval($this->code); } } diff --git a/phpBB/includes/template_executor_include.php b/phpBB/includes/template_executor_include.php index 74f0593b13..3671265cca 100644 --- a/phpBB/includes/template_executor_include.php +++ b/phpBB/includes/template_executor_include.php @@ -13,20 +13,29 @@ class phpbb_template_executor_include implements phpbb_template_executor /** * Constructor. Stores path to the template for future inclusion. + * Template includes are delegated to template object $template. * * @param string $path path to the template */ - public function __construct($path) + public function __construct($path, $template) { $this->path = $path; + $this->template = $template; } /** * Executes the template managed by this executor by including * the php file containing the template. + * @param phpbb_template_context $context Template context to use + * @param array $lang Language entries to use */ - public function execute() + public function execute($context, $lang) { + $_template = &$this->template; + $_tpldata = &$context->get_data_ref(); + $_rootref = &$context->get_root_ref(); + $_lang = &$lang; + include($this->path); } } -- cgit v1.2.1 From b5444a7d7d1f6ac694468d8cc37fc0489e714547 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 7 May 2011 17:50:48 -0400 Subject: [feature/template-engine] Removed more dead code. PHPBB3-9726 --- phpBB/includes/template.php | 6 ------ 1 file changed, 6 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 755e6adba9..02815c4e15 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -32,9 +32,6 @@ if (!defined('IN_PHPBB')) */ class phpbb_template { - public $phpbb_required = array('user', 'config'); - public $phpbb_optional = array(); - /** * @var phpbb_template_context Template context. * Stores template data used during template rendering. @@ -68,9 +65,6 @@ class phpbb_template public $orig_tpl_inherits_id; - // this will hash handle names to the compiled/uncompiled code for that handle. - public $compiled_code = array(); - /** * Set template location * @access public -- cgit v1.2.1 From 1cba674b9a04390ff754bdb34691b3654f5916f9 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sat, 7 May 2011 17:58:56 -0400 Subject: [feature/template-engine] Added docblocks and boilerplate to new files. PHPBB3-9726 --- phpBB/includes/template_context.php | 21 +++++++++++++++++++++ phpBB/includes/template_executor.php | 18 ++++++++++++++++++ phpBB/includes/template_executor_eval.php | 18 ++++++++++++++++++ phpBB/includes/template_executor_include.php | 19 +++++++++++++++++++ 4 files changed, 76 insertions(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template_context.php b/phpBB/includes/template_context.php index ae898e9be1..df5c4afb24 100644 --- a/phpBB/includes/template_context.php +++ b/phpBB/includes/template_context.php @@ -1,5 +1,26 @@ Date: Sun, 8 May 2011 04:03:41 -0400 Subject: [feature/template-engine] Renamed template executor and friends to renderer. PHPBB3-9726 --- phpBB/includes/template.php | 34 ++++++++-------- phpBB/includes/template_executor.php | 35 ---------------- phpBB/includes/template_executor_eval.php | 60 ---------------------------- phpBB/includes/template_executor_include.php | 60 ---------------------------- phpBB/includes/template_renderer.php | 35 ++++++++++++++++ phpBB/includes/template_renderer_eval.php | 60 ++++++++++++++++++++++++++++ phpBB/includes/template_renderer_include.php | 60 ++++++++++++++++++++++++++++ 7 files changed, 172 insertions(+), 172 deletions(-) delete mode 100644 phpBB/includes/template_executor.php delete mode 100644 phpBB/includes/template_executor_eval.php delete mode 100644 phpBB/includes/template_executor_include.php create mode 100644 phpBB/includes/template_renderer.php create mode 100644 phpBB/includes/template_renderer_eval.php create mode 100644 phpBB/includes/template_renderer_include.php (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 02815c4e15..f27d0c7560 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -206,11 +206,11 @@ class phpbb_template } */ - $executor = $this->_tpl_load($handle); + $renderer = $this->_tpl_load($handle); - if ($executor) + if ($renderer) { - $executor->execute($this->_context, $this->get_lang()); + $renderer->render($this->_context, $this->get_lang()); return true; } else @@ -270,8 +270,8 @@ class phpbb_template } /** - * Obtains a template executor for a template identified by specified - * handle. THe template executor can execute the template later. + * Obtains a template renderer for a template identified by specified + * handle. The template renderer can display the template later. * * Template source will first be compiled into php code. * If template cache is writable the compiled php code will be stored @@ -281,15 +281,15 @@ class phpbb_template * configuration setting may be used to force templates to be always * recompiled. * - * Returns an object implementing phpbb_template_executor, or null - * if template loading or compilation failed. Call execute() on the - * executor to execute the template. This will result in template + * Returns an object implementing phpbb_template_renderer, or null + * if template loading or compilation failed. Call render() on the + * renderer to display the template. This will result in template * contents sent to the output stream (unless, of course, output * buffering is in effect). * * @access private * @param string $handle Handle of the template to load - * @return phpbb_template_executor Template executor object, or null on failure + * @return phpbb_template_renderer Template renderer object, or null on failure * @uses template_compile is used to compile template source */ private function _tpl_load($handle) @@ -333,7 +333,7 @@ class phpbb_template // Recompile page if the original template is newer, otherwise load the compiled version if (!$recompile) { - return new phpbb_template_executor_include($filename, $this); + return new phpbb_template_renderer_include($filename, $this); } // Inheritance - we point to another template file for this one. @@ -350,18 +350,18 @@ class phpbb_template $output_file = $this->_compiled_file_for_handle($handle); if ($compile->compile_file_to_file($source_file, $output_file) !== false) { - $executor = new phpbb_template_executor_include($output_file, $this); + $renderer = new phpbb_template_renderer_include($output_file, $this); } else if (($code = $compile->compile_file($source_file)) !== false) { - $executor = new phpbb_template_executor_eval($code, $this); + $renderer = new phpbb_template_renderer_eval($code, $this); } else { - $executor = null; + $renderer = null; } - return $executor; + return $renderer; } /** @@ -489,11 +489,11 @@ class phpbb_template $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename; } - $executor = $this->_tpl_load($handle); + $renderer = $this->_tpl_load($handle); - if ($executor) + if ($renderer) { - $executor->execute($this->_context, $this->get_lang()); + $renderer->render($this->_context, $this->get_lang()); } else { diff --git a/phpBB/includes/template_executor.php b/phpBB/includes/template_executor.php deleted file mode 100644 index 0d410679b9..0000000000 --- a/phpBB/includes/template_executor.php +++ /dev/null @@ -1,35 +0,0 @@ -code = $code; - $this->template = $template; - } - - /** - * Executes the template managed by this executor by eval'ing php code - * of the template. - * @param phpbb_template_context $context Template context to use - * @param array $lang Language entries to use - */ - public function execute($context, $lang) - { - $_template = &$this->template; - $_tpldata = &$context->get_data_ref(); - $_rootref = &$context->get_root_ref(); - $_lang = &$lang; - - eval($this->code); - } -} diff --git a/phpBB/includes/template_executor_include.php b/phpBB/includes/template_executor_include.php deleted file mode 100644 index aacabc61e4..0000000000 --- a/phpBB/includes/template_executor_include.php +++ /dev/null @@ -1,60 +0,0 @@ -path = $path; - $this->template = $template; - } - - /** - * Executes the template managed by this executor by including - * the php file containing the template. - * @param phpbb_template_context $context Template context to use - * @param array $lang Language entries to use - */ - public function execute($context, $lang) - { - $_template = &$this->template; - $_tpldata = &$context->get_data_ref(); - $_rootref = &$context->get_root_ref(); - $_lang = &$lang; - - include($this->path); - } -} diff --git a/phpBB/includes/template_renderer.php b/phpBB/includes/template_renderer.php new file mode 100644 index 0000000000..0af2d94bb6 --- /dev/null +++ b/phpBB/includes/template_renderer.php @@ -0,0 +1,35 @@ +code = $code; + $this->template = $template; + } + + /** + * Displays the template managed by this renderer by eval'ing php code + * of the template. + * @param phpbb_template_context $context Template context to use + * @param array $lang Language entries to use + */ + public function render($context, $lang) + { + $_template = &$this->template; + $_tpldata = &$context->get_data_ref(); + $_rootref = &$context->get_root_ref(); + $_lang = &$lang; + + eval($this->code); + } +} diff --git a/phpBB/includes/template_renderer_include.php b/phpBB/includes/template_renderer_include.php new file mode 100644 index 0000000000..aca3a3634d --- /dev/null +++ b/phpBB/includes/template_renderer_include.php @@ -0,0 +1,60 @@ +path = $path; + $this->template = $template; + } + + /** + * Displays the template managed by this renderer by including + * the php file containing the template. + * @param phpbb_template_context $context Template context to use + * @param array $lang Language entries to use + */ + public function render($context, $lang) + { + $_template = &$this->template; + $_tpldata = &$context->get_data_ref(); + $_rootref = &$context->get_root_ref(); + $_lang = &$lang; + + include($this->path); + } +} -- cgit v1.2.1 From 49cf28a9c43060d2a4c4d5fe882fc3c7dedd7d0b Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 8 May 2011 04:05:09 -0400 Subject: [feature/template-engine] Moved template classes to subdirectory. PHPBB3-9726 --- phpBB/includes/template/compile.php | 941 +++++++++++++++++++++++++++ phpBB/includes/template/context.php | 320 +++++++++ phpBB/includes/template/renderer.php | 35 + phpBB/includes/template/renderer_eval.php | 60 ++ phpBB/includes/template/renderer_include.php | 60 ++ phpBB/includes/template_compile.php | 941 --------------------------- phpBB/includes/template_context.php | 320 --------- phpBB/includes/template_renderer.php | 35 - phpBB/includes/template_renderer_eval.php | 60 -- phpBB/includes/template_renderer_include.php | 60 -- 10 files changed, 1416 insertions(+), 1416 deletions(-) create mode 100644 phpBB/includes/template/compile.php create mode 100644 phpBB/includes/template/context.php create mode 100644 phpBB/includes/template/renderer.php create mode 100644 phpBB/includes/template/renderer_eval.php create mode 100644 phpBB/includes/template/renderer_include.php delete mode 100644 phpBB/includes/template_compile.php delete mode 100644 phpBB/includes/template_context.php delete mode 100644 phpBB/includes/template_renderer.php delete mode 100644 phpBB/includes/template_renderer_eval.php delete mode 100644 phpBB/includes/template_renderer_include.php (limited to 'phpBB/includes') diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php new file mode 100644 index 0000000000..4132fb2e34 --- /dev/null +++ b/phpBB/includes/template/compile.php @@ -0,0 +1,941 @@ +'; + + const REGEX_TOKENS = '~|{((?:[a-z_][a-z_0-9]+\.)*\\$?[A-Z][A-Z_0-9]+)}~'; + + /** + * @var array + */ + private $block_names = array(); + + /** + * @var array + */ + private $block_else_level = array(); + + /** + * @var string + */ + private $chunk; + + /** + * @var bool + */ + private $in_php; + + public function filter($in, $out, &$consumed, $closing) + { + $written = false; + + while ($bucket = stream_bucket_make_writeable($in)) + { + $consumed += $bucket->datalen; + + $data = $this->chunk . $bucket->data; + $last_nl = strrpos($data, "\n"); + $this->chunk = substr($data, $last_nl); + $data = substr($data, 0, $last_nl); + + if (!strlen($data)) + { + continue; + } + + $written = true; + + $bucket->data = $this->compile($data); + $bucket->datalen = strlen($bucket->data); + stream_bucket_append($out, $bucket); + } + + if ($closing && strlen($this->chunk)) + { + $written = true; + $bucket = stream_bucket_new($this->stream, $this->compile($this->chunk)); + stream_bucket_append($out, $bucket); + } + + return $written ? PSFS_PASS_ON : PSFS_FEED_ME; + } + + public function onCreate() + { + $this->chunk = ''; + $this->in_php = false; + return true; + } + + private function compile($data) + { + $block_start_in_php = $this->in_php; + + $data = preg_replace('#<(?:[\\?%]|script)#s', '', $data); + $data = preg_replace_callback(self::REGEX_TOKENS, array($this, 'replace'), $data); + + global $config; + + // Remove php + if (!$config['tpl_allow_php']) + { + if ($block_start_in_php + && $this->in_php + && strpos($data, '') === false + && strpos($data, '') === false) + { + // This is just php code + return ''; + } + $data = preg_replace('~^.*?~', '', $data); + $data = preg_replace('~.*?~', '', $data); + $data = preg_replace('~.*?$~', '', $data); + } + + /* + Preserve whitespace. + PHP removes a newline after the closing tag (if it's there). This is by design. + + + Consider the following template: + + + some content + + + If we were to simply preserve all whitespace, we could simply replace all "?>" tags + with "?>\n". + Doing that, would add additional newlines to the compiled tempalte in place of the + IF and ENDIF statements. These newlines are unwanted (and one is conditional). + The IF and ENDIF are usually on their own line for ease of reading. + + This replacement preserves newlines only for statements that aren't the only statement on a line. + It will NOT preserve newlines at the end of statements in the above examle. + It will preserve newlines in situations like: + + inline content + + + */ + + $data = preg_replace('~(?).)+(?)$~m', "$1\n", $data); + $data = str_replace('/**/?>', "?>\n", $data); + $data = str_replace('?>in_php && $matches[1] != 'ENDPHP') + { + return ''; + } + + if (isset($matches[3])) + { + return $this->compile_var_tags($matches[0]); + } + + global $config; + + switch ($matches[1]) + { + case 'BEGIN': + $this->block_else_level[] = false; + return 'compile_tag_block($matches[2]) . ' ?>'; + break; + + case 'BEGINELSE': + $this->block_else_level[sizeof($this->block_else_level) - 1] = true; + return ''; + break; + + case 'END': + array_pop($this->block_names); + return 'block_else_level)) ? '}' : '}}') . ' ?>'; + break; + + case 'IF': + return 'compile_tag_if($matches[2], false) . ' ?>'; + break; + + case 'ELSE': + return ''; + break; + + case 'ELSEIF': + return 'compile_tag_if($matches[2], true) . ' ?>'; + break; + + case 'ENDIF': + return ''; + break; + + case 'DEFINE': + return 'compile_tag_define($matches[2], true) . ' ?>'; + break; + + case 'UNDEFINE': + return 'compile_tag_define($matches[2], false) . ' ?>'; + break; + + case 'INCLUDE': + return 'compile_tag_include($matches[2]) . ' ?>'; + break; + + case 'INCLUDEPHP': + return ($config['tpl_allow_php']) ? 'compile_tag_include_php($matches[2]) . ' ?>' : ''; + break; + + case 'PHP': + if ($config['tpl_allow_php']) + { + $this->in_php = true; + return ''; + break; + + case 'ENDPHP': + if ($config['tpl_allow_php']) + { + $this->in_php = false; + return ' ?>'; + } + return ''; + break; + + default: + return $matches[0]; + break; + + } + return ''; + } + + /** + * Compile variables + * @access private + */ + private function compile_var_tags(&$text_blocks) + { + // change template varrefs into PHP varrefs + $varrefs = array(); + + // This one will handle varrefs WITH namespaces + preg_match_all('#\{((?:' . self::REGEX_NS . '\.)+)(\$)?(' . self::REGEX_VAR . ')\}#', $text_blocks, $varrefs, PREG_SET_ORDER); + + foreach ($varrefs as $var_val) + { + $namespace = $var_val[1]; + $varname = $var_val[3]; + $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]); + + $text_blocks = str_replace($var_val[0], $new, $text_blocks); + } + + // Handle special language tags L_ and LA_ + $this->compile_language_tags($text_blocks); + + // This will handle the remaining root-level varrefs + $text_blocks = preg_replace('#\{(' . self::REGEX_VAR . ')\}#', "", $text_blocks); + $text_blocks = preg_replace('#\{\$(' . self::REGEX_VAR . ')\}#', "", $text_blocks); + + return $text_blocks; + } + + /** + * Handles special language tags L_ and LA_ + */ + private function compile_language_tags(&$text_blocks) + { + // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array + if (strpos($text_blocks, '{L_') !== false) + { + $text_blocks = preg_replace('#\{L_(' . self::REGEX_VAR . ')\}#', "", $text_blocks); + } + + // Handle addslashed language variables prefixed with LA_ + // If a template variable already exist, it will be used in favor of it... + if (strpos($text_blocks, '{LA_') !== false) + { + $text_blocks = preg_replace('#\{LA_(' . self::REGEX_VAR . '+)\}#', "", $text_blocks); + } + } + + /** + * Compile blocks + * @access private + */ + private function compile_tag_block($tag_args) + { + $no_nesting = false; + + // Is the designer wanting to call another loop in a loop? + // + // + // + // + // 'loop2' is actually on the same nesting level as 'loop' you assign + // variables to it with template->assign_block_vars('loop2', array(...)) + if (strpos($tag_args, '!') === 0) + { + // Count the number if ! occurrences (not allowed in vars) + $no_nesting = substr_count($tag_args, '!'); + $tag_args = substr($tag_args, $no_nesting); + } + + // Allow for control of looping (indexes start from zero): + // foo(2) : Will start the loop on the 3rd entry + // foo(-2) : Will start the loop two entries from the end + // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth + // foo(3,-4) : Will start the loop on the fourth entry and end it four from last + $match = array(); + + if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match)) + { + $tag_args = $match[1]; + + if ($match[2] < 0) + { + $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')'; + } + else + { + $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')'; + } + + if (!isset($match[3]) || strlen($match[3]) < 1 || $match[3] == -1) + { + $loop_end = '$_' . $tag_args . '_count'; + } + else if ($match[3] >= 0) + { + $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')'; + } + else //if ($match[3] < -1) + { + $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1); + } + } + else + { + $loop_start = 0; + $loop_end = '$_' . $tag_args . '_count'; + } + + $tag_template_php = ''; + array_push($this->block_names, $tag_args); + + if ($no_nesting !== false) + { + // We need to implode $no_nesting times from the end... + $block = array_slice($this->block_names, -$no_nesting); + } + else + { + $block = $this->block_names; + } + + if (sizeof($block) < 2) + { + // Block is not nested. + $tag_template_php = '$_' . $tag_args . "_count = (isset(\$_tpldata['$tag_args'])) ? sizeof(\$_tpldata['$tag_args']) : 0;"; + $varref = "\$_tpldata['$tag_args']"; + } + else + { + // This block is nested. + // Generate a namespace string for this block. + $namespace = implode('.', $block); + + // Get a reference to the data array for this block that depends on the + // current indices of all parent blocks. + $varref = $this->generate_block_data_ref($namespace, false); + + // Create the for loop code to iterate over this block. + $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;'; + } + + $tag_template_php .= 'if ($_' . $tag_args . '_count) {'; + + /** + * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory + * + * if (!$offset) + * { + * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){'; + * } + * + */ + + $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){'; + $tag_template_php .= '$_' . $tag_args . '_val = &' . $varref . '[$_' . $tag_args . '_i];'; + + return $tag_template_php; + } + + /** + * Compile a general expression - much of this is from Smarty with + * some adaptions for our block level methods + * @access private + */ + private function compile_expression($tag_args) + { + $match = array(); + preg_match_all('/(?: + "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | + \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | + [(),] | + [^\s(),]+)/x', $tag_args, $match); + + $tokens = $match[0]; + $is_arg_stack = array(); + + for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) + { + $token = &$tokens[$i]; + + switch ($token) + { + case '!==': + case '===': + case '<<': + case '>>': + case '|': + case '^': + case '&': + case '~': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '@': + break; + + case '==': + case 'eq': + $token = '=='; + break; + + case '!=': + case '<>': + case 'ne': + case 'neq': + $token = '!='; + break; + + case '<': + case 'lt': + $token = '<'; + break; + + case '<=': + case 'le': + case 'lte': + $token = '<='; + break; + + case '>': + case 'gt': + $token = '>'; + break; + + case '>=': + case 'ge': + case 'gte': + $token = '>='; + break; + + case '&&': + case 'and': + $token = '&&'; + break; + + case '||': + case 'or': + $token = '||'; + break; + + case '!': + case 'not': + $token = '!'; + break; + + case '%': + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; + $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens); + + $i = $is_arg_start; + + // no break + + default: + $varrefs = array(); + if (preg_match('#^((?:' . self::REGEX_NS . '\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs)) + { + if (!empty($varrefs[1])) + { + $namespace = substr($varrefs[1], 0, -1); + $dot_pos = strrchr($namespace, '.'); + if ($dot_pos !== false) + { + $namespace = substr($dot_pos, 1); + } + + // S_ROW_COUNT is deceptive, it returns the current row number not the number of rows + // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM + switch ($varrefs[3]) + { + case 'S_ROW_NUM': + case 'S_ROW_COUNT': + $token = "\$_${namespace}_i"; + break; + + case 'S_NUM_ROWS': + $token = "\$_${namespace}_count"; + break; + + case 'S_FIRST_ROW': + $token = "(\$_${namespace}_i == 0)"; + break; + + case 'S_LAST_ROW': + $token = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; + break; + + case 'S_BLOCK_NAME': + $token = "'$namespace'"; + break; + + default: + $token = $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']'; + $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; + break; + } + } + else + { + $token = ($varrefs[2]) ? '$_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$_rootref[\'' . $varrefs[3] . '\']'; + $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; + } + + } + else if (preg_match('#^\.((?:' . self::REGEX_NS . '\.?)+)$#s', $token, $varrefs)) + { + // Allow checking if loops are set with .loopname + // It is also possible to check the loop count by doing for example + $blocks = explode('.', $varrefs[1]); + + // If the block is nested, we have a reference that we can grab. + // If the block is not nested, we just go and grab the block from _tpldata + if (sizeof($blocks) > 1) + { + $block = array_pop($blocks); + $namespace = implode('.', $blocks); + $varref = $this->generate_block_data_ref($namespace, true); + + // Add the block reference for the last child. + $varref .= "['" . $block . "']"; + } + else + { + $varref = '$_tpldata'; + + // Add the block reference for the last child. + $varref .= "['" . $blocks[0] . "']"; + } + $token = "(isset($varref) ? sizeof($varref) : 0)"; + } + + break; + } + } + + return $tokens; + } + + + private function compile_tag_if($tag_args, $elseif) + { + $tokens = $this->compile_expression($tag_args); + + $tpl = ($elseif) ? '} else if (' : 'if ('; + + $tpl .= implode(' ', $tokens); + $tpl .= ') { '; + + return $tpl; + } + + /** + * Compile DEFINE tags + * @access private + */ + private function compile_tag_define($tag_args, $op) + { + $match = array(); + preg_match('#^((?:' . self::REGEX_NS . '\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (.*?))?$#', $tag_args, $match); + + if (empty($match[2]) || (!isset($match[3]) && $op)) + { + return ''; + } + + if (!$op) + { + return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');'; + } + + $parsed_statement = implode(' ', $this->compile_expression($match[3])); + + return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $parsed_statement . ';'; + } + + /** + * Compile INCLUDE tag + * @access private + */ + private function compile_tag_include($tag_args) + { + return "\$_template->_tpl_include('$tag_args');"; + } + + /** + * Compile INCLUDE_PHP tag + * @access private + */ + private function compile_tag_include_php($tag_args) + { + return "include('$tag_args');"; + } + + /** + * parse expression + * This is from Smarty + * @access private + */ + private function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') + { + $negate_expr = true; + $expr_type = array_shift($tokens); + } + else + { + $expr_type = $first_token; + } + + switch ($expr_type) + { + case 'even': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(($is_arg / $expr_arg) & 1)"; + } + else + { + $expr = "!($is_arg & 1)"; + } + break; + + case 'odd': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(($is_arg / $expr_arg) & 1)"; + } + else + { + $expr = "($is_arg & 1)"; + } + break; + + case 'div': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % $expr_arg)"; + } + break; + } + + if ($negate_expr) + { + if ($expr[0] == '!') + { + // Negated expression, de-negate it. + $expr = substr($expr, 1); + } + else + { + $expr = "!($expr)"; + } + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + /** + * Generates a reference to the given variable inside the given (possibly nested) + * block namespace. This is a string of the form: + * ' . $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' + * It's ready to be inserted into an "echo" line in one of the templates. + * + * @access private + * @param string $namespace Namespace to access (expects a trailing "." on the namespace) + * @param string $varname Variable name to use + * @param bool $echo If true return an echo statement, otherwise a reference to the internal variable + * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable + * @return string Code to access variable or echo it if $echo is true + */ + private function generate_block_varref($namespace, $varname, $echo = true, $defop = false) + { + // Strip the trailing period. + $namespace = substr($namespace, 0, -1); + + $expr = true; + $isset = false; + + // S_ROW_COUNT is deceptive, it returns the current row number now the number of rows + // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM + switch ($varname) + { + case 'S_ROW_NUM': + case 'S_ROW_COUNT': + $varref = "\$_${namespace}_i"; + break; + + case 'S_NUM_ROWS': + $varref = "\$_${namespace}_count"; + break; + + case 'S_FIRST_ROW': + $varref = "(\$_${namespace}_i == 0)"; + break; + + case 'S_LAST_ROW': + $varref = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; + break; + + case 'S_BLOCK_NAME': + $varref = "'$namespace'"; + break; + + default: + // Get a reference to the data block for this namespace. + $varref = $this->generate_block_data_ref($namespace, true, $defop); + // Prepend the necessary code to stick this in an echo line. + + // Append the variable reference. + $varref .= "['$varname']"; + + $expr = false; + $isset = true; + break; + } + // @todo Test the !$expr more + $varref = ($echo) ? '' : (($expr || isset($varref)) ? $varref : ''); + + return $varref; + } + + /** + * Generates a reference to the array of data values for the given + * (possibly nested) block namespace. This is a string of the form: + * $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] + * + * @access private + * @param string $blockname Block to access (does not expect a trailing "." on the blockname) + * @param bool $include_last_iterator If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. + * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable + * @return string Code to access variable + */ + private function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) + { + // Get an array of the blocks involved. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + // DEFINE is not an element of any referenced variable, we must use _tpldata to access it + if ($defop) + { + $varref = '$_tpldata[\'DEFINE\']'; + // Build up the string with everything but the last child. + for ($i = 0; $i < $blockcount; $i++) + { + $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]'; + } + // Add the block reference for the last child. + $varref .= "['" . $blocks[$blockcount] . "']"; + // Add the iterator for the last child if requried. + if ($include_last_iterator) + { + $varref .= '[$_' . $blocks[$blockcount] . '_i]'; + } + return $varref; + } + else if ($include_last_iterator) + { + return '$_'. $blocks[$blockcount] . '_val'; + } + else + { + return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']'; + } + } +} + +stream_filter_register('phpbb_template', 'phpbb_template_filter'); + +/** +* Extension of template class - Functions needed for compiling templates only. +* +* psoTFX, phpBB Development Team - Completion of file caching, decompilation +* routines and implementation of conditionals/keywords and associated changes +* +* The interface was inspired by PHPLib templates, and the template file (formats are +* quite similar) +* +* The keyword/conditional implementation is currently based on sections of code from +* the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released +* (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code +* derived from an LGPL application may be relicenced under the GPL, this applies +* to this source +* +* DEFINE directive inspired by a request by Cyberalien +* +* @package phpBB3 +* @uses template_filter As a PHP stream filter to perform compilation of templates +*/ +class phpbb_template_compile +{ + /** + * Compiles template in $source_file and writes compiled template to + * cache directory + * @access public + * @param string $handle Template handle to compile + * @param string $source_file Source template file + * @return bool Return true on success otherwise false + */ + public function compile_file_to_file($source_file, $compiled_file) + { + $source_handle = @fopen($source_file, 'rb'); + $destination_handle = @fopen($compiled_file, 'wb'); + + if (!$source_handle || !$destination_handle) + { + 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); + + clearstatcache(); + + return true; + } + + /** + * Compiles a template located at $source_file. + * Returns PHP source suitable for eval(). + * @access public + * @param string $source_file Source template file + * @return string|bool Return compiled code on successful compilation otherwise false + */ + public function compile_file($source_file) + { + $source_handle = @fopen($source_file, 'rb'); + $destination_handle = @fopen('php://temp' ,'r+b'); + + if (!$source_handle || !$destination_handle) + { + return false; + } + + $this->compile_stream_to_stream($source_handle, $destination_handle); + + @fclose($source_handle); + + rewind($destination_handle); + $contents = stream_get_contents($destination_handle); + @fclose($dest_handle); + + return $contents; + } + + /** + * Compiles contents of $source_stream into $dest_stream. + * + * A stream filter is appended to $source_stream as part of the + * process. + * + * @access private + * @param resource $source_stream Source stream + * @param resource $dest_stream Destination stream + * @return void + */ + private function compile_stream_to_stream($source_stream, $dest_stream) + { + stream_filter_append($source_stream, 'phpbb_template'); + stream_copy_to_stream($source_stream, $dest_stream); + } +} diff --git a/phpBB/includes/template/context.php b/phpBB/includes/template/context.php new file mode 100644 index 0000000000..df5c4afb24 --- /dev/null +++ b/phpBB/includes/template/context.php @@ -0,0 +1,320 @@ + $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value + * if it's a root-level variable, it'll be like this: + * --> $this->_tpldata[.][0][varname] == value + * @var array + */ + private $_tpldata = array('.' => array(0 => array())); + + /** + * @var array Reference to template->_tpldata['.'][0] + */ + private $_rootref; + + public function __construct() + { + $this->clear(); + } + + /** + * Clears template data set. + * @access public + */ + public function clear() + { + $this->_tpldata = array('.' => array(0 => array())); + $this->_rootref = &$this->_tpldata['.'][0]; + } + + /** + * Assign a single variable to a single key + * @access public + * @param string $varname Variable name + * @param string $varval Value to assign to variable + */ + public function assign_var($varname, $varval) + { + $this->_rootref[$varname] = $varval; + + return true; + } + + public function get_data_ref() + { + return $this->_tpldata; + } + + public function get_root_ref() + { + return $this->_rootref; + } + + /** + * Assign key variable pairs from an array to a specified block + * @access public + * @param string $blockname Name of block to assign $vararray to + * @param array $vararray A hash of variable name => value pairs + */ + public function assign_block_vars($blockname, array $vararray) + { + if (strpos($blockname, '.') !== false) + { + // Nested block. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $str = &$this->_tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + $str = &$str[$blocks[$i]]; + $str = &$str[sizeof($str) - 1]; + } + + $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0; + $vararray['S_ROW_COUNT'] = $s_row_count; + + // Assign S_FIRST_ROW + if (!$s_row_count) + { + $vararray['S_FIRST_ROW'] = true; + } + + // Now the tricky part, we always assign S_LAST_ROW and remove the entry before + // This is much more clever than going through the complete template data on display (phew) + $vararray['S_LAST_ROW'] = true; + if ($s_row_count > 0) + { + unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']); + } + + // Now we add the block that we're actually assigning to. + // We're adding a new iteration to this block with the given + // variable assignments. + $str[$blocks[$blockcount]][] = $vararray; + } + else + { + // Top-level block. + $s_row_count = (isset($this->_tpldata[$blockname])) ? sizeof($this->_tpldata[$blockname]) : 0; + $vararray['S_ROW_COUNT'] = $s_row_count; + + // Assign S_FIRST_ROW + if (!$s_row_count) + { + $vararray['S_FIRST_ROW'] = true; + } + + // We always assign S_LAST_ROW and remove the entry before + $vararray['S_LAST_ROW'] = true; + if ($s_row_count > 0) + { + unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']); + } + + // Add a new iteration to this block with the variable assignments we were given. + $this->_tpldata[$blockname][] = $vararray; + } + + return true; + } + + /** + * Change already assigned key variable pair (one-dimensional - single loop entry) + * + * An example of how to use this function: + * {@example alter_block_array.php} + * + * @param string $blockname the blockname, for example 'loop' + * @param array $vararray the var array to insert/add or merge + * @param mixed $key Key to search for + * + * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] + * + * int: Position [the position to change or insert at directly given] + * + * If key is false the position is set to 0 + * If key is true the position is set to the last entry + * + * @param string $mode Mode to execute (valid modes are 'insert' and 'change') + * + * If insert, the vararray is inserted at the given position (position counting from zero). + * If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new value). + * + * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array) + * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars) + * + * @return bool false on error, true on success + * @access public + */ + public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') + { + if (strpos($blockname, '.') !== false) + { + // Nested block. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $block = &$this->_tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + if (($pos = strpos($blocks[$i], '[')) !== false) + { + $name = substr($blocks[$i], 0, $pos); + + if (strpos($blocks[$i], '[]') === $pos) + { + $index = sizeof($block[$name]) - 1; + } + else + { + $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1); + } + } + else + { + $name = $blocks[$i]; + $index = sizeof($block[$name]) - 1; + } + $block = &$block[$name]; + $block = &$block[$index]; + } + + $block = &$block[$blocks[$i]]; // Traverse the last block + } + else + { + // Top-level block. + $block = &$this->_tpldata[$blockname]; + } + + // Change key to zero (change first position) if false and to last position if true + if ($key === false || $key === true) + { + $key = ($key === false) ? 0 : sizeof($block); + } + + // Get correct position if array given + if (is_array($key)) + { + // Search array to get correct position + list($search_key, $search_value) = @each($key); + + $key = NULL; + foreach ($block as $i => $val_ary) + { + if ($val_ary[$search_key] === $search_value) + { + $key = $i; + break; + } + } + + // key/value pair not found + if ($key === NULL) + { + return false; + } + } + + // Insert Block + if ($mode == 'insert') + { + // Make sure we are not exceeding the last iteration + if ($key >= sizeof($this->_tpldata[$blockname])) + { + $key = sizeof($this->_tpldata[$blockname]); + unset($this->_tpldata[$blockname][($key - 1)]['S_LAST_ROW']); + $vararray['S_LAST_ROW'] = true; + } + else if ($key === 0) + { + unset($this->_tpldata[$blockname][0]['S_FIRST_ROW']); + $vararray['S_FIRST_ROW'] = true; + } + + // Re-position template blocks + for ($i = sizeof($block); $i > $key; $i--) + { + $block[$i] = $block[$i-1]; + } + + // Insert vararray at given position + $block[$key] = $vararray; + + return true; + } + + // Which block to change? + if ($mode == 'change') + { + if ($key == sizeof($block)) + { + $key--; + } + + $block[$key] = array_merge($block[$key], $vararray); + + return true; + } + + return false; + } + + /** + * Reset/empty complete block + * @access public + * @param string $blockname Name of block to destroy + */ + public function destroy_block_vars($blockname) + { + if (strpos($blockname, '.') !== false) + { + // Nested block. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $str = &$this->_tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + $str = &$str[$blocks[$i]]; + $str = &$str[sizeof($str) - 1]; + } + + unset($str[$blocks[$blockcount]]); + } + else + { + // Top-level block. + unset($this->_tpldata[$blockname]); + } + + return true; + } +} diff --git a/phpBB/includes/template/renderer.php b/phpBB/includes/template/renderer.php new file mode 100644 index 0000000000..0af2d94bb6 --- /dev/null +++ b/phpBB/includes/template/renderer.php @@ -0,0 +1,35 @@ +code = $code; + $this->template = $template; + } + + /** + * Displays the template managed by this renderer by eval'ing php code + * of the template. + * @param phpbb_template_context $context Template context to use + * @param array $lang Language entries to use + */ + public function render($context, $lang) + { + $_template = &$this->template; + $_tpldata = &$context->get_data_ref(); + $_rootref = &$context->get_root_ref(); + $_lang = &$lang; + + eval($this->code); + } +} diff --git a/phpBB/includes/template/renderer_include.php b/phpBB/includes/template/renderer_include.php new file mode 100644 index 0000000000..aca3a3634d --- /dev/null +++ b/phpBB/includes/template/renderer_include.php @@ -0,0 +1,60 @@ +path = $path; + $this->template = $template; + } + + /** + * Displays the template managed by this renderer by including + * the php file containing the template. + * @param phpbb_template_context $context Template context to use + * @param array $lang Language entries to use + */ + public function render($context, $lang) + { + $_template = &$this->template; + $_tpldata = &$context->get_data_ref(); + $_rootref = &$context->get_root_ref(); + $_lang = &$lang; + + include($this->path); + } +} diff --git a/phpBB/includes/template_compile.php b/phpBB/includes/template_compile.php deleted file mode 100644 index 4132fb2e34..0000000000 --- a/phpBB/includes/template_compile.php +++ /dev/null @@ -1,941 +0,0 @@ -'; - - const REGEX_TOKENS = '~|{((?:[a-z_][a-z_0-9]+\.)*\\$?[A-Z][A-Z_0-9]+)}~'; - - /** - * @var array - */ - private $block_names = array(); - - /** - * @var array - */ - private $block_else_level = array(); - - /** - * @var string - */ - private $chunk; - - /** - * @var bool - */ - private $in_php; - - public function filter($in, $out, &$consumed, $closing) - { - $written = false; - - while ($bucket = stream_bucket_make_writeable($in)) - { - $consumed += $bucket->datalen; - - $data = $this->chunk . $bucket->data; - $last_nl = strrpos($data, "\n"); - $this->chunk = substr($data, $last_nl); - $data = substr($data, 0, $last_nl); - - if (!strlen($data)) - { - continue; - } - - $written = true; - - $bucket->data = $this->compile($data); - $bucket->datalen = strlen($bucket->data); - stream_bucket_append($out, $bucket); - } - - if ($closing && strlen($this->chunk)) - { - $written = true; - $bucket = stream_bucket_new($this->stream, $this->compile($this->chunk)); - stream_bucket_append($out, $bucket); - } - - return $written ? PSFS_PASS_ON : PSFS_FEED_ME; - } - - public function onCreate() - { - $this->chunk = ''; - $this->in_php = false; - return true; - } - - private function compile($data) - { - $block_start_in_php = $this->in_php; - - $data = preg_replace('#<(?:[\\?%]|script)#s', '', $data); - $data = preg_replace_callback(self::REGEX_TOKENS, array($this, 'replace'), $data); - - global $config; - - // Remove php - if (!$config['tpl_allow_php']) - { - if ($block_start_in_php - && $this->in_php - && strpos($data, '') === false - && strpos($data, '') === false) - { - // This is just php code - return ''; - } - $data = preg_replace('~^.*?~', '', $data); - $data = preg_replace('~.*?~', '', $data); - $data = preg_replace('~.*?$~', '', $data); - } - - /* - Preserve whitespace. - PHP removes a newline after the closing tag (if it's there). This is by design. - - - Consider the following template: - - - some content - - - If we were to simply preserve all whitespace, we could simply replace all "?>" tags - with "?>\n". - Doing that, would add additional newlines to the compiled tempalte in place of the - IF and ENDIF statements. These newlines are unwanted (and one is conditional). - The IF and ENDIF are usually on their own line for ease of reading. - - This replacement preserves newlines only for statements that aren't the only statement on a line. - It will NOT preserve newlines at the end of statements in the above examle. - It will preserve newlines in situations like: - - inline content - - - */ - - $data = preg_replace('~(?).)+(?)$~m', "$1\n", $data); - $data = str_replace('/**/?>', "?>\n", $data); - $data = str_replace('?>in_php && $matches[1] != 'ENDPHP') - { - return ''; - } - - if (isset($matches[3])) - { - return $this->compile_var_tags($matches[0]); - } - - global $config; - - switch ($matches[1]) - { - case 'BEGIN': - $this->block_else_level[] = false; - return 'compile_tag_block($matches[2]) . ' ?>'; - break; - - case 'BEGINELSE': - $this->block_else_level[sizeof($this->block_else_level) - 1] = true; - return ''; - break; - - case 'END': - array_pop($this->block_names); - return 'block_else_level)) ? '}' : '}}') . ' ?>'; - break; - - case 'IF': - return 'compile_tag_if($matches[2], false) . ' ?>'; - break; - - case 'ELSE': - return ''; - break; - - case 'ELSEIF': - return 'compile_tag_if($matches[2], true) . ' ?>'; - break; - - case 'ENDIF': - return ''; - break; - - case 'DEFINE': - return 'compile_tag_define($matches[2], true) . ' ?>'; - break; - - case 'UNDEFINE': - return 'compile_tag_define($matches[2], false) . ' ?>'; - break; - - case 'INCLUDE': - return 'compile_tag_include($matches[2]) . ' ?>'; - break; - - case 'INCLUDEPHP': - return ($config['tpl_allow_php']) ? 'compile_tag_include_php($matches[2]) . ' ?>' : ''; - break; - - case 'PHP': - if ($config['tpl_allow_php']) - { - $this->in_php = true; - return ''; - break; - - case 'ENDPHP': - if ($config['tpl_allow_php']) - { - $this->in_php = false; - return ' ?>'; - } - return ''; - break; - - default: - return $matches[0]; - break; - - } - return ''; - } - - /** - * Compile variables - * @access private - */ - private function compile_var_tags(&$text_blocks) - { - // change template varrefs into PHP varrefs - $varrefs = array(); - - // This one will handle varrefs WITH namespaces - preg_match_all('#\{((?:' . self::REGEX_NS . '\.)+)(\$)?(' . self::REGEX_VAR . ')\}#', $text_blocks, $varrefs, PREG_SET_ORDER); - - foreach ($varrefs as $var_val) - { - $namespace = $var_val[1]; - $varname = $var_val[3]; - $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]); - - $text_blocks = str_replace($var_val[0], $new, $text_blocks); - } - - // Handle special language tags L_ and LA_ - $this->compile_language_tags($text_blocks); - - // This will handle the remaining root-level varrefs - $text_blocks = preg_replace('#\{(' . self::REGEX_VAR . ')\}#', "", $text_blocks); - $text_blocks = preg_replace('#\{\$(' . self::REGEX_VAR . ')\}#', "", $text_blocks); - - return $text_blocks; - } - - /** - * Handles special language tags L_ and LA_ - */ - private function compile_language_tags(&$text_blocks) - { - // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array - if (strpos($text_blocks, '{L_') !== false) - { - $text_blocks = preg_replace('#\{L_(' . self::REGEX_VAR . ')\}#', "", $text_blocks); - } - - // Handle addslashed language variables prefixed with LA_ - // If a template variable already exist, it will be used in favor of it... - if (strpos($text_blocks, '{LA_') !== false) - { - $text_blocks = preg_replace('#\{LA_(' . self::REGEX_VAR . '+)\}#', "", $text_blocks); - } - } - - /** - * Compile blocks - * @access private - */ - private function compile_tag_block($tag_args) - { - $no_nesting = false; - - // Is the designer wanting to call another loop in a loop? - // - // - // - // - // 'loop2' is actually on the same nesting level as 'loop' you assign - // variables to it with template->assign_block_vars('loop2', array(...)) - if (strpos($tag_args, '!') === 0) - { - // Count the number if ! occurrences (not allowed in vars) - $no_nesting = substr_count($tag_args, '!'); - $tag_args = substr($tag_args, $no_nesting); - } - - // Allow for control of looping (indexes start from zero): - // foo(2) : Will start the loop on the 3rd entry - // foo(-2) : Will start the loop two entries from the end - // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth - // foo(3,-4) : Will start the loop on the fourth entry and end it four from last - $match = array(); - - if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match)) - { - $tag_args = $match[1]; - - if ($match[2] < 0) - { - $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')'; - } - else - { - $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')'; - } - - if (!isset($match[3]) || strlen($match[3]) < 1 || $match[3] == -1) - { - $loop_end = '$_' . $tag_args . '_count'; - } - else if ($match[3] >= 0) - { - $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')'; - } - else //if ($match[3] < -1) - { - $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1); - } - } - else - { - $loop_start = 0; - $loop_end = '$_' . $tag_args . '_count'; - } - - $tag_template_php = ''; - array_push($this->block_names, $tag_args); - - if ($no_nesting !== false) - { - // We need to implode $no_nesting times from the end... - $block = array_slice($this->block_names, -$no_nesting); - } - else - { - $block = $this->block_names; - } - - if (sizeof($block) < 2) - { - // Block is not nested. - $tag_template_php = '$_' . $tag_args . "_count = (isset(\$_tpldata['$tag_args'])) ? sizeof(\$_tpldata['$tag_args']) : 0;"; - $varref = "\$_tpldata['$tag_args']"; - } - else - { - // This block is nested. - // Generate a namespace string for this block. - $namespace = implode('.', $block); - - // Get a reference to the data array for this block that depends on the - // current indices of all parent blocks. - $varref = $this->generate_block_data_ref($namespace, false); - - // Create the for loop code to iterate over this block. - $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;'; - } - - $tag_template_php .= 'if ($_' . $tag_args . '_count) {'; - - /** - * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory - * - * if (!$offset) - * { - * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){'; - * } - * - */ - - $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){'; - $tag_template_php .= '$_' . $tag_args . '_val = &' . $varref . '[$_' . $tag_args . '_i];'; - - return $tag_template_php; - } - - /** - * Compile a general expression - much of this is from Smarty with - * some adaptions for our block level methods - * @access private - */ - private function compile_expression($tag_args) - { - $match = array(); - preg_match_all('/(?: - "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | - \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | - [(),] | - [^\s(),]+)/x', $tag_args, $match); - - $tokens = $match[0]; - $is_arg_stack = array(); - - for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) - { - $token = &$tokens[$i]; - - switch ($token) - { - case '!==': - case '===': - case '<<': - case '>>': - case '|': - case '^': - case '&': - case '~': - case ')': - case ',': - case '+': - case '-': - case '*': - case '/': - case '@': - break; - - case '==': - case 'eq': - $token = '=='; - break; - - case '!=': - case '<>': - case 'ne': - case 'neq': - $token = '!='; - break; - - case '<': - case 'lt': - $token = '<'; - break; - - case '<=': - case 'le': - case 'lte': - $token = '<='; - break; - - case '>': - case 'gt': - $token = '>'; - break; - - case '>=': - case 'ge': - case 'gte': - $token = '>='; - break; - - case '&&': - case 'and': - $token = '&&'; - break; - - case '||': - case 'or': - $token = '||'; - break; - - case '!': - case 'not': - $token = '!'; - break; - - case '%': - case 'mod': - $token = '%'; - break; - - case '(': - array_push($is_arg_stack, $i); - break; - - case 'is': - $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; - $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); - - $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); - - array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens); - - $i = $is_arg_start; - - // no break - - default: - $varrefs = array(); - if (preg_match('#^((?:' . self::REGEX_NS . '\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs)) - { - if (!empty($varrefs[1])) - { - $namespace = substr($varrefs[1], 0, -1); - $dot_pos = strrchr($namespace, '.'); - if ($dot_pos !== false) - { - $namespace = substr($dot_pos, 1); - } - - // S_ROW_COUNT is deceptive, it returns the current row number not the number of rows - // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM - switch ($varrefs[3]) - { - case 'S_ROW_NUM': - case 'S_ROW_COUNT': - $token = "\$_${namespace}_i"; - break; - - case 'S_NUM_ROWS': - $token = "\$_${namespace}_count"; - break; - - case 'S_FIRST_ROW': - $token = "(\$_${namespace}_i == 0)"; - break; - - case 'S_LAST_ROW': - $token = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; - break; - - case 'S_BLOCK_NAME': - $token = "'$namespace'"; - break; - - default: - $token = $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']'; - $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; - break; - } - } - else - { - $token = ($varrefs[2]) ? '$_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$_rootref[\'' . $varrefs[3] . '\']'; - $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; - } - - } - else if (preg_match('#^\.((?:' . self::REGEX_NS . '\.?)+)$#s', $token, $varrefs)) - { - // Allow checking if loops are set with .loopname - // It is also possible to check the loop count by doing for example - $blocks = explode('.', $varrefs[1]); - - // If the block is nested, we have a reference that we can grab. - // If the block is not nested, we just go and grab the block from _tpldata - if (sizeof($blocks) > 1) - { - $block = array_pop($blocks); - $namespace = implode('.', $blocks); - $varref = $this->generate_block_data_ref($namespace, true); - - // Add the block reference for the last child. - $varref .= "['" . $block . "']"; - } - else - { - $varref = '$_tpldata'; - - // Add the block reference for the last child. - $varref .= "['" . $blocks[0] . "']"; - } - $token = "(isset($varref) ? sizeof($varref) : 0)"; - } - - break; - } - } - - return $tokens; - } - - - private function compile_tag_if($tag_args, $elseif) - { - $tokens = $this->compile_expression($tag_args); - - $tpl = ($elseif) ? '} else if (' : 'if ('; - - $tpl .= implode(' ', $tokens); - $tpl .= ') { '; - - return $tpl; - } - - /** - * Compile DEFINE tags - * @access private - */ - private function compile_tag_define($tag_args, $op) - { - $match = array(); - preg_match('#^((?:' . self::REGEX_NS . '\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (.*?))?$#', $tag_args, $match); - - if (empty($match[2]) || (!isset($match[3]) && $op)) - { - return ''; - } - - if (!$op) - { - return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');'; - } - - $parsed_statement = implode(' ', $this->compile_expression($match[3])); - - return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $parsed_statement . ';'; - } - - /** - * Compile INCLUDE tag - * @access private - */ - private function compile_tag_include($tag_args) - { - return "\$_template->_tpl_include('$tag_args');"; - } - - /** - * Compile INCLUDE_PHP tag - * @access private - */ - private function compile_tag_include_php($tag_args) - { - return "include('$tag_args');"; - } - - /** - * parse expression - * This is from Smarty - * @access private - */ - private function _parse_is_expr($is_arg, $tokens) - { - $expr_end = 0; - $negate_expr = false; - - if (($first_token = array_shift($tokens)) == 'not') - { - $negate_expr = true; - $expr_type = array_shift($tokens); - } - else - { - $expr_type = $first_token; - } - - switch ($expr_type) - { - case 'even': - if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!(($is_arg / $expr_arg) & 1)"; - } - else - { - $expr = "!($is_arg & 1)"; - } - break; - - case 'odd': - if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "(($is_arg / $expr_arg) & 1)"; - } - else - { - $expr = "($is_arg & 1)"; - } - break; - - case 'div': - if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!($is_arg % $expr_arg)"; - } - break; - } - - if ($negate_expr) - { - if ($expr[0] == '!') - { - // Negated expression, de-negate it. - $expr = substr($expr, 1); - } - else - { - $expr = "!($expr)"; - } - } - - array_splice($tokens, 0, $expr_end, $expr); - - return $tokens; - } - - /** - * Generates a reference to the given variable inside the given (possibly nested) - * block namespace. This is a string of the form: - * ' . $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' - * It's ready to be inserted into an "echo" line in one of the templates. - * - * @access private - * @param string $namespace Namespace to access (expects a trailing "." on the namespace) - * @param string $varname Variable name to use - * @param bool $echo If true return an echo statement, otherwise a reference to the internal variable - * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable - * @return string Code to access variable or echo it if $echo is true - */ - private function generate_block_varref($namespace, $varname, $echo = true, $defop = false) - { - // Strip the trailing period. - $namespace = substr($namespace, 0, -1); - - $expr = true; - $isset = false; - - // S_ROW_COUNT is deceptive, it returns the current row number now the number of rows - // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM - switch ($varname) - { - case 'S_ROW_NUM': - case 'S_ROW_COUNT': - $varref = "\$_${namespace}_i"; - break; - - case 'S_NUM_ROWS': - $varref = "\$_${namespace}_count"; - break; - - case 'S_FIRST_ROW': - $varref = "(\$_${namespace}_i == 0)"; - break; - - case 'S_LAST_ROW': - $varref = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; - break; - - case 'S_BLOCK_NAME': - $varref = "'$namespace'"; - break; - - default: - // Get a reference to the data block for this namespace. - $varref = $this->generate_block_data_ref($namespace, true, $defop); - // Prepend the necessary code to stick this in an echo line. - - // Append the variable reference. - $varref .= "['$varname']"; - - $expr = false; - $isset = true; - break; - } - // @todo Test the !$expr more - $varref = ($echo) ? '' : (($expr || isset($varref)) ? $varref : ''); - - return $varref; - } - - /** - * Generates a reference to the array of data values for the given - * (possibly nested) block namespace. This is a string of the form: - * $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] - * - * @access private - * @param string $blockname Block to access (does not expect a trailing "." on the blockname) - * @param bool $include_last_iterator If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. - * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable - * @return string Code to access variable - */ - private function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) - { - // Get an array of the blocks involved. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - // DEFINE is not an element of any referenced variable, we must use _tpldata to access it - if ($defop) - { - $varref = '$_tpldata[\'DEFINE\']'; - // Build up the string with everything but the last child. - for ($i = 0; $i < $blockcount; $i++) - { - $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]'; - } - // Add the block reference for the last child. - $varref .= "['" . $blocks[$blockcount] . "']"; - // Add the iterator for the last child if requried. - if ($include_last_iterator) - { - $varref .= '[$_' . $blocks[$blockcount] . '_i]'; - } - return $varref; - } - else if ($include_last_iterator) - { - return '$_'. $blocks[$blockcount] . '_val'; - } - else - { - return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']'; - } - } -} - -stream_filter_register('phpbb_template', 'phpbb_template_filter'); - -/** -* Extension of template class - Functions needed for compiling templates only. -* -* psoTFX, phpBB Development Team - Completion of file caching, decompilation -* routines and implementation of conditionals/keywords and associated changes -* -* The interface was inspired by PHPLib templates, and the template file (formats are -* quite similar) -* -* The keyword/conditional implementation is currently based on sections of code from -* the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released -* (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code -* derived from an LGPL application may be relicenced under the GPL, this applies -* to this source -* -* DEFINE directive inspired by a request by Cyberalien -* -* @package phpBB3 -* @uses template_filter As a PHP stream filter to perform compilation of templates -*/ -class phpbb_template_compile -{ - /** - * Compiles template in $source_file and writes compiled template to - * cache directory - * @access public - * @param string $handle Template handle to compile - * @param string $source_file Source template file - * @return bool Return true on success otherwise false - */ - public function compile_file_to_file($source_file, $compiled_file) - { - $source_handle = @fopen($source_file, 'rb'); - $destination_handle = @fopen($compiled_file, 'wb'); - - if (!$source_handle || !$destination_handle) - { - 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); - - clearstatcache(); - - return true; - } - - /** - * Compiles a template located at $source_file. - * Returns PHP source suitable for eval(). - * @access public - * @param string $source_file Source template file - * @return string|bool Return compiled code on successful compilation otherwise false - */ - public function compile_file($source_file) - { - $source_handle = @fopen($source_file, 'rb'); - $destination_handle = @fopen('php://temp' ,'r+b'); - - if (!$source_handle || !$destination_handle) - { - return false; - } - - $this->compile_stream_to_stream($source_handle, $destination_handle); - - @fclose($source_handle); - - rewind($destination_handle); - $contents = stream_get_contents($destination_handle); - @fclose($dest_handle); - - return $contents; - } - - /** - * Compiles contents of $source_stream into $dest_stream. - * - * A stream filter is appended to $source_stream as part of the - * process. - * - * @access private - * @param resource $source_stream Source stream - * @param resource $dest_stream Destination stream - * @return void - */ - private function compile_stream_to_stream($source_stream, $dest_stream) - { - stream_filter_append($source_stream, 'phpbb_template'); - stream_copy_to_stream($source_stream, $dest_stream); - } -} diff --git a/phpBB/includes/template_context.php b/phpBB/includes/template_context.php deleted file mode 100644 index df5c4afb24..0000000000 --- a/phpBB/includes/template_context.php +++ /dev/null @@ -1,320 +0,0 @@ - $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value - * if it's a root-level variable, it'll be like this: - * --> $this->_tpldata[.][0][varname] == value - * @var array - */ - private $_tpldata = array('.' => array(0 => array())); - - /** - * @var array Reference to template->_tpldata['.'][0] - */ - private $_rootref; - - public function __construct() - { - $this->clear(); - } - - /** - * Clears template data set. - * @access public - */ - public function clear() - { - $this->_tpldata = array('.' => array(0 => array())); - $this->_rootref = &$this->_tpldata['.'][0]; - } - - /** - * Assign a single variable to a single key - * @access public - * @param string $varname Variable name - * @param string $varval Value to assign to variable - */ - public function assign_var($varname, $varval) - { - $this->_rootref[$varname] = $varval; - - return true; - } - - public function get_data_ref() - { - return $this->_tpldata; - } - - public function get_root_ref() - { - return $this->_rootref; - } - - /** - * Assign key variable pairs from an array to a specified block - * @access public - * @param string $blockname Name of block to assign $vararray to - * @param array $vararray A hash of variable name => value pairs - */ - public function assign_block_vars($blockname, array $vararray) - { - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - $str = &$this->_tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - $str = &$str[$blocks[$i]]; - $str = &$str[sizeof($str) - 1]; - } - - $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0; - $vararray['S_ROW_COUNT'] = $s_row_count; - - // Assign S_FIRST_ROW - if (!$s_row_count) - { - $vararray['S_FIRST_ROW'] = true; - } - - // Now the tricky part, we always assign S_LAST_ROW and remove the entry before - // This is much more clever than going through the complete template data on display (phew) - $vararray['S_LAST_ROW'] = true; - if ($s_row_count > 0) - { - unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']); - } - - // Now we add the block that we're actually assigning to. - // We're adding a new iteration to this block with the given - // variable assignments. - $str[$blocks[$blockcount]][] = $vararray; - } - else - { - // Top-level block. - $s_row_count = (isset($this->_tpldata[$blockname])) ? sizeof($this->_tpldata[$blockname]) : 0; - $vararray['S_ROW_COUNT'] = $s_row_count; - - // Assign S_FIRST_ROW - if (!$s_row_count) - { - $vararray['S_FIRST_ROW'] = true; - } - - // We always assign S_LAST_ROW and remove the entry before - $vararray['S_LAST_ROW'] = true; - if ($s_row_count > 0) - { - unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']); - } - - // Add a new iteration to this block with the variable assignments we were given. - $this->_tpldata[$blockname][] = $vararray; - } - - return true; - } - - /** - * Change already assigned key variable pair (one-dimensional - single loop entry) - * - * An example of how to use this function: - * {@example alter_block_array.php} - * - * @param string $blockname the blockname, for example 'loop' - * @param array $vararray the var array to insert/add or merge - * @param mixed $key Key to search for - * - * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] - * - * int: Position [the position to change or insert at directly given] - * - * If key is false the position is set to 0 - * If key is true the position is set to the last entry - * - * @param string $mode Mode to execute (valid modes are 'insert' and 'change') - * - * If insert, the vararray is inserted at the given position (position counting from zero). - * If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new value). - * - * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array) - * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars) - * - * @return bool false on error, true on success - * @access public - */ - public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') - { - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - $block = &$this->_tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - if (($pos = strpos($blocks[$i], '[')) !== false) - { - $name = substr($blocks[$i], 0, $pos); - - if (strpos($blocks[$i], '[]') === $pos) - { - $index = sizeof($block[$name]) - 1; - } - else - { - $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1); - } - } - else - { - $name = $blocks[$i]; - $index = sizeof($block[$name]) - 1; - } - $block = &$block[$name]; - $block = &$block[$index]; - } - - $block = &$block[$blocks[$i]]; // Traverse the last block - } - else - { - // Top-level block. - $block = &$this->_tpldata[$blockname]; - } - - // Change key to zero (change first position) if false and to last position if true - if ($key === false || $key === true) - { - $key = ($key === false) ? 0 : sizeof($block); - } - - // Get correct position if array given - if (is_array($key)) - { - // Search array to get correct position - list($search_key, $search_value) = @each($key); - - $key = NULL; - foreach ($block as $i => $val_ary) - { - if ($val_ary[$search_key] === $search_value) - { - $key = $i; - break; - } - } - - // key/value pair not found - if ($key === NULL) - { - return false; - } - } - - // Insert Block - if ($mode == 'insert') - { - // Make sure we are not exceeding the last iteration - if ($key >= sizeof($this->_tpldata[$blockname])) - { - $key = sizeof($this->_tpldata[$blockname]); - unset($this->_tpldata[$blockname][($key - 1)]['S_LAST_ROW']); - $vararray['S_LAST_ROW'] = true; - } - else if ($key === 0) - { - unset($this->_tpldata[$blockname][0]['S_FIRST_ROW']); - $vararray['S_FIRST_ROW'] = true; - } - - // Re-position template blocks - for ($i = sizeof($block); $i > $key; $i--) - { - $block[$i] = $block[$i-1]; - } - - // Insert vararray at given position - $block[$key] = $vararray; - - return true; - } - - // Which block to change? - if ($mode == 'change') - { - if ($key == sizeof($block)) - { - $key--; - } - - $block[$key] = array_merge($block[$key], $vararray); - - return true; - } - - return false; - } - - /** - * Reset/empty complete block - * @access public - * @param string $blockname Name of block to destroy - */ - public function destroy_block_vars($blockname) - { - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - $str = &$this->_tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - $str = &$str[$blocks[$i]]; - $str = &$str[sizeof($str) - 1]; - } - - unset($str[$blocks[$blockcount]]); - } - else - { - // Top-level block. - unset($this->_tpldata[$blockname]); - } - - return true; - } -} diff --git a/phpBB/includes/template_renderer.php b/phpBB/includes/template_renderer.php deleted file mode 100644 index 0af2d94bb6..0000000000 --- a/phpBB/includes/template_renderer.php +++ /dev/null @@ -1,35 +0,0 @@ -code = $code; - $this->template = $template; - } - - /** - * Displays the template managed by this renderer by eval'ing php code - * of the template. - * @param phpbb_template_context $context Template context to use - * @param array $lang Language entries to use - */ - public function render($context, $lang) - { - $_template = &$this->template; - $_tpldata = &$context->get_data_ref(); - $_rootref = &$context->get_root_ref(); - $_lang = &$lang; - - eval($this->code); - } -} diff --git a/phpBB/includes/template_renderer_include.php b/phpBB/includes/template_renderer_include.php deleted file mode 100644 index aca3a3634d..0000000000 --- a/phpBB/includes/template_renderer_include.php +++ /dev/null @@ -1,60 +0,0 @@ -path = $path; - $this->template = $template; - } - - /** - * Displays the template managed by this renderer by including - * the php file containing the template. - * @param phpbb_template_context $context Template context to use - * @param array $lang Language entries to use - */ - public function render($context, $lang) - { - $_template = &$this->template; - $_tpldata = &$context->get_data_ref(); - $_rootref = &$context->get_root_ref(); - $_lang = &$lang; - - include($this->path); - } -} -- cgit v1.2.1 From 437013194a516932b6f85ba4ee355dcf5836ef19 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 9 May 2011 12:46:34 +0200 Subject: [ticket/10158] Add return-link to folder, when the user replied from a folder. PHPBB3-10158 --- phpBB/includes/ucp/ucp_pm.php | 4 ++-- phpBB/includes/ucp/ucp_pm_compose.php | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/ucp/ucp_pm.php b/phpBB/includes/ucp/ucp_pm.php index e1c51170db..c675928a5b 100644 --- a/phpBB/includes/ucp/ucp_pm.php +++ b/phpBB/includes/ucp/ucp_pm.php @@ -115,7 +115,7 @@ class ucp_pm case 'compose': $action = request_var('action', 'post'); - get_folder($user->data['user_id']); + $user_folders = get_folder($user->data['user_id']); if (!$auth->acl_get('u_sendpm')) { @@ -130,7 +130,7 @@ class ucp_pm } include($phpbb_root_path . 'includes/ucp/ucp_pm_compose.' . $phpEx); - compose_pm($id, $mode, $action); + compose_pm($id, $mode, $action, $user_folders); $tpl_file = 'posting_body'; break; diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index d7fe0af361..6ea702570e 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -20,7 +20,7 @@ if (!defined('IN_PHPBB')) * Compose private message * Called from ucp_pm with mode == 'compose' */ -function compose_pm($id, $mode, $action) +function compose_pm($id, $mode, $action, $user_folders = array()) { global $template, $db, $auth, $user; global $phpbb_root_path, $phpEx, $config; @@ -398,7 +398,7 @@ function compose_pm($id, $mode, $action) unset($message_text); $s_action = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=$mode&action=$action", true, $user->session_id); - $s_action .= ($msg_id) ? "&p=$msg_id" : ''; + $s_action .= (($folder_id) ? "&f=$folder_id" : '') . (($msg_id) ? "&p=$msg_id" : ''); // Delete triggered ? if ($action == 'delete') @@ -741,13 +741,23 @@ function compose_pm($id, $mode, $action) $msg_id = submit_pm($action, $subject, $pm_data); $return_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=view&p=' . $msg_id); - $return_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'); + $inbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'); $outbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); - meta_refresh(3, $return_message_url); + + $folder_return_message = ''; + $return_message_url = $inbox_folder_url; + if ($folder_id && isset($user_folders[$folder_id])) + { + $return_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id); + $folder_return_message = '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user_folders[$folder_id]['folder_name']); + } $message = $user->lang['MESSAGE_STORED'] . '

' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '', ''); - $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_INBOX']); + $message .= $folder_return_message; + $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_INBOX']); $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_OUTBOX']); + + meta_refresh(3, $return_message_url); trigger_error($message); } -- cgit v1.2.1 From 4038091382fb9d5e429c1eaee79413f077a54d2d Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Mon, 9 May 2011 23:11:56 +0200 Subject: [ticket/9999] Remove broken and unused L_FORUM_FOLDER_ALT variable. L_FORUM_FOLDER_ALT was supposed to be a language variable but the language variable is never looked up but directly passed as L_FORUM_FOLDER_ALT instead. Also, the expected functionality is correctly implemented by FORUM_FOLDER_IMG_ALT. PHPBB3-9999 --- phpBB/includes/functions_display.php | 1 - 1 file changed, 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index acaef49fe8..d7422aa2c9 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -477,7 +477,6 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'SUBFORUMS' => $s_subforums_list, 'L_SUBFORUM_STR' => $l_subforums, - 'L_FORUM_FOLDER_ALT' => $folder_alt, 'L_MODERATOR_STR' => $l_moderator, 'U_UNAPPROVED_TOPICS' => ($row['forum_id_unapproved_topics']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_topics&f=' . $row['forum_id_unapproved_topics']) : '', -- cgit v1.2.1 From ca981b6d1819560f7722773796ac33407f18cde8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Fr=C3=A8rejean?= Date: Tue, 10 May 2011 23:31:41 +0200 Subject: [ticket/10170] reCaptcha API has been moved. The reCaptcha API has been moved from recaptcha.net to google.com/recaptcha. PHPBB3-10170 --- phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php index ea171dbe2c..f3bc1a859f 100644 --- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php @@ -27,9 +27,9 @@ if (!class_exists('phpbb_default_captcha')) */ class phpbb_recaptcha extends phpbb_default_captcha { - var $recaptcha_server = 'http://api.recaptcha.net'; - var $recaptcha_server_secure = 'https://api-secure.recaptcha.net'; // class constants :( - var $recaptcha_verify_server = 'api-verify.recaptcha.net'; + var $recaptcha_server = 'http://www.google.com/recaptcha/api'; + var $recaptcha_server_secure = 'https://www.google.com/recaptcha/api'; // class constants :( + var $recaptcha_verify_server = 'http://www.google.com/recaptcha/api/verify'; var $challenge; var $response; -- cgit v1.2.1 From eded608a53b3882a7a42bddf6b1c9f479c2b0304 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Wed, 11 May 2011 03:23:31 +0200 Subject: [ticket/10170] Fix broken recaptcha verification host. PHPBB3-10170 --- phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php index f3bc1a859f..0b0270f568 100644 --- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php @@ -29,7 +29,12 @@ class phpbb_recaptcha extends phpbb_default_captcha { var $recaptcha_server = 'http://www.google.com/recaptcha/api'; var $recaptcha_server_secure = 'https://www.google.com/recaptcha/api'; // class constants :( - var $recaptcha_verify_server = 'http://www.google.com/recaptcha/api/verify'; + + // We are opening a socket to port 80 of this host and send + // the POST request asking for verification to the path specified here. + var $recaptcha_verify_server = 'www.google.com'; + var $recaptcha_verify_path = '/recaptcha/api/verify'; + var $challenge; var $response; @@ -296,7 +301,7 @@ class phpbb_recaptcha extends phpbb_default_captcha return $user->lang['RECAPTCHA_INCORRECT']; } - $response = $this->_recaptcha_http_post($this->recaptcha_verify_server, '/verify', + $response = $this->_recaptcha_http_post($this->recaptcha_verify_server, $this->recaptcha_verify_path, array( 'privatekey' => $config['recaptcha_privkey'], 'remoteip' => $user->ip, -- cgit v1.2.1 From bfdb5c413deb15588c4e6d29e54cc42aae2ff5ae Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Wed, 11 May 2011 11:32:09 +0200 Subject: [ticket/10146] Fix Firebird DECIMAL precision issue on develop. PHPBB3-10146 --- phpBB/includes/db/firebird.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php index 8868d4e317..8acc84b1c0 100644 --- a/phpBB/includes/db/firebird.php +++ b/phpBB/includes/db/firebird.php @@ -497,7 +497,8 @@ class dbal_firebird extends dbal */ function cast_expr_to_bigint($expression) { - return 'CAST(' . $expression . ' as DECIMAL(255, 0))'; + // Precision must be from 1 to 18 + return 'CAST(' . $expression . ' as DECIMAL(18, 0))'; } /** -- cgit v1.2.1 From 0462ab3a4a5cea64699eaf4b2e9900e36d027e50 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 9 May 2011 22:00:38 -0400 Subject: [feature/template-engine] Add back IN_PHPBB preamble. PHPBB3-9726 --- phpBB/includes/template/compile.php | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 4132fb2e34..18a52e87a6 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -54,6 +54,7 @@ class phpbb_template_filter extends php_user_filter public function filter($in, $out, &$consumed, $closing) { $written = false; + $first = false; while ($bucket = stream_bucket_make_writeable($in)) { @@ -71,7 +72,13 @@ class phpbb_template_filter extends php_user_filter $written = true; - $bucket->data = $this->compile($data); + $data = $this->compile($data); + if (!$first) + { + $data = $this->prepend_preamble($data); + $first = false; + } + $bucket->data = $data; $bucket->datalen = strlen($bucket->data); stream_bucket_append($out, $bucket); } @@ -150,6 +157,18 @@ class phpbb_template_filter extends php_user_filter return $data; } + /** + * Prepends a preamble to compiled template. + * Currently preamble checks if IN_PHPBB is defined and calls exit() if it is not. + * @param string $data Compiled template chunk + * @return string Compiled template chunk with preamble prepended + */ + private function prepend_preamble($data) + { + $data = "' . $data); + return $data; + } + private function replace($matches) { if ($this->in_php && $matches[1] != 'ENDPHP') -- cgit v1.2.1 From df76885b11e56348f7fbe6274a6dbc727bb677ad Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 9 May 2011 22:01:07 -0400 Subject: [feature/template-engine] Reinstate phpbb_template#destroy function. PHPBB3-9726 --- phpBB/includes/template.php | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index f27d0c7560..c03b87b13c 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -167,6 +167,15 @@ class phpbb_template return true; } + /** + * Clears all variables and blocks assigned to this template. + * @access public + */ + public function destroy() + { + $this->_context->clear(); + } + /** * Reset/empty complete block * @access public -- cgit v1.2.1 From 0ca7ad66dc8d9173394e0c5fb7e8393977de22ed Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 9 May 2011 22:01:54 -0400 Subject: [feature/template-engine] Refactor hook logic into a separate function. PHPBB3-9726 --- phpBB/includes/template.php | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index c03b87b13c..9a030ffd35 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -195,14 +195,10 @@ class phpbb_template */ public function display($handle, $include_once = true) { - global $phpbb_hook; - - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once, $this)) + $result = $this->call_hook($handle, $include_once); + if ($result !== false) { - if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__))) - { - return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__)); - } + return $result[0]; } /* @@ -228,6 +224,27 @@ class phpbb_template } } + /** + * Calls hook if any is defined. + * @param string $handle Template handle being displayed. + * @param bool $include_once Allow multiple inclusions + */ + private function call_hook($handle, $include_once) + { + global $phpbb_hook; + + if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once, $this)) + { + if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__))) + { + $result = $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__)); + return array($result); + } + } + + return false; + } + /** * Obtains language array. * This is either lang property of global $user object, or if -- cgit v1.2.1 From 97d2a6527e75a5db9249a7c57360087cbaf424ac Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Mon, 9 May 2011 22:02:14 -0400 Subject: [feature/template-engine] Remove commented out error reporting logic. PHPBB3-9726 --- phpBB/includes/template.php | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 9a030ffd35..a30690615d 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -201,16 +201,6 @@ class phpbb_template return $result[0]; } - /* - if (defined('IN_ERROR_HANDLER')) - { - if ((E_NOTICE & error_reporting()) == E_NOTICE) - { - error_reporting(error_reporting() ^ E_NOTICE); - } - } - */ - $renderer = $this->_tpl_load($handle); if ($renderer) -- cgit v1.2.1 From 169c4377e98826432411db773ebcbfa19bcdb439 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 11 May 2011 09:04:07 -0400 Subject: [feature/template-engine] Disposed of underscores in property names. PHPBB3-9726 --- phpBB/includes/template.php | 20 ++++++++--------- phpBB/includes/template/context.php | 44 ++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 32 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index a30690615d..4dadfac571 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -37,7 +37,7 @@ class phpbb_template * Stores template data used during template rendering. * @access private */ - private $_context; + private $context; /** * @var string Root dir for template. @@ -95,7 +95,7 @@ class phpbb_template trigger_error('Template path could not be found: styles/' . $user->theme['template_path'] . '/template', E_USER_ERROR); } - $this->_context = new phpbb_template_context(); + $this->context = new phpbb_template_context(); return true; } @@ -135,7 +135,7 @@ class phpbb_template $this->orig_tpl_inherits_id = false; } - $this->_context = new phpbb_template_context(); + $this->context = new phpbb_template_context(); return true; } @@ -173,7 +173,7 @@ class phpbb_template */ public function destroy() { - $this->_context->clear(); + $this->context->clear(); } /** @@ -183,7 +183,7 @@ class phpbb_template */ public function destroy_block_vars($blockname) { - $this->_context->destroy_block_vars($blockname); + $this->context->destroy_block_vars($blockname); } /** @@ -205,7 +205,7 @@ class phpbb_template if ($renderer) { - $renderer->render($this->_context, $this->get_lang()); + $renderer->render($this->context, $this->get_lang()); return true; } else @@ -439,7 +439,7 @@ class phpbb_template */ public function assign_var($varname, $varval) { - $this->_context->assign_var($varname, $varval); + $this->context->assign_var($varname, $varval); } // Docstring is copied from phpbb_template_context method with the same name. @@ -451,7 +451,7 @@ class phpbb_template */ public function assign_block_vars($blockname, array $vararray) { - return $this->_context->assign_block_vars($blockname, $vararray); + return $this->context->assign_block_vars($blockname, $vararray); } // Docstring is copied from phpbb_template_context method with the same name. @@ -485,7 +485,7 @@ class phpbb_template */ public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') { - return $this->_context->alter_block_array($blockname, $vararray, $key, $mode); + return $this->context->alter_block_array($blockname, $vararray, $key, $mode); } /** @@ -509,7 +509,7 @@ class phpbb_template if ($renderer) { - $renderer->render($this->_context, $this->get_lang()); + $renderer->render($this->context, $this->get_lang()); } else { diff --git a/phpBB/includes/template/context.php b/phpBB/includes/template/context.php index df5c4afb24..c667282f7b 100644 --- a/phpBB/includes/template/context.php +++ b/phpBB/includes/template/context.php @@ -26,17 +26,17 @@ class phpbb_template_context /** * variable that holds all the data we'll be substituting into * the compiled templates. Takes form: - * --> $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value + * --> $this->tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value * if it's a root-level variable, it'll be like this: - * --> $this->_tpldata[.][0][varname] == value + * --> $this->tpldata[.][0][varname] == value * @var array */ - private $_tpldata = array('.' => array(0 => array())); + private $tpldata = array('.' => array(0 => array())); /** - * @var array Reference to template->_tpldata['.'][0] + * @var array Reference to template->tpldata['.'][0] */ - private $_rootref; + private $rootref; public function __construct() { @@ -49,8 +49,8 @@ class phpbb_template_context */ public function clear() { - $this->_tpldata = array('.' => array(0 => array())); - $this->_rootref = &$this->_tpldata['.'][0]; + $this->tpldata = array('.' => array(0 => array())); + $this->rootref = &$this->tpldata['.'][0]; } /** @@ -61,19 +61,19 @@ class phpbb_template_context */ public function assign_var($varname, $varval) { - $this->_rootref[$varname] = $varval; + $this->rootref[$varname] = $varval; return true; } public function get_data_ref() { - return $this->_tpldata; + return $this->tpldata; } public function get_root_ref() { - return $this->_rootref; + return $this->rootref; } /** @@ -90,7 +90,7 @@ class phpbb_template_context $blocks = explode('.', $blockname); $blockcount = sizeof($blocks) - 1; - $str = &$this->_tpldata; + $str = &$this->tpldata; for ($i = 0; $i < $blockcount; $i++) { $str = &$str[$blocks[$i]]; @@ -122,7 +122,7 @@ class phpbb_template_context else { // Top-level block. - $s_row_count = (isset($this->_tpldata[$blockname])) ? sizeof($this->_tpldata[$blockname]) : 0; + $s_row_count = (isset($this->tpldata[$blockname])) ? sizeof($this->tpldata[$blockname]) : 0; $vararray['S_ROW_COUNT'] = $s_row_count; // Assign S_FIRST_ROW @@ -135,11 +135,11 @@ class phpbb_template_context $vararray['S_LAST_ROW'] = true; if ($s_row_count > 0) { - unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']); + unset($this->tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']); } // Add a new iteration to this block with the variable assignments we were given. - $this->_tpldata[$blockname][] = $vararray; + $this->tpldata[$blockname][] = $vararray; } return true; @@ -181,7 +181,7 @@ class phpbb_template_context $blocks = explode('.', $blockname); $blockcount = sizeof($blocks) - 1; - $block = &$this->_tpldata; + $block = &$this->tpldata; for ($i = 0; $i < $blockcount; $i++) { if (($pos = strpos($blocks[$i], '[')) !== false) @@ -211,7 +211,7 @@ class phpbb_template_context else { // Top-level block. - $block = &$this->_tpldata[$blockname]; + $block = &$this->tpldata[$blockname]; } // Change key to zero (change first position) if false and to last position if true @@ -247,15 +247,15 @@ class phpbb_template_context if ($mode == 'insert') { // Make sure we are not exceeding the last iteration - if ($key >= sizeof($this->_tpldata[$blockname])) + if ($key >= sizeof($this->tpldata[$blockname])) { - $key = sizeof($this->_tpldata[$blockname]); - unset($this->_tpldata[$blockname][($key - 1)]['S_LAST_ROW']); + $key = sizeof($this->tpldata[$blockname]); + unset($this->tpldata[$blockname][($key - 1)]['S_LAST_ROW']); $vararray['S_LAST_ROW'] = true; } else if ($key === 0) { - unset($this->_tpldata[$blockname][0]['S_FIRST_ROW']); + unset($this->tpldata[$blockname][0]['S_FIRST_ROW']); $vararray['S_FIRST_ROW'] = true; } @@ -300,7 +300,7 @@ class phpbb_template_context $blocks = explode('.', $blockname); $blockcount = sizeof($blocks) - 1; - $str = &$this->_tpldata; + $str = &$this->tpldata; for ($i = 0; $i < $blockcount; $i++) { $str = &$str[$blocks[$i]]; @@ -312,7 +312,7 @@ class phpbb_template_context else { // Top-level block. - unset($this->_tpldata[$blockname]); + unset($this->tpldata[$blockname]); } return true; -- cgit v1.2.1 From 635460fa6dda70be8ae8b36c4c4be012c9c0a590 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 11 May 2011 09:12:52 -0400 Subject: [feature/template-engine] Fixed reference usage. Hopefully this is right, I have not checked it against the manual (assuming the manual even covers these things). PHPBB3-9726 --- phpBB/includes/template/context.php | 6 +++++- phpBB/includes/template/renderer_eval.php | 2 +- phpBB/includes/template/renderer_include.php | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template/context.php b/phpBB/includes/template/context.php index c667282f7b..695f6e0ed3 100644 --- a/phpBB/includes/template/context.php +++ b/phpBB/includes/template/context.php @@ -68,11 +68,15 @@ class phpbb_template_context public function get_data_ref() { - return $this->tpldata; + // returning a reference directly is not + // something php is capable of doing + $ref = &$this->tpldata; + return $ref; } public function get_root_ref() { + // rootref is already a reference return $this->rootref; } diff --git a/phpBB/includes/template/renderer_eval.php b/phpBB/includes/template/renderer_eval.php index a3d7f88fa5..f3365ff8a7 100644 --- a/phpBB/includes/template/renderer_eval.php +++ b/phpBB/includes/template/renderer_eval.php @@ -50,7 +50,7 @@ class phpbb_template_renderer_eval implements phpbb_template_renderer */ public function render($context, $lang) { - $_template = &$this->template; + $_template = $this->template; $_tpldata = &$context->get_data_ref(); $_rootref = &$context->get_root_ref(); $_lang = &$lang; diff --git a/phpBB/includes/template/renderer_include.php b/phpBB/includes/template/renderer_include.php index aca3a3634d..28a8027df3 100644 --- a/phpBB/includes/template/renderer_include.php +++ b/phpBB/includes/template/renderer_include.php @@ -50,7 +50,7 @@ class phpbb_template_renderer_include implements phpbb_template_renderer */ public function render($context, $lang) { - $_template = &$this->template; + $_template = $this->template; $_tpldata = &$context->get_data_ref(); $_rootref = &$context->get_root_ref(); $_lang = &$lang; -- cgit v1.2.1 From d6f75e97d60981efd3ca2792e1a9d379d922631d Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 11 May 2011 09:17:20 -0400 Subject: [feature/template-engine] Added docblocks to get_*_ref in context. PHPBB3-9726 --- phpBB/includes/template/context.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template/context.php b/phpBB/includes/template/context.php index 695f6e0ed3..73f1373655 100644 --- a/phpBB/includes/template/context.php +++ b/phpBB/includes/template/context.php @@ -66,6 +66,17 @@ class phpbb_template_context return true; } + /** + * Returns a reference to template data array. + * + * This function is public so that template renderer may invoke it. + * Users should alter template variables via functions in phpbb_template. + * + * Note: modifying returned array will affect data stored in the context. + * + * @access public + * @return array template data + */ public function get_data_ref() { // returning a reference directly is not @@ -74,6 +85,17 @@ class phpbb_template_context return $ref; } + /** + * Returns a reference to template root scope. + * + * This function is public so that template renderer may invoke it. + * Users should not need to invoke this function. + * + * Note: modifying returned array will affect data stored in the context. + * + * @access public + * @return array template data + */ public function get_root_ref() { // rootref is already a reference -- cgit v1.2.1 From 504acaba6b898de13d1c27dde567f1a01c0b0bd6 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 11 May 2011 09:23:16 -0400 Subject: [feature/template-engine] Deleted useless assignment. PHPBB3-9726 --- phpBB/includes/template.php | 1 - 1 file changed, 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 4dadfac571..85d378fa67 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -325,7 +325,6 @@ class phpbb_template $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0; - $recompile = false; $recompile = (!file_exists($filename) || @filesize($filename) === 0 || ($config['load_tplcompile'] && @filemtime($filename) < @filemtime($this->files[$handle]))) ? true : false; if (!$recompile) -- cgit v1.2.1 From 77787718196c05b98efccec668c4a9762591398f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 11 May 2011 19:25:07 -0400 Subject: [feature/template-engine] Move DEBUG_EXTRA check for $recompile up. PHPBB3-9726 --- phpBB/includes/template.php | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 85d378fa67..865535cfd5 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -325,24 +325,20 @@ class phpbb_template $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0; - $recompile = (!file_exists($filename) || @filesize($filename) === 0 || ($config['load_tplcompile'] && @filemtime($filename) < @filemtime($this->files[$handle]))) ? true : false; + $recompile = defined('DEBUG_EXTRA') || + !file_exists($filename) || + @filesize($filename) === 0 || + ($config['load_tplcompile'] && @filemtime($filename) < @filemtime($this->files[$handle])); - if (!$recompile) + if (!$recompile && $config['load_tplcompile']) { - if (defined('DEBUG_EXTRA')) - { - $recompile = true; - } - else if ($config['load_tplcompile']) + // No way around it: we need to check inheritance here + if ($user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) { - // No way around it: we need to check inheritance here - if ($user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) - { - $this->files[$handle] = $this->files_inherit[$handle]; - $this->files_template[$handle] = $user->theme['template_inherits_id']; - } - $recompile = (@filemtime($filename) < @filemtime($this->files[$handle])) ? true : false; + $this->files[$handle] = $this->files_inherit[$handle]; + $this->files_template[$handle] = $user->theme['template_inherits_id']; } + $recompile = (@filemtime($filename) < @filemtime($this->files[$handle])) ? true : false; } // Recompile page if the original template is newer, otherwise load the compiled version -- cgit v1.2.1 From 7638bcb56011ebde65005a0ce1abfe7f4a6be4b7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 11 May 2011 19:32:32 -0400 Subject: [feature/template-engine] Rename $filename to $compiled_path for clarity. PHPBB3-9726 --- phpBB/includes/template.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 865535cfd5..2ebbca3568 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -322,13 +322,13 @@ class phpbb_template // by other template class instances in between. $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; - $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; + $compiled_path = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0; $recompile = defined('DEBUG_EXTRA') || - !file_exists($filename) || - @filesize($filename) === 0 || - ($config['load_tplcompile'] && @filemtime($filename) < @filemtime($this->files[$handle])); + !file_exists($compiled_path) || + @filesize($compiled_path) === 0 || + ($config['load_tplcompile'] && @filemtime($compiled_path) < @filemtime($this->files[$handle])); if (!$recompile && $config['load_tplcompile']) { @@ -338,13 +338,13 @@ class phpbb_template $this->files[$handle] = $this->files_inherit[$handle]; $this->files_template[$handle] = $user->theme['template_inherits_id']; } - $recompile = (@filemtime($filename) < @filemtime($this->files[$handle])) ? true : false; + $recompile = (@filemtime($compiled_path) < @filemtime($this->files[$handle])) ? true : false; } // Recompile page if the original template is newer, otherwise load the compiled version if (!$recompile) { - return new phpbb_template_renderer_include($filename, $this); + return new phpbb_template_renderer_include($compiled_path, $this); } // Inheritance - we point to another template file for this one. -- cgit v1.2.1 From d2daaf0317ac6bb224b8f93c1ac9578c9d570dc9 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 11 May 2011 19:38:04 -0400 Subject: [feature/template-engine] Try to handle failed template includes. PHPBB3-9726 --- phpBB/includes/template.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 2ebbca3568..90b8bb2a22 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -508,7 +508,8 @@ class phpbb_template } else { - // What should we do here? + // trigger_error cannot be used here, as the output already started + echo 'template->_tpl_include(): Failed including ' . htmlspecialchars($handle) . "\n"; } } @@ -525,7 +526,7 @@ class phpbb_template if (!file_exists($file)) { // trigger_error cannot be used here, as the output already started - echo 'template->_php_include(): File ' . htmlspecialchars($file) . ' does not exist or is empty'; + echo 'template->_php_include(): File ' . htmlspecialchars($file) . " does not exist\n"; return; } include($file); -- cgit v1.2.1 From 345852d240fe224fa825f90b0ef8a34398c91291 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Wed, 11 May 2011 19:43:08 -0400 Subject: [feature/template-engine] Clarify cache directory path for set_custom_template Even if the template may be outside of phpBB, phpBB's cache directory is still going to be used for storing compiled template code. PHPBB3-9726 --- phpBB/includes/template.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 90b8bb2a22..daff785dc0 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -101,7 +101,10 @@ class phpbb_template } /** - * Set custom template location (able to use directory outside of phpBB) + * Set custom template location (able to use directory outside of phpBB). + * + * Note: Templates are still compiled to phpBB's cache directory. + * * @access public * @param string $template_path Path to template directory * @param string $template_name Name of template -- cgit v1.2.1 From d2ac05aa74d3a1c9723be41a4c0ffe86542f223f Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 12 May 2011 18:08:36 -0400 Subject: [feature/template-engine] Replaced globals with dependency injection. PHPBB3-9726 --- phpBB/includes/functions_messenger.php | 4 +- phpBB/includes/template.php | 93 +++++++++++++++++++++------------- 2 files changed, 60 insertions(+), 37 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index 8255d4b148..da7e7cb9e4 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -175,7 +175,7 @@ class messenger */ function template($template_file, $template_lang = '', $template_path = '') { - global $config, $phpbb_root_path, $user; + global $config, $phpbb_root_path, $phpEx, $user; if (!trim($template_file)) { @@ -193,7 +193,7 @@ class messenger // tpl_msg now holds a template object we can use to parse the template file if (!isset($this->tpl_msg[$template_lang . $template_file])) { - $this->tpl_msg[$template_lang . $template_file] = new phpbb_template(); + $this->tpl_msg[$template_lang . $template_file] = new phpbb_template($phpbb_root_path, $phpEx, $config, $user); $tpl = &$this->tpl_msg[$template_lang . $template_file]; $fallback_template_path = false; diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index daff785dc0..64a3b80f07 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -65,34 +65,67 @@ class phpbb_template public $orig_tpl_inherits_id; + /** + * @var string phpBB root path + */ + private $phpbb_root_path; + + /** + * @var phpEx PHP file extension + */ + private $phpEx; + + /** + * @var phpbb_config phpBB config instance + */ + private $config; + + /** + * @var user current user + */ + private $user; + + /** + * Constructor. + * + * @param string $phpbb_root_path phpBB root path + * @param user $user current user + */ + public function __construct($phpbb_root_path, $phpEx, $config, $user) + { + $this->phpbb_root_path = $phpbb_root_path; + $this->phpEx = $phpEx; + $this->config = $config; + $this->user = $user; + } + /** * Set template location * @access public */ public function set_template() { - global $phpbb_root_path, $user; - - if (file_exists($phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template')) + $template_path = $this->user->theme['template_path']; + if (file_exists($this->phpbb_root_path . 'styles/' . $template_path . '/template')) { - $this->root = $phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template'; - $this->cachepath = $phpbb_root_path . 'cache/tpl_' . str_replace('_', '-', $user->theme['template_path']) . '_'; + $this->root = $this->phpbb_root_path . 'styles/' . $template_path . '/template'; + $this->cachepath = $this->phpbb_root_path . 'cache/tpl_' . str_replace('_', '-', $template_path) . '_'; if ($this->orig_tpl_inherits_id === null) { - $this->orig_tpl_inherits_id = $user->theme['template_inherits_id']; + $this->orig_tpl_inherits_id = $this->user->theme['template_inherits_id']; } - $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; + $this->user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; - if ($user->theme['template_inherits_id']) + if ($this->user->theme['template_inherits_id']) { - $this->inherit_root = $phpbb_root_path . 'styles/' . $user->theme['template_inherit_path'] . '/template'; + $this->inherit_root = $this->phpbb_root_path . 'styles/' . $this->user->theme['template_inherit_path'] . '/template'; } } else { - trigger_error('Template path could not be found: styles/' . $user->theme['template_path'] . '/template', E_USER_ERROR); + trigger_error('Template path could not be found: styles/' . $template_path . '/template', E_USER_ERROR); } $this->context = new phpbb_template_context(); @@ -112,8 +145,6 @@ class phpbb_template */ public function set_custom_template($template_path, $template_name, $fallback_template_path = false) { - global $phpbb_root_path, $user; - // Make sure $template_path has no ending slash if (substr($template_path, -1) == '/') { @@ -121,7 +152,7 @@ class phpbb_template } $this->root = $template_path; - $this->cachepath = $phpbb_root_path . 'cache/ctpl_' . str_replace('_', '-', $template_name) . '_'; + $this->cachepath = $this->phpbb_root_path . 'cache/ctpl_' . str_replace('_', '-', $template_name) . '_'; if ($fallback_template_path !== false) { @@ -240,17 +271,15 @@ class phpbb_template /** * Obtains language array. - * This is either lang property of global $user object, or if + * This is either lang property of $user property, or if * it is not set an empty array. * @return array language entries */ public function get_lang() { - global $user; - - if (isset($user->lang)) + if (isset($this->user->lang)) { - $lang = $user->lang; + $lang = $this->user->lang; } else { @@ -313,8 +342,6 @@ class phpbb_template */ private function _tpl_load($handle) { - global $user, $phpEx, $config; - if (!isset($this->filename[$handle])) { trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR); @@ -323,23 +350,23 @@ class phpbb_template // reload this setting to have the values they had when this object was initialised // using set_template or set_custom_template, they might otherwise have been overwritten // by other template class instances in between. - $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; + $this->user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; - $compiled_path = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; - $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0; + $compiled_path = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $this->phpEx; + $this->files_template[$handle] = (isset($this->user->theme['template_id'])) ? $this->user->theme['template_id'] : 0; $recompile = defined('DEBUG_EXTRA') || !file_exists($compiled_path) || @filesize($compiled_path) === 0 || - ($config['load_tplcompile'] && @filemtime($compiled_path) < @filemtime($this->files[$handle])); + ($this->config['load_tplcompile'] && @filemtime($compiled_path) < @filemtime($this->files[$handle])); - if (!$recompile && $config['load_tplcompile']) + if (!$recompile && $this->config['load_tplcompile']) { // No way around it: we need to check inheritance here - if ($user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) + if ($this->user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) { $this->files[$handle] = $this->files_inherit[$handle]; - $this->files_template[$handle] = $user->theme['template_inherits_id']; + $this->files_template[$handle] = $this->user->theme['template_inherits_id']; } $recompile = (@filemtime($compiled_path) < @filemtime($this->files[$handle])) ? true : false; } @@ -351,10 +378,10 @@ class phpbb_template } // Inheritance - we point to another template file for this one. - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) + if (isset($this->user->theme['template_inherits_id']) && $this->user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) { $this->files[$handle] = $this->files_inherit[$handle]; - $this->files_template[$handle] = $user->theme['template_inherits_id']; + $this->files_template[$handle] = $this->user->theme['template_inherits_id']; } $source_file = $this->_source_file_for_handle($handle); @@ -410,9 +437,7 @@ class phpbb_template */ private function _compiled_file_for_handle($handle) { - global $phpEx; - - $compiled_file = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; + $compiled_file = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $this->phpEx; return $compiled_file; } @@ -522,9 +547,7 @@ class phpbb_template */ private function _php_include($filename) { - global $phpbb_root_path; - - $file = $phpbb_root_path . $filename; + $file = $this->phpbb_root_path . $filename; if (!file_exists($file)) { -- cgit v1.2.1 From 94560d708649df876f8486d4ba5361475037f1ff Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 12 May 2011 20:09:41 -0400 Subject: [feature/template-engine] Make INCLUDEPHP relative to board root. PHPBB3-9726 --- phpBB/includes/template.php | 6 +++--- phpBB/includes/template/compile.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 64a3b80f07..f2b1cccd2c 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -513,7 +513,7 @@ class phpbb_template /** * Include a separate template - * @access private + * @access public * @param string $filename Template filename to include * @param bool $include True to include the file, false to just load it * @uses template_compile is used to compile uncached templates @@ -543,9 +543,9 @@ class phpbb_template /** * Include a php-file - * @access private + * @access public */ - private function _php_include($filename) + public function _php_include($filename) { $file = $this->phpbb_root_path . $filename; diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 18a52e87a6..46a30d26d3 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -667,7 +667,7 @@ class phpbb_template_filter extends php_user_filter */ private function compile_tag_include_php($tag_args) { - return "include('$tag_args');"; + return "\$_template->_php_include('$tag_args');"; } /** -- cgit v1.2.1 From b04f0a5f70ed79d45e254d7b6db61f6fc1f484f5 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 13 May 2011 10:49:53 -0400 Subject: [feature/template-engine] Delete @access everywhere. Access specification in php 5 is done directly on functions/properties. PHPBB3-9726 --- phpBB/includes/template.php | 17 ----------------- phpBB/includes/template/compile.php | 12 ------------ phpBB/includes/template/context.php | 7 ------- 3 files changed, 36 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index f2b1cccd2c..5fb0f41311 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -35,7 +35,6 @@ class phpbb_template /** * @var phpbb_template_context Template context. * Stores template data used during template rendering. - * @access private */ private $context; @@ -101,7 +100,6 @@ class phpbb_template /** * Set template location - * @access public */ public function set_template() { @@ -138,7 +136,6 @@ class phpbb_template * * Note: Templates are still compiled to phpBB's cache directory. * - * @access public * @param string $template_path Path to template directory * @param string $template_name Name of template * @param string $fallback_template_path Path to fallback template @@ -177,7 +174,6 @@ class phpbb_template /** * Sets the template filenames for handles. $filename_array * should be a hash of handle => filename pairs. - * @access public * @param array $filname_array Should be a hash of handle => filename pairs. */ public function set_filenames(array $filename_array) @@ -203,7 +199,6 @@ class phpbb_template /** * Clears all variables and blocks assigned to this template. - * @access public */ public function destroy() { @@ -212,7 +207,6 @@ class phpbb_template /** * Reset/empty complete block - * @access public * @param string $blockname Name of block to destroy */ public function destroy_block_vars($blockname) @@ -222,7 +216,6 @@ class phpbb_template /** * Display handle - * @access public * @param string $handle Handle to display * @param bool $include_once Allow multiple inclusions * @return bool True on success, false on failure @@ -290,7 +283,6 @@ class phpbb_template /** * Display the handle and assign the output to a template variable or return the compiled result. - * @access public * @param string $handle Handle to operate on * @param string $template_var Template variable to assign compiled handle to * @param bool $return_content If true return compiled handle, otherwise assign to $template_var @@ -335,7 +327,6 @@ class phpbb_template * contents sent to the output stream (unless, of course, output * buffering is in effect). * - * @access private * @param string $handle Handle of the template to load * @return phpbb_template_renderer Template renderer object, or null on failure * @uses template_compile is used to compile template source @@ -407,7 +398,6 @@ class phpbb_template /** * Resolves template handle $handle to source file path. - * @access private * @param string $handle Template handle (i.e. "friendly" template name) * @return string Source file path */ @@ -431,7 +421,6 @@ class phpbb_template /** * Determines compiled file path for handle $handle. - * @access private * @param string $handle Template handle (i.e. "friendly" template name) * @return string Compiled file path */ @@ -443,7 +432,6 @@ class phpbb_template /** * Assign key variable pairs from an array - * @access public * @param array $vararray A hash of variable name => value pairs */ public function assign_vars(array $vararray) @@ -456,7 +444,6 @@ class phpbb_template /** * Assign a single variable to a single key - * @access public * @param string $varname Variable name * @param string $varval Value to assign to variable */ @@ -468,7 +455,6 @@ class phpbb_template // Docstring is copied from phpbb_template_context method with the same name. /** * Assign key variable pairs from an array to a specified block - * @access public * @param string $blockname Name of block to assign $vararray to * @param array $vararray A hash of variable name => value pairs */ @@ -504,7 +490,6 @@ class phpbb_template * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars) * * @return bool false on error, true on success - * @access public */ public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') { @@ -513,7 +498,6 @@ class phpbb_template /** * Include a separate template - * @access public * @param string $filename Template filename to include * @param bool $include True to include the file, false to just load it * @uses template_compile is used to compile uncached templates @@ -543,7 +527,6 @@ class phpbb_template /** * Include a php-file - * @access public */ public function _php_include($filename) { diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 46a30d26d3..79a7d784cd 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -260,7 +260,6 @@ class phpbb_template_filter extends php_user_filter /** * Compile variables - * @access private */ private function compile_var_tags(&$text_blocks) { @@ -310,7 +309,6 @@ class phpbb_template_filter extends php_user_filter /** * Compile blocks - * @access private */ private function compile_tag_block($tag_args) { @@ -423,7 +421,6 @@ class phpbb_template_filter extends php_user_filter /** * Compile a general expression - much of this is from Smarty with * some adaptions for our block level methods - * @access private */ private function compile_expression($tag_args) { @@ -630,7 +627,6 @@ class phpbb_template_filter extends php_user_filter /** * Compile DEFINE tags - * @access private */ private function compile_tag_define($tag_args, $op) { @@ -654,7 +650,6 @@ class phpbb_template_filter extends php_user_filter /** * Compile INCLUDE tag - * @access private */ private function compile_tag_include($tag_args) { @@ -663,7 +658,6 @@ class phpbb_template_filter extends php_user_filter /** * Compile INCLUDE_PHP tag - * @access private */ private function compile_tag_include_php($tag_args) { @@ -673,7 +667,6 @@ class phpbb_template_filter extends php_user_filter /** * parse expression * This is from Smarty - * @access private */ private function _parse_is_expr($is_arg, $tokens) { @@ -752,7 +745,6 @@ class phpbb_template_filter extends php_user_filter * ' . $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' * It's ready to be inserted into an "echo" line in one of the templates. * - * @access private * @param string $namespace Namespace to access (expects a trailing "." on the namespace) * @param string $varname Variable name to use * @param bool $echo If true return an echo statement, otherwise a reference to the internal variable @@ -815,7 +807,6 @@ class phpbb_template_filter extends php_user_filter * (possibly nested) block namespace. This is a string of the form: * $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] * - * @access private * @param string $blockname Block to access (does not expect a trailing "." on the blockname) * @param bool $include_last_iterator If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable @@ -883,7 +874,6 @@ class phpbb_template_compile /** * Compiles template in $source_file and writes compiled template to * cache directory - * @access public * @param string $handle Template handle to compile * @param string $source_file Source template file * @return bool Return true on success otherwise false @@ -916,7 +906,6 @@ class phpbb_template_compile /** * Compiles a template located at $source_file. * Returns PHP source suitable for eval(). - * @access public * @param string $source_file Source template file * @return string|bool Return compiled code on successful compilation otherwise false */ @@ -947,7 +936,6 @@ class phpbb_template_compile * A stream filter is appended to $source_stream as part of the * process. * - * @access private * @param resource $source_stream Source stream * @param resource $dest_stream Destination stream * @return void diff --git a/phpBB/includes/template/context.php b/phpBB/includes/template/context.php index 73f1373655..3c0dceb981 100644 --- a/phpBB/includes/template/context.php +++ b/phpBB/includes/template/context.php @@ -45,7 +45,6 @@ class phpbb_template_context /** * Clears template data set. - * @access public */ public function clear() { @@ -55,7 +54,6 @@ class phpbb_template_context /** * Assign a single variable to a single key - * @access public * @param string $varname Variable name * @param string $varval Value to assign to variable */ @@ -74,7 +72,6 @@ class phpbb_template_context * * Note: modifying returned array will affect data stored in the context. * - * @access public * @return array template data */ public function get_data_ref() @@ -93,7 +90,6 @@ class phpbb_template_context * * Note: modifying returned array will affect data stored in the context. * - * @access public * @return array template data */ public function get_root_ref() @@ -104,7 +100,6 @@ class phpbb_template_context /** * Assign key variable pairs from an array to a specified block - * @access public * @param string $blockname Name of block to assign $vararray to * @param array $vararray A hash of variable name => value pairs */ @@ -197,7 +192,6 @@ class phpbb_template_context * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars) * * @return bool false on error, true on success - * @access public */ public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert') { @@ -315,7 +309,6 @@ class phpbb_template_context /** * Reset/empty complete block - * @access public * @param string $blockname Name of block to destroy */ public function destroy_block_vars($blockname) -- cgit v1.2.1 From 70ccf04e068c3de1611049d094b8295fb6f07b45 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 13 May 2011 10:52:33 -0400 Subject: [feature/template-engine] Moved phpbb_template_filter into own file. PHPBB3-9726 --- phpBB/includes/template/compile.php | 831 ----------------------------------- phpBB/includes/template/filter.php | 848 ++++++++++++++++++++++++++++++++++++ 2 files changed, 848 insertions(+), 831 deletions(-) create mode 100644 phpBB/includes/template/filter.php (limited to 'phpBB/includes') diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 79a7d784cd..246c83a010 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -16,837 +16,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* The template filter that does the actual compilation -* @see template_compile -* @package phpBB3 -*/ -class phpbb_template_filter extends php_user_filter -{ - const REGEX_NS = '[a-z_][a-z_0-9]+'; - - const REGEX_VAR = '[A-Z_][A-Z_0-9]+'; - - const REGEX_TAG = ''; - - const REGEX_TOKENS = '~|{((?:[a-z_][a-z_0-9]+\.)*\\$?[A-Z][A-Z_0-9]+)}~'; - - /** - * @var array - */ - private $block_names = array(); - - /** - * @var array - */ - private $block_else_level = array(); - - /** - * @var string - */ - private $chunk; - - /** - * @var bool - */ - private $in_php; - - public function filter($in, $out, &$consumed, $closing) - { - $written = false; - $first = false; - - while ($bucket = stream_bucket_make_writeable($in)) - { - $consumed += $bucket->datalen; - - $data = $this->chunk . $bucket->data; - $last_nl = strrpos($data, "\n"); - $this->chunk = substr($data, $last_nl); - $data = substr($data, 0, $last_nl); - - if (!strlen($data)) - { - continue; - } - - $written = true; - - $data = $this->compile($data); - if (!$first) - { - $data = $this->prepend_preamble($data); - $first = false; - } - $bucket->data = $data; - $bucket->datalen = strlen($bucket->data); - stream_bucket_append($out, $bucket); - } - - if ($closing && strlen($this->chunk)) - { - $written = true; - $bucket = stream_bucket_new($this->stream, $this->compile($this->chunk)); - stream_bucket_append($out, $bucket); - } - - return $written ? PSFS_PASS_ON : PSFS_FEED_ME; - } - - public function onCreate() - { - $this->chunk = ''; - $this->in_php = false; - return true; - } - - private function compile($data) - { - $block_start_in_php = $this->in_php; - - $data = preg_replace('#<(?:[\\?%]|script)#s', '', $data); - $data = preg_replace_callback(self::REGEX_TOKENS, array($this, 'replace'), $data); - - global $config; - - // Remove php - if (!$config['tpl_allow_php']) - { - if ($block_start_in_php - && $this->in_php - && strpos($data, '') === false - && strpos($data, '') === false) - { - // This is just php code - return ''; - } - $data = preg_replace('~^.*?~', '', $data); - $data = preg_replace('~.*?~', '', $data); - $data = preg_replace('~.*?$~', '', $data); - } - - /* - Preserve whitespace. - PHP removes a newline after the closing tag (if it's there). This is by design. - - - Consider the following template: - - - some content - - - If we were to simply preserve all whitespace, we could simply replace all "?>" tags - with "?>\n". - Doing that, would add additional newlines to the compiled tempalte in place of the - IF and ENDIF statements. These newlines are unwanted (and one is conditional). - The IF and ENDIF are usually on their own line for ease of reading. - - This replacement preserves newlines only for statements that aren't the only statement on a line. - It will NOT preserve newlines at the end of statements in the above examle. - It will preserve newlines in situations like: - - inline content - - - */ - - $data = preg_replace('~(?).)+(?)$~m', "$1\n", $data); - $data = str_replace('/**/?>', "?>\n", $data); - $data = str_replace('?>' . $data); - return $data; - } - - private function replace($matches) - { - if ($this->in_php && $matches[1] != 'ENDPHP') - { - return ''; - } - - if (isset($matches[3])) - { - return $this->compile_var_tags($matches[0]); - } - - global $config; - - switch ($matches[1]) - { - case 'BEGIN': - $this->block_else_level[] = false; - return 'compile_tag_block($matches[2]) . ' ?>'; - break; - - case 'BEGINELSE': - $this->block_else_level[sizeof($this->block_else_level) - 1] = true; - return ''; - break; - - case 'END': - array_pop($this->block_names); - return 'block_else_level)) ? '}' : '}}') . ' ?>'; - break; - - case 'IF': - return 'compile_tag_if($matches[2], false) . ' ?>'; - break; - - case 'ELSE': - return ''; - break; - - case 'ELSEIF': - return 'compile_tag_if($matches[2], true) . ' ?>'; - break; - - case 'ENDIF': - return ''; - break; - - case 'DEFINE': - return 'compile_tag_define($matches[2], true) . ' ?>'; - break; - - case 'UNDEFINE': - return 'compile_tag_define($matches[2], false) . ' ?>'; - break; - - case 'INCLUDE': - return 'compile_tag_include($matches[2]) . ' ?>'; - break; - - case 'INCLUDEPHP': - return ($config['tpl_allow_php']) ? 'compile_tag_include_php($matches[2]) . ' ?>' : ''; - break; - - case 'PHP': - if ($config['tpl_allow_php']) - { - $this->in_php = true; - return ''; - break; - - case 'ENDPHP': - if ($config['tpl_allow_php']) - { - $this->in_php = false; - return ' ?>'; - } - return ''; - break; - - default: - return $matches[0]; - break; - - } - return ''; - } - - /** - * Compile variables - */ - private function compile_var_tags(&$text_blocks) - { - // change template varrefs into PHP varrefs - $varrefs = array(); - - // This one will handle varrefs WITH namespaces - preg_match_all('#\{((?:' . self::REGEX_NS . '\.)+)(\$)?(' . self::REGEX_VAR . ')\}#', $text_blocks, $varrefs, PREG_SET_ORDER); - - foreach ($varrefs as $var_val) - { - $namespace = $var_val[1]; - $varname = $var_val[3]; - $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]); - - $text_blocks = str_replace($var_val[0], $new, $text_blocks); - } - - // Handle special language tags L_ and LA_ - $this->compile_language_tags($text_blocks); - - // This will handle the remaining root-level varrefs - $text_blocks = preg_replace('#\{(' . self::REGEX_VAR . ')\}#', "", $text_blocks); - $text_blocks = preg_replace('#\{\$(' . self::REGEX_VAR . ')\}#', "", $text_blocks); - - return $text_blocks; - } - - /** - * Handles special language tags L_ and LA_ - */ - private function compile_language_tags(&$text_blocks) - { - // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array - if (strpos($text_blocks, '{L_') !== false) - { - $text_blocks = preg_replace('#\{L_(' . self::REGEX_VAR . ')\}#', "", $text_blocks); - } - - // Handle addslashed language variables prefixed with LA_ - // If a template variable already exist, it will be used in favor of it... - if (strpos($text_blocks, '{LA_') !== false) - { - $text_blocks = preg_replace('#\{LA_(' . self::REGEX_VAR . '+)\}#', "", $text_blocks); - } - } - - /** - * Compile blocks - */ - private function compile_tag_block($tag_args) - { - $no_nesting = false; - - // Is the designer wanting to call another loop in a loop? - // - // - // - // - // 'loop2' is actually on the same nesting level as 'loop' you assign - // variables to it with template->assign_block_vars('loop2', array(...)) - if (strpos($tag_args, '!') === 0) - { - // Count the number if ! occurrences (not allowed in vars) - $no_nesting = substr_count($tag_args, '!'); - $tag_args = substr($tag_args, $no_nesting); - } - - // Allow for control of looping (indexes start from zero): - // foo(2) : Will start the loop on the 3rd entry - // foo(-2) : Will start the loop two entries from the end - // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth - // foo(3,-4) : Will start the loop on the fourth entry and end it four from last - $match = array(); - - if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match)) - { - $tag_args = $match[1]; - - if ($match[2] < 0) - { - $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')'; - } - else - { - $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')'; - } - - if (!isset($match[3]) || strlen($match[3]) < 1 || $match[3] == -1) - { - $loop_end = '$_' . $tag_args . '_count'; - } - else if ($match[3] >= 0) - { - $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')'; - } - else //if ($match[3] < -1) - { - $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1); - } - } - else - { - $loop_start = 0; - $loop_end = '$_' . $tag_args . '_count'; - } - - $tag_template_php = ''; - array_push($this->block_names, $tag_args); - - if ($no_nesting !== false) - { - // We need to implode $no_nesting times from the end... - $block = array_slice($this->block_names, -$no_nesting); - } - else - { - $block = $this->block_names; - } - - if (sizeof($block) < 2) - { - // Block is not nested. - $tag_template_php = '$_' . $tag_args . "_count = (isset(\$_tpldata['$tag_args'])) ? sizeof(\$_tpldata['$tag_args']) : 0;"; - $varref = "\$_tpldata['$tag_args']"; - } - else - { - // This block is nested. - // Generate a namespace string for this block. - $namespace = implode('.', $block); - - // Get a reference to the data array for this block that depends on the - // current indices of all parent blocks. - $varref = $this->generate_block_data_ref($namespace, false); - - // Create the for loop code to iterate over this block. - $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;'; - } - - $tag_template_php .= 'if ($_' . $tag_args . '_count) {'; - - /** - * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory - * - * if (!$offset) - * { - * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){'; - * } - * - */ - - $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){'; - $tag_template_php .= '$_' . $tag_args . '_val = &' . $varref . '[$_' . $tag_args . '_i];'; - - return $tag_template_php; - } - - /** - * Compile a general expression - much of this is from Smarty with - * some adaptions for our block level methods - */ - private function compile_expression($tag_args) - { - $match = array(); - preg_match_all('/(?: - "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | - \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | - [(),] | - [^\s(),]+)/x', $tag_args, $match); - - $tokens = $match[0]; - $is_arg_stack = array(); - - for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) - { - $token = &$tokens[$i]; - - switch ($token) - { - case '!==': - case '===': - case '<<': - case '>>': - case '|': - case '^': - case '&': - case '~': - case ')': - case ',': - case '+': - case '-': - case '*': - case '/': - case '@': - break; - - case '==': - case 'eq': - $token = '=='; - break; - - case '!=': - case '<>': - case 'ne': - case 'neq': - $token = '!='; - break; - - case '<': - case 'lt': - $token = '<'; - break; - - case '<=': - case 'le': - case 'lte': - $token = '<='; - break; - - case '>': - case 'gt': - $token = '>'; - break; - - case '>=': - case 'ge': - case 'gte': - $token = '>='; - break; - - case '&&': - case 'and': - $token = '&&'; - break; - - case '||': - case 'or': - $token = '||'; - break; - - case '!': - case 'not': - $token = '!'; - break; - - case '%': - case 'mod': - $token = '%'; - break; - - case '(': - array_push($is_arg_stack, $i); - break; - - case 'is': - $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; - $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); - - $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); - - array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens); - - $i = $is_arg_start; - - // no break - - default: - $varrefs = array(); - if (preg_match('#^((?:' . self::REGEX_NS . '\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs)) - { - if (!empty($varrefs[1])) - { - $namespace = substr($varrefs[1], 0, -1); - $dot_pos = strrchr($namespace, '.'); - if ($dot_pos !== false) - { - $namespace = substr($dot_pos, 1); - } - - // S_ROW_COUNT is deceptive, it returns the current row number not the number of rows - // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM - switch ($varrefs[3]) - { - case 'S_ROW_NUM': - case 'S_ROW_COUNT': - $token = "\$_${namespace}_i"; - break; - - case 'S_NUM_ROWS': - $token = "\$_${namespace}_count"; - break; - - case 'S_FIRST_ROW': - $token = "(\$_${namespace}_i == 0)"; - break; - - case 'S_LAST_ROW': - $token = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; - break; - - case 'S_BLOCK_NAME': - $token = "'$namespace'"; - break; - - default: - $token = $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']'; - $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; - break; - } - } - else - { - $token = ($varrefs[2]) ? '$_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$_rootref[\'' . $varrefs[3] . '\']'; - $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; - } - - } - else if (preg_match('#^\.((?:' . self::REGEX_NS . '\.?)+)$#s', $token, $varrefs)) - { - // Allow checking if loops are set with .loopname - // It is also possible to check the loop count by doing for example - $blocks = explode('.', $varrefs[1]); - - // If the block is nested, we have a reference that we can grab. - // If the block is not nested, we just go and grab the block from _tpldata - if (sizeof($blocks) > 1) - { - $block = array_pop($blocks); - $namespace = implode('.', $blocks); - $varref = $this->generate_block_data_ref($namespace, true); - - // Add the block reference for the last child. - $varref .= "['" . $block . "']"; - } - else - { - $varref = '$_tpldata'; - - // Add the block reference for the last child. - $varref .= "['" . $blocks[0] . "']"; - } - $token = "(isset($varref) ? sizeof($varref) : 0)"; - } - - break; - } - } - - return $tokens; - } - - - private function compile_tag_if($tag_args, $elseif) - { - $tokens = $this->compile_expression($tag_args); - - $tpl = ($elseif) ? '} else if (' : 'if ('; - - $tpl .= implode(' ', $tokens); - $tpl .= ') { '; - - return $tpl; - } - - /** - * Compile DEFINE tags - */ - private function compile_tag_define($tag_args, $op) - { - $match = array(); - preg_match('#^((?:' . self::REGEX_NS . '\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (.*?))?$#', $tag_args, $match); - - if (empty($match[2]) || (!isset($match[3]) && $op)) - { - return ''; - } - - if (!$op) - { - return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');'; - } - - $parsed_statement = implode(' ', $this->compile_expression($match[3])); - - return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $parsed_statement . ';'; - } - - /** - * Compile INCLUDE tag - */ - private function compile_tag_include($tag_args) - { - return "\$_template->_tpl_include('$tag_args');"; - } - - /** - * Compile INCLUDE_PHP tag - */ - private function compile_tag_include_php($tag_args) - { - return "\$_template->_php_include('$tag_args');"; - } - - /** - * parse expression - * This is from Smarty - */ - private function _parse_is_expr($is_arg, $tokens) - { - $expr_end = 0; - $negate_expr = false; - - if (($first_token = array_shift($tokens)) == 'not') - { - $negate_expr = true; - $expr_type = array_shift($tokens); - } - else - { - $expr_type = $first_token; - } - - switch ($expr_type) - { - case 'even': - if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!(($is_arg / $expr_arg) & 1)"; - } - else - { - $expr = "!($is_arg & 1)"; - } - break; - - case 'odd': - if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "(($is_arg / $expr_arg) & 1)"; - } - else - { - $expr = "($is_arg & 1)"; - } - break; - - case 'div': - if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!($is_arg % $expr_arg)"; - } - break; - } - - if ($negate_expr) - { - if ($expr[0] == '!') - { - // Negated expression, de-negate it. - $expr = substr($expr, 1); - } - else - { - $expr = "!($expr)"; - } - } - - array_splice($tokens, 0, $expr_end, $expr); - - return $tokens; - } - - /** - * Generates a reference to the given variable inside the given (possibly nested) - * block namespace. This is a string of the form: - * ' . $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' - * It's ready to be inserted into an "echo" line in one of the templates. - * - * @param string $namespace Namespace to access (expects a trailing "." on the namespace) - * @param string $varname Variable name to use - * @param bool $echo If true return an echo statement, otherwise a reference to the internal variable - * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable - * @return string Code to access variable or echo it if $echo is true - */ - private function generate_block_varref($namespace, $varname, $echo = true, $defop = false) - { - // Strip the trailing period. - $namespace = substr($namespace, 0, -1); - - $expr = true; - $isset = false; - - // S_ROW_COUNT is deceptive, it returns the current row number now the number of rows - // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM - switch ($varname) - { - case 'S_ROW_NUM': - case 'S_ROW_COUNT': - $varref = "\$_${namespace}_i"; - break; - - case 'S_NUM_ROWS': - $varref = "\$_${namespace}_count"; - break; - - case 'S_FIRST_ROW': - $varref = "(\$_${namespace}_i == 0)"; - break; - - case 'S_LAST_ROW': - $varref = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; - break; - - case 'S_BLOCK_NAME': - $varref = "'$namespace'"; - break; - - default: - // Get a reference to the data block for this namespace. - $varref = $this->generate_block_data_ref($namespace, true, $defop); - // Prepend the necessary code to stick this in an echo line. - - // Append the variable reference. - $varref .= "['$varname']"; - - $expr = false; - $isset = true; - break; - } - // @todo Test the !$expr more - $varref = ($echo) ? '' : (($expr || isset($varref)) ? $varref : ''); - - return $varref; - } - - /** - * Generates a reference to the array of data values for the given - * (possibly nested) block namespace. This is a string of the form: - * $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] - * - * @param string $blockname Block to access (does not expect a trailing "." on the blockname) - * @param bool $include_last_iterator If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. - * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable - * @return string Code to access variable - */ - private function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) - { - // Get an array of the blocks involved. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - // DEFINE is not an element of any referenced variable, we must use _tpldata to access it - if ($defop) - { - $varref = '$_tpldata[\'DEFINE\']'; - // Build up the string with everything but the last child. - for ($i = 0; $i < $blockcount; $i++) - { - $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]'; - } - // Add the block reference for the last child. - $varref .= "['" . $blocks[$blockcount] . "']"; - // Add the iterator for the last child if requried. - if ($include_last_iterator) - { - $varref .= '[$_' . $blocks[$blockcount] . '_i]'; - } - return $varref; - } - else if ($include_last_iterator) - { - return '$_'. $blocks[$blockcount] . '_val'; - } - else - { - return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']'; - } - } -} - stream_filter_register('phpbb_template', 'phpbb_template_filter'); /** diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php new file mode 100644 index 0000000000..1c64cdb8da --- /dev/null +++ b/phpBB/includes/template/filter.php @@ -0,0 +1,848 @@ +'; + + const REGEX_TOKENS = '~|{((?:[a-z_][a-z_0-9]+\.)*\\$?[A-Z][A-Z_0-9]+)}~'; + + /** + * @var array + */ + private $block_names = array(); + + /** + * @var array + */ + private $block_else_level = array(); + + /** + * @var string + */ + private $chunk; + + /** + * @var bool + */ + private $in_php; + + public function filter($in, $out, &$consumed, $closing) + { + $written = false; + $first = false; + + while ($bucket = stream_bucket_make_writeable($in)) + { + $consumed += $bucket->datalen; + + $data = $this->chunk . $bucket->data; + $last_nl = strrpos($data, "\n"); + $this->chunk = substr($data, $last_nl); + $data = substr($data, 0, $last_nl); + + if (!strlen($data)) + { + continue; + } + + $written = true; + + $data = $this->compile($data); + if (!$first) + { + $data = $this->prepend_preamble($data); + $first = false; + } + $bucket->data = $data; + $bucket->datalen = strlen($bucket->data); + stream_bucket_append($out, $bucket); + } + + if ($closing && strlen($this->chunk)) + { + $written = true; + $bucket = stream_bucket_new($this->stream, $this->compile($this->chunk)); + stream_bucket_append($out, $bucket); + } + + return $written ? PSFS_PASS_ON : PSFS_FEED_ME; + } + + public function onCreate() + { + $this->chunk = ''; + $this->in_php = false; + return true; + } + + private function compile($data) + { + $block_start_in_php = $this->in_php; + + $data = preg_replace('#<(?:[\\?%]|script)#s', '', $data); + $data = preg_replace_callback(self::REGEX_TOKENS, array($this, 'replace'), $data); + + global $config; + + // Remove php + if (!$config['tpl_allow_php']) + { + if ($block_start_in_php + && $this->in_php + && strpos($data, '') === false + && strpos($data, '') === false) + { + // This is just php code + return ''; + } + $data = preg_replace('~^.*?~', '', $data); + $data = preg_replace('~.*?~', '', $data); + $data = preg_replace('~.*?$~', '', $data); + } + + /* + Preserve whitespace. + PHP removes a newline after the closing tag (if it's there). This is by design. + + + Consider the following template: + + + some content + + + If we were to simply preserve all whitespace, we could simply replace all "?>" tags + with "?>\n". + Doing that, would add additional newlines to the compiled tempalte in place of the + IF and ENDIF statements. These newlines are unwanted (and one is conditional). + The IF and ENDIF are usually on their own line for ease of reading. + + This replacement preserves newlines only for statements that aren't the only statement on a line. + It will NOT preserve newlines at the end of statements in the above examle. + It will preserve newlines in situations like: + + inline content + + + */ + + $data = preg_replace('~(?).)+(?)$~m', "$1\n", $data); + $data = str_replace('/**/?>', "?>\n", $data); + $data = str_replace('?>' . $data); + return $data; + } + + private function replace($matches) + { + if ($this->in_php && $matches[1] != 'ENDPHP') + { + return ''; + } + + if (isset($matches[3])) + { + return $this->compile_var_tags($matches[0]); + } + + global $config; + + switch ($matches[1]) + { + case 'BEGIN': + $this->block_else_level[] = false; + return 'compile_tag_block($matches[2]) . ' ?>'; + break; + + case 'BEGINELSE': + $this->block_else_level[sizeof($this->block_else_level) - 1] = true; + return ''; + break; + + case 'END': + array_pop($this->block_names); + return 'block_else_level)) ? '}' : '}}') . ' ?>'; + break; + + case 'IF': + return 'compile_tag_if($matches[2], false) . ' ?>'; + break; + + case 'ELSE': + return ''; + break; + + case 'ELSEIF': + return 'compile_tag_if($matches[2], true) . ' ?>'; + break; + + case 'ENDIF': + return ''; + break; + + case 'DEFINE': + return 'compile_tag_define($matches[2], true) . ' ?>'; + break; + + case 'UNDEFINE': + return 'compile_tag_define($matches[2], false) . ' ?>'; + break; + + case 'INCLUDE': + return 'compile_tag_include($matches[2]) . ' ?>'; + break; + + case 'INCLUDEPHP': + return ($config['tpl_allow_php']) ? 'compile_tag_include_php($matches[2]) . ' ?>' : ''; + break; + + case 'PHP': + if ($config['tpl_allow_php']) + { + $this->in_php = true; + return ''; + break; + + case 'ENDPHP': + if ($config['tpl_allow_php']) + { + $this->in_php = false; + return ' ?>'; + } + return ''; + break; + + default: + return $matches[0]; + break; + + } + return ''; + } + + /** + * Compile variables + */ + private function compile_var_tags(&$text_blocks) + { + // change template varrefs into PHP varrefs + $varrefs = array(); + + // This one will handle varrefs WITH namespaces + preg_match_all('#\{((?:' . self::REGEX_NS . '\.)+)(\$)?(' . self::REGEX_VAR . ')\}#', $text_blocks, $varrefs, PREG_SET_ORDER); + + foreach ($varrefs as $var_val) + { + $namespace = $var_val[1]; + $varname = $var_val[3]; + $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]); + + $text_blocks = str_replace($var_val[0], $new, $text_blocks); + } + + // Handle special language tags L_ and LA_ + $this->compile_language_tags($text_blocks); + + // This will handle the remaining root-level varrefs + $text_blocks = preg_replace('#\{(' . self::REGEX_VAR . ')\}#', "", $text_blocks); + $text_blocks = preg_replace('#\{\$(' . self::REGEX_VAR . ')\}#', "", $text_blocks); + + return $text_blocks; + } + + /** + * Handles special language tags L_ and LA_ + */ + private function compile_language_tags(&$text_blocks) + { + // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array + if (strpos($text_blocks, '{L_') !== false) + { + $text_blocks = preg_replace('#\{L_(' . self::REGEX_VAR . ')\}#', "", $text_blocks); + } + + // Handle addslashed language variables prefixed with LA_ + // If a template variable already exist, it will be used in favor of it... + if (strpos($text_blocks, '{LA_') !== false) + { + $text_blocks = preg_replace('#\{LA_(' . self::REGEX_VAR . '+)\}#', "", $text_blocks); + } + } + + /** + * Compile blocks + */ + private function compile_tag_block($tag_args) + { + $no_nesting = false; + + // Is the designer wanting to call another loop in a loop? + // + // + // + // + // 'loop2' is actually on the same nesting level as 'loop' you assign + // variables to it with template->assign_block_vars('loop2', array(...)) + if (strpos($tag_args, '!') === 0) + { + // Count the number if ! occurrences (not allowed in vars) + $no_nesting = substr_count($tag_args, '!'); + $tag_args = substr($tag_args, $no_nesting); + } + + // Allow for control of looping (indexes start from zero): + // foo(2) : Will start the loop on the 3rd entry + // foo(-2) : Will start the loop two entries from the end + // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth + // foo(3,-4) : Will start the loop on the fourth entry and end it four from last + $match = array(); + + if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match)) + { + $tag_args = $match[1]; + + if ($match[2] < 0) + { + $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')'; + } + else + { + $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')'; + } + + if (!isset($match[3]) || strlen($match[3]) < 1 || $match[3] == -1) + { + $loop_end = '$_' . $tag_args . '_count'; + } + else if ($match[3] >= 0) + { + $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')'; + } + else //if ($match[3] < -1) + { + $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1); + } + } + else + { + $loop_start = 0; + $loop_end = '$_' . $tag_args . '_count'; + } + + $tag_template_php = ''; + array_push($this->block_names, $tag_args); + + if ($no_nesting !== false) + { + // We need to implode $no_nesting times from the end... + $block = array_slice($this->block_names, -$no_nesting); + } + else + { + $block = $this->block_names; + } + + if (sizeof($block) < 2) + { + // Block is not nested. + $tag_template_php = '$_' . $tag_args . "_count = (isset(\$_tpldata['$tag_args'])) ? sizeof(\$_tpldata['$tag_args']) : 0;"; + $varref = "\$_tpldata['$tag_args']"; + } + else + { + // This block is nested. + // Generate a namespace string for this block. + $namespace = implode('.', $block); + + // Get a reference to the data array for this block that depends on the + // current indices of all parent blocks. + $varref = $this->generate_block_data_ref($namespace, false); + + // Create the for loop code to iterate over this block. + $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;'; + } + + $tag_template_php .= 'if ($_' . $tag_args . '_count) {'; + + /** + * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory + * + * if (!$offset) + * { + * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){'; + * } + * + */ + + $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){'; + $tag_template_php .= '$_' . $tag_args . '_val = &' . $varref . '[$_' . $tag_args . '_i];'; + + return $tag_template_php; + } + + /** + * Compile a general expression - much of this is from Smarty with + * some adaptions for our block level methods + */ + private function compile_expression($tag_args) + { + $match = array(); + preg_match_all('/(?: + "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | + \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | + [(),] | + [^\s(),]+)/x', $tag_args, $match); + + $tokens = $match[0]; + $is_arg_stack = array(); + + for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) + { + $token = &$tokens[$i]; + + switch ($token) + { + case '!==': + case '===': + case '<<': + case '>>': + case '|': + case '^': + case '&': + case '~': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '@': + break; + + case '==': + case 'eq': + $token = '=='; + break; + + case '!=': + case '<>': + case 'ne': + case 'neq': + $token = '!='; + break; + + case '<': + case 'lt': + $token = '<'; + break; + + case '<=': + case 'le': + case 'lte': + $token = '<='; + break; + + case '>': + case 'gt': + $token = '>'; + break; + + case '>=': + case 'ge': + case 'gte': + $token = '>='; + break; + + case '&&': + case 'and': + $token = '&&'; + break; + + case '||': + case 'or': + $token = '||'; + break; + + case '!': + case 'not': + $token = '!'; + break; + + case '%': + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; + $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens); + + $i = $is_arg_start; + + // no break + + default: + $varrefs = array(); + if (preg_match('#^((?:' . self::REGEX_NS . '\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs)) + { + if (!empty($varrefs[1])) + { + $namespace = substr($varrefs[1], 0, -1); + $dot_pos = strrchr($namespace, '.'); + if ($dot_pos !== false) + { + $namespace = substr($dot_pos, 1); + } + + // S_ROW_COUNT is deceptive, it returns the current row number not the number of rows + // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM + switch ($varrefs[3]) + { + case 'S_ROW_NUM': + case 'S_ROW_COUNT': + $token = "\$_${namespace}_i"; + break; + + case 'S_NUM_ROWS': + $token = "\$_${namespace}_count"; + break; + + case 'S_FIRST_ROW': + $token = "(\$_${namespace}_i == 0)"; + break; + + case 'S_LAST_ROW': + $token = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; + break; + + case 'S_BLOCK_NAME': + $token = "'$namespace'"; + break; + + default: + $token = $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']'; + $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; + break; + } + } + else + { + $token = ($varrefs[2]) ? '$_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$_rootref[\'' . $varrefs[3] . '\']'; + $token = '(isset(' . $token . ') ? ' . $token . ' : null)'; + } + + } + else if (preg_match('#^\.((?:' . self::REGEX_NS . '\.?)+)$#s', $token, $varrefs)) + { + // Allow checking if loops are set with .loopname + // It is also possible to check the loop count by doing for example + $blocks = explode('.', $varrefs[1]); + + // If the block is nested, we have a reference that we can grab. + // If the block is not nested, we just go and grab the block from _tpldata + if (sizeof($blocks) > 1) + { + $block = array_pop($blocks); + $namespace = implode('.', $blocks); + $varref = $this->generate_block_data_ref($namespace, true); + + // Add the block reference for the last child. + $varref .= "['" . $block . "']"; + } + else + { + $varref = '$_tpldata'; + + // Add the block reference for the last child. + $varref .= "['" . $blocks[0] . "']"; + } + $token = "(isset($varref) ? sizeof($varref) : 0)"; + } + + break; + } + } + + return $tokens; + } + + + private function compile_tag_if($tag_args, $elseif) + { + $tokens = $this->compile_expression($tag_args); + + $tpl = ($elseif) ? '} else if (' : 'if ('; + + $tpl .= implode(' ', $tokens); + $tpl .= ') { '; + + return $tpl; + } + + /** + * Compile DEFINE tags + */ + private function compile_tag_define($tag_args, $op) + { + $match = array(); + preg_match('#^((?:' . self::REGEX_NS . '\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (.*?))?$#', $tag_args, $match); + + if (empty($match[2]) || (!isset($match[3]) && $op)) + { + return ''; + } + + if (!$op) + { + return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');'; + } + + $parsed_statement = implode(' ', $this->compile_expression($match[3])); + + return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $parsed_statement . ';'; + } + + /** + * Compile INCLUDE tag + */ + private function compile_tag_include($tag_args) + { + return "\$_template->_tpl_include('$tag_args');"; + } + + /** + * Compile INCLUDE_PHP tag + */ + private function compile_tag_include_php($tag_args) + { + return "\$_template->_php_include('$tag_args');"; + } + + /** + * parse expression + * This is from Smarty + */ + private function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') + { + $negate_expr = true; + $expr_type = array_shift($tokens); + } + else + { + $expr_type = $first_token; + } + + switch ($expr_type) + { + case 'even': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(($is_arg / $expr_arg) & 1)"; + } + else + { + $expr = "!($is_arg & 1)"; + } + break; + + case 'odd': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(($is_arg / $expr_arg) & 1)"; + } + else + { + $expr = "($is_arg & 1)"; + } + break; + + case 'div': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') + { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % $expr_arg)"; + } + break; + } + + if ($negate_expr) + { + if ($expr[0] == '!') + { + // Negated expression, de-negate it. + $expr = substr($expr, 1); + } + else + { + $expr = "!($expr)"; + } + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + /** + * Generates a reference to the given variable inside the given (possibly nested) + * block namespace. This is a string of the form: + * ' . $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' + * It's ready to be inserted into an "echo" line in one of the templates. + * + * @param string $namespace Namespace to access (expects a trailing "." on the namespace) + * @param string $varname Variable name to use + * @param bool $echo If true return an echo statement, otherwise a reference to the internal variable + * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable + * @return string Code to access variable or echo it if $echo is true + */ + private function generate_block_varref($namespace, $varname, $echo = true, $defop = false) + { + // Strip the trailing period. + $namespace = substr($namespace, 0, -1); + + $expr = true; + $isset = false; + + // S_ROW_COUNT is deceptive, it returns the current row number now the number of rows + // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM + switch ($varname) + { + case 'S_ROW_NUM': + case 'S_ROW_COUNT': + $varref = "\$_${namespace}_i"; + break; + + case 'S_NUM_ROWS': + $varref = "\$_${namespace}_count"; + break; + + case 'S_FIRST_ROW': + $varref = "(\$_${namespace}_i == 0)"; + break; + + case 'S_LAST_ROW': + $varref = "(\$_${namespace}_i == \$_${namespace}_count - 1)"; + break; + + case 'S_BLOCK_NAME': + $varref = "'$namespace'"; + break; + + default: + // Get a reference to the data block for this namespace. + $varref = $this->generate_block_data_ref($namespace, true, $defop); + // Prepend the necessary code to stick this in an echo line. + + // Append the variable reference. + $varref .= "['$varname']"; + + $expr = false; + $isset = true; + break; + } + // @todo Test the !$expr more + $varref = ($echo) ? '' : (($expr || isset($varref)) ? $varref : ''); + + return $varref; + } + + /** + * Generates a reference to the array of data values for the given + * (possibly nested) block namespace. This is a string of the form: + * $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] + * + * @param string $blockname Block to access (does not expect a trailing "." on the blockname) + * @param bool $include_last_iterator If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. + * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable + * @return string Code to access variable + */ + private function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) + { + // Get an array of the blocks involved. + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + // DEFINE is not an element of any referenced variable, we must use _tpldata to access it + if ($defop) + { + $varref = '$_tpldata[\'DEFINE\']'; + // Build up the string with everything but the last child. + for ($i = 0; $i < $blockcount; $i++) + { + $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]'; + } + // Add the block reference for the last child. + $varref .= "['" . $blocks[$blockcount] . "']"; + // Add the iterator for the last child if requried. + if ($include_last_iterator) + { + $varref .= '[$_' . $blocks[$blockcount] . '_i]'; + } + return $varref; + } + else if ($include_last_iterator) + { + return '$_'. $blocks[$blockcount] . '_val'; + } + else + { + return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']'; + } + } +} -- cgit v1.2.1 From 7d911e0bc1475ee769bfd3849d1eca6db7cc95d2 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Fri, 13 May 2011 10:54:23 -0400 Subject: [feature/template-engine] Delete @version everywhere. This is not used since the switch to git. PHPBB3-9726 --- phpBB/includes/template.php | 1 - phpBB/includes/template/compile.php | 1 - phpBB/includes/template/context.php | 1 - phpBB/includes/template/filter.php | 1 - phpBB/includes/template/renderer.php | 1 - phpBB/includes/template/renderer_eval.php | 1 - phpBB/includes/template/renderer_include.php | 1 - 7 files changed, 7 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 5fb0f41311..e99b9a8c6c 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -2,7 +2,6 @@ /** * * @package phpBB3 -* @version $Id$ * @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc * @license http://opensource.org/licenses/gpl-license.php GNU Public License * diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 246c83a010..837af1df05 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -2,7 +2,6 @@ /** * * @package phpBB3 -* @version $Id$ * @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc * @license http://opensource.org/licenses/gpl-license.php GNU Public License * diff --git a/phpBB/includes/template/context.php b/phpBB/includes/template/context.php index 3c0dceb981..169add036e 100644 --- a/phpBB/includes/template/context.php +++ b/phpBB/includes/template/context.php @@ -2,7 +2,6 @@ /** * * @package phpBB3 -* @version $Id$ * @copyright (c) 2011 phpBB Group * @license http://opensource.org/licenses/gpl-license.php GNU Public License * diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 1c64cdb8da..2332a8281e 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -2,7 +2,6 @@ /** * * @package phpBB3 -* @version $Id$ * @copyright (c) 2011 phpBB Group, sections (c) 2001 ispi of Lincoln Inc * @license http://opensource.org/licenses/gpl-license.php GNU Public License * diff --git a/phpBB/includes/template/renderer.php b/phpBB/includes/template/renderer.php index 0af2d94bb6..c15252fd83 100644 --- a/phpBB/includes/template/renderer.php +++ b/phpBB/includes/template/renderer.php @@ -2,7 +2,6 @@ /** * * @package phpBB3 -* @version $Id$ * @copyright (c) 2011 phpBB Group * @license http://opensource.org/licenses/gpl-license.php GNU Public License * diff --git a/phpBB/includes/template/renderer_eval.php b/phpBB/includes/template/renderer_eval.php index f3365ff8a7..6cbcf5ce40 100644 --- a/phpBB/includes/template/renderer_eval.php +++ b/phpBB/includes/template/renderer_eval.php @@ -2,7 +2,6 @@ /** * * @package phpBB3 -* @version $Id$ * @copyright (c) 2011 phpBB Group * @license http://opensource.org/licenses/gpl-license.php GNU Public License * diff --git a/phpBB/includes/template/renderer_include.php b/phpBB/includes/template/renderer_include.php index 28a8027df3..0e05630d55 100644 --- a/phpBB/includes/template/renderer_include.php +++ b/phpBB/includes/template/renderer_include.php @@ -2,7 +2,6 @@ /** * * @package phpBB3 -* @version $Id$ * @copyright (c) 2011 phpBB Group * @license http://opensource.org/licenses/gpl-license.php GNU Public License * -- cgit v1.2.1 From 6ae5a64f6c12937367ad56cac5e38104b445c780 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 19 May 2011 12:18:16 -0400 Subject: [feature/template-engine] Fixed absolute path PHP includes, added test. PHPBB3-9726 --- phpBB/includes/template.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index e99b9a8c6c..935605b12a 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -529,7 +529,14 @@ class phpbb_template */ public function _php_include($filename) { - $file = $this->phpbb_root_path . $filename; + if (is_absolute($filename)) + { + $file = $filename; + } + else + { + $file = $this->phpbb_root_path . $filename; + } if (!file_exists($file)) { -- cgit v1.2.1 From f231590c7b39a8e8503bcc3a7c9db593dde339dd Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Thu, 19 May 2011 12:31:06 -0400 Subject: [ticket/10156] Fix new cron on windows. PHPBB3-10156 --- phpBB/includes/cron/manager.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/cron/manager.php b/phpBB/includes/cron/manager.php index 21dcb91695..31be1a69cb 100644 --- a/phpBB/includes/cron/manager.php +++ b/phpBB/includes/cron/manager.php @@ -73,6 +73,14 @@ class phpbb_cron_manager */ public function __construct($task_path, $phpEx, phpbb_cache_driver_interface $cache = null) { + if (DIRECTORY_SEPARATOR != '/') + { + // Need this on some platforms since the code elsewhere uses / + // to separate directory components, but PHP iterators return + // paths with platform-specific directory separators. + $task_path = str_replace('/', DIRECTORY_SEPARATOR, $task_path); + } + $this->task_path = $task_path; $this->phpEx = $phpEx; $this->cache = $cache; @@ -116,9 +124,9 @@ class phpbb_cron_manager $file = preg_replace('#^' . preg_quote($this->task_path, '#') . '#', '', $fileinfo->getPathname()); // skip directories and files direclty in the task root path - if ($fileinfo->isFile() && strpos($file, '/') !== false) + if ($fileinfo->isFile() && strpos($file, DIRECTORY_SEPARATOR) !== false) { - $task_name = str_replace('/', '_', substr($file, 0, -$ext_length)); + $task_name = str_replace(DIRECTORY_SEPARATOR, '_', substr($file, 0, -$ext_length)); if (substr($file, -$ext_length) == $ext && $this->is_valid_name($task_name)) { $task_names[] = 'phpbb_cron_task_' . $task_name; -- cgit v1.2.1 From 8fa44cc3b9778f84ca20eab1c1d404c4f848eab4 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 19 Oct 2010 17:06:23 +0200 Subject: [ticket/8542] Display custom profile fields in private messages Introduce an option to display the cpf in the PM view. PHPBB3-8542 --- phpBB/includes/acp/acp_board.php | 2 ++ phpBB/includes/acp/acp_profile.php | 6 ++++- phpBB/includes/ucp/ucp_pm_viewmessage.php | 43 +++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 6821073749..54cdcb8e32 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -96,6 +96,7 @@ class acp_board 'load_moderators' => array('lang' => 'YES_MODERATORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_jumpbox' => array('lang' => 'YES_JUMPBOX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'load_cpf_pm' => array('lang' => 'LOAD_CPF_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), @@ -327,6 +328,7 @@ class acp_board 'legend3' => 'CUSTOM_PROFILE_FIELDS', 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'load_cpf_pm' => array('lang' => 'LOAD_CPF_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index ca6a5f04d2..a18a01c44a 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -370,6 +370,7 @@ class acp_profile 'field_show_profile'=> 0, 'field_no_view' => 0, 'field_show_on_reg' => 0, + 'field_show_on_pm' => 0, 'field_show_on_vt' => 0, 'lang_name' => utf8_normalize_nfc(request_var('field_ident', '', true)), 'lang_explain' => '', @@ -381,7 +382,7 @@ class acp_profile // $exclude contains the data we gather in each step $exclude = array( - 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_vt', 'field_required', 'field_hide', 'field_show_profile', 'field_no_view'), + 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_pm', 'field_show_on_vt', 'field_required', 'field_hide', 'field_show_profile', 'field_no_view'), 2 => array('field_length', 'field_maxlen', 'field_minlen', 'field_validation', 'field_novalue', 'field_default_value'), 3 => array('l_lang_name', 'l_lang_explain', 'l_lang_default_value', 'l_lang_options') ); @@ -407,6 +408,7 @@ class acp_profile $visibility_ary = array( 'field_required', 'field_show_on_reg', + 'field_show_on_pm', 'field_show_on_vt', 'field_show_profile', 'field_hide', @@ -734,6 +736,7 @@ class acp_profile 'S_STEP_ONE' => true, 'S_FIELD_REQUIRED' => ($cp->vars['field_required']) ? true : false, 'S_SHOW_ON_REG' => ($cp->vars['field_show_on_reg']) ? true : false, + 'S_SHOW_ON_PM' => ($cp->vars['field_show_on_pm']) ? true : false, 'S_SHOW_ON_VT' => ($cp->vars['field_show_on_vt']) ? true : false, 'S_FIELD_HIDE' => ($cp->vars['field_hide']) ? true : false, 'S_SHOW_PROFILE' => ($cp->vars['field_show_profile']) ? true : false, @@ -1050,6 +1053,7 @@ class acp_profile 'field_validation' => $cp->vars['field_validation'], 'field_required' => $cp->vars['field_required'], 'field_show_on_reg' => $cp->vars['field_show_on_reg'], + 'field_show_on_pm' => $cp->vars['field_show_on_pm'], 'field_show_on_vt' => $cp->vars['field_show_on_vt'], 'field_hide' => $cp->vars['field_hide'], 'field_show_profile' => $cp->vars['field_show_profile'], diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index 74a32a68c9..8b288f5de1 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -59,6 +59,18 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) $bbcode = new bbcode($message_row['bbcode_bitfield']); } + // Load the custom profile fields + if ($config['load_cpf_pm']) + { + if (!class_exists('custom_profile')) + { + include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); + } + $cp = new custom_profile(); + + $profile_fields = $cp->generate_profile_fields_template('grab', $author_id); + } + // Assign TO/BCC Addresses to template write_pm_addresses(array('to' => $message_row['to_address'], 'bcc' => $message_row['bcc_address']), $author_id); @@ -174,6 +186,25 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) $bbcode_status = ($config['allow_bbcode'] && $config['auth_bbcode_pm'] && $auth->acl_get('u_pm_bbcode')) ? true : false; + // Get the profile fields template data + $cp_row = array(); + if ($config['load_cpf_pm'] && isset($profile_fields[$author_id])) + { + // Filter the fields we don't want to show + foreach ($profile_fields[$author_id] as $used_ident => $profile_field) + { + if (!$profile_field['data']['field_show_on_pm']) + { + unset($profile_fields[$author_id][$used_ident]); + } + } + + if (isset($profile_fields[$author_id])) + { + $cp_row = $cp->generate_profile_fields_template('show', false, $profile_fields[$author_id]); + } + } + $template->assign_vars(array( 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), @@ -232,11 +263,23 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'S_SPECIAL_FOLDER' => in_array($folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)), 'S_PM_RECIPIENTS' => $num_recipients, 'S_BBCODE_ALLOWED' => ($bbcode_status) ? 1 : 0, + 'S_CUSTOM_FIELDS' => (!empty($cp_row['row'])) ? true : false, 'U_PRINT_PM' => ($config['print_pm'] && $auth->acl_get('u_pm_printpm')) ? "$url&f=$folder_id&p=" . $message_row['msg_id'] . "&view=print" : '', 'U_FORWARD_PM' => ($config['forward_pm'] && $auth->acl_get('u_sendpm') && $auth->acl_get('u_pm_forward')) ? "$url&mode=compose&action=forward&f=$folder_id&p=" . $message_row['msg_id'] : '') ); + // Display the custom profile fields + if (!empty($cp_row['row'])) + { + $template->assign_vars($cp_row['row']); + + foreach ($cp_row['blockrow'] as $cp_block_row) + { + $template->assign_block_vars('custom_fields', $cp_block_row); + } + } + // Display not already displayed Attachments for this post, we already parsed them. ;) if (isset($attachments) && sizeof($attachments)) { -- cgit v1.2.1 From 9b62500a1068fd9c17409e435b53a33bb1cf6838 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 22 May 2011 06:48:59 -0400 Subject: [ticket/10188] Use ob_get_level in msg_handler for output buffering check. Output buffering may be enabled via various approaches, among them: * output_buffering in php.ini; * output_handler in php.ini enables output_buffering; * ob_start call. ob_get_level allows us to query php runtime for the actual output buffering status. PHPBB3-10188 --- phpBB/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index ceaf426850..9f1d39118a 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3743,7 +3743,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false) { // flush the content, else we get a white page if output buffering is on - if ((int) @ini_get('output_buffering') === 1 || strtolower(@ini_get('output_buffering')) === 'on') + if (ob_get_level() > 0) { @ob_flush(); } -- cgit v1.2.1 From 44cc8153cdfedda1d0733655bc13e5e9beac3431 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 22 May 2011 07:16:40 -0400 Subject: [ticket/10191] Use ob_get_level in exit_handler for output buffering check. Calling flush() when output buffering is enabled causes output to be duplicated. Besides phpBB enabling output buffering for gzip compression, output buffering may be enabled externally to phpBB via output_handler or output_buffering directives in php.ini. Use ob_get_level to determine whether output buffering is active and call ob_flush in that case. PHPBB3-10191 --- phpBB/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index ceaf426850..22373f6d63 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -4719,7 +4719,7 @@ function exit_handler() } // As a pre-caution... some setups display a blank page if the flush() is not there. - (empty($config['gzip_compress'])) ? @flush() : @ob_flush(); + (ob_get_level() > 0) ? @ob_flush() : @flush(); exit; } -- cgit v1.2.1 From 67449f8f1b1b9eff8430a77d16d6ee2dac1210d9 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 23 May 2011 12:01:11 +0200 Subject: [ticket/10158] Only view "Return to" links if they are useful. PHPBB3-10158 --- phpBB/includes/ucp/ucp_pm_compose.php | 42 ++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index 6ea702570e..78b2e7a348 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -135,6 +135,7 @@ function compose_pm($id, $mode, $action, $user_folders = array()) } $sql = ''; + $folder_id = 0; // What is all this following SQL for? Well, we need to know // some basic information in all cases before we do anything. @@ -744,18 +745,43 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $inbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'); $outbox_folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=outbox'); - $folder_return_message = ''; - $return_message_url = $inbox_folder_url; - if ($folder_id && isset($user_folders[$folder_id])) + $folder_url = ''; + if (($folder_id > 0) && isset($user_folders[$folder_id])) { - $return_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id); - $folder_return_message = '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user_folders[$folder_id]['folder_name']); + $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id); } $message = $user->lang['MESSAGE_STORED'] . '

' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '', ''); - $message .= $folder_return_message; - $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_INBOX']); - $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_OUTBOX']); + switch ($action) + { + case 'post': + case 'edit': + if ($folder_url) + { + $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user_folders[$folder_id]['folder_name']); + $message .= '

' . sprintf($user->lang['CLICK_GOTO_FOLDER'], '', '', $user->lang['PM_OUTBOX']); + } + else + { + $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_OUTBOX']); + } + break; + + case 'quote': + case 'quotepost': + case 'reply': + case 'forward': + if ($folder_url) + { + $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user_folders[$folder_id]['folder_name']); + $message .= '

' . sprintf($user->lang['CLICK_GOTO_FOLDER'], '', '', $user->lang['PM_INBOX']); + } + else + { + $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_INBOX']); + } + break; + } meta_refresh(3, $return_message_url); trigger_error($message); -- cgit v1.2.1 From 83dfe0d22c71df8e5701c812d304ef8918c3190f Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 26 May 2011 10:43:14 +0200 Subject: [ticket/10195] Return false in session::check_dnsbl() when IPv6 is passed. There is no support for IPv6 addresses in the blacklists we check right now. PHPBB3-10195 --- phpBB/includes/session.php | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index d803f8d799..2181375dc1 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -1238,6 +1238,12 @@ class session $ip = $this->ip; } + // Neither Spamhaus nor Spamcop supports IPv6 addresses. + if (strpos($ip, ':') !== false) + { + return false; + } + $dnsbl_check = array( 'sbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=', ); -- cgit v1.2.1 From ebe83769e6efff249f94e5337dcd8fd16593a290 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Thu, 2 Jun 2011 01:45:12 +0200 Subject: [ticket/9685] Consistently name the new sql_buffer_nested_transactions function PHPBB3-9685 --- phpBB/includes/db/dbal.php | 2 +- phpBB/includes/db/mssqlnative.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php index d7860fc8bc..2f9619c8ea 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/dbal.php @@ -246,7 +246,7 @@ class dbal * * @return bool Whether buffering is required. */ - function sql_buffer_nested_transaction() + function sql_buffer_nested_transactions() { return false; } diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index e057e7fe74..6810562d17 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -261,7 +261,7 @@ class dbal_mssqlnative extends dbal /** * {@inheritDoc} */ - function sql_buffer_nested_transaction() + function sql_buffer_nested_transactions() { return true; } -- cgit v1.2.1 From 324c913ac9eb3ce158d1c735ee49b62a06d8327b Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Thu, 2 Jun 2011 06:24:28 +0200 Subject: [ticket/9950] Use actual language instead of user's language in overall header PHPBB3-9950 --- phpBB/includes/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 791aa09010..2d9d2c225f 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -4529,7 +4529,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'T_TEMPLATE_PATH' => "{$web_path}styles/" . $user->theme['template_path'] . '/template', 'T_SUPER_TEMPLATE_PATH' => (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? "{$web_path}styles/" . $user->theme['template_inherit_path'] . '/template' : "{$web_path}styles/" . $user->theme['template_path'] . '/template', 'T_IMAGESET_PATH' => "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset', - 'T_IMAGESET_LANG_PATH' => "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->data['user_lang'], + 'T_IMAGESET_LANG_PATH' => "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->lang_name, 'T_IMAGES_PATH' => "{$web_path}images/", 'T_SMILIES_PATH' => "{$web_path}{$config['smilies_path']}/", 'T_AVATAR_PATH' => "{$web_path}{$config['avatar_path']}/", @@ -4537,7 +4537,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'T_ICONS_PATH' => "{$web_path}{$config['icons_path']}/", 'T_RANKS_PATH' => "{$web_path}{$config['ranks_path']}/", 'T_UPLOAD_PATH' => "{$web_path}{$config['upload_path']}/", - 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&lang=' . $user->data['user_lang']), + 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&lang=' . $user->lang_name), 'T_STYLESHEET_NAME' => $user->theme['theme_name'], 'T_THEME_NAME' => $user->theme['theme_path'], -- cgit v1.2.1 From 7b10f859decdb5d97ffe97e647db52f29f4661f8 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Thu, 2 Jun 2011 08:45:48 +0200 Subject: [ticket/10005] Add validation of dropdown custom profile field values PHPBB3-10005 --- phpBB/includes/functions_profile_fields.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php index 78fe049f40..1eae2a9ad6 100644 --- a/phpBB/includes/functions_profile_fields.php +++ b/phpBB/includes/functions_profile_fields.php @@ -149,7 +149,18 @@ class custom_profile case FIELD_DROPDOWN: $field_value = (int) $field_value; - + + // retrieve option lang data if necessary + if (!isset($this->options_lang[$field_data['field_id']]) || !isset($this->options_lang[$field_data['field_id']][$field_data['lang_id']]) || !sizeof($this->options_lang[$file_data['field_id']][$field_data['lang_id']])) + { + $this->get_option_lang($field_data['field_id'], $field_data['lang_id'], FIELD_DROPDOWN, false); + } + + if (!isset($this->options_lang[$field_data['field_id']][$field_data['lang_id']][$field_value])) + { + return 'FIELD_INVALID_VALUE'; + } + if ($field_value == $field_data['field_novalue'] && $field_data['field_required']) { return 'FIELD_REQUIRED'; @@ -302,6 +313,7 @@ class custom_profile switch ($cp_result) { case 'FIELD_INVALID_DATE': + case 'FIELD_INVALID_VALUE': case 'FIELD_REQUIRED': $error = sprintf($user->lang[$cp_result], $row['lang_name']); break; -- cgit v1.2.1 From d270f736e3a553042879b9a7918d2e9bd513c659 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Thu, 2 Jun 2011 09:48:49 +0200 Subject: [ticket/7057] Remove trailing whitespace in functions.php PHPBB3-7057 --- phpBB/includes/functions.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 9a8cc5d6b3..7cbf314309 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3434,7 +3434,7 @@ function get_preg_expression($mode) * Depends on whether installed PHP version supports unicode properties * * @param string $word word template to be replaced -* @param bool $use_unicode whether or not to take advantage of PCRE supporting unicode +* @param bool $use_unicode whether or not to take advantage of PCRE supporting unicode * * @return string $preg_expr regex to use with word censor */ @@ -3544,7 +3544,7 @@ function phpbb_checkdnsrr($host, $type = 'MX') // but until 5.3.3 it only works for MX records // See: http://bugs.php.net/bug.php?id=51844 - // Call checkdnsrr() if + // Call checkdnsrr() if // we're looking for an MX record or // we're not on Windows or // we're running a PHP version where #51844 has been fixed @@ -3564,7 +3564,7 @@ function phpbb_checkdnsrr($host, $type = 'MX') // dns_get_record() is available since PHP 5; since PHP 5.3 also on Windows, // but on Windows it does not work reliable for AAAA records before PHP 5.3.1 - // Call dns_get_record() if + // Call dns_get_record() if // we're not looking for an AAAA record or // we're not on Windows or // we're running a PHP version where AAAA lookups work reliable @@ -3594,7 +3594,7 @@ function phpbb_checkdnsrr($host, $type = 'MX') foreach ($resultset as $result) { if ( - isset($result['host']) && $result['host'] == $host && + isset($result['host']) && $result['host'] == $host && isset($result['type']) && $result['type'] == $type ) { -- cgit v1.2.1 From 6e8b59dce32032cafeb39c3dc1dfe16e20194683 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Thu, 2 Jun 2011 09:44:02 +0200 Subject: [ticket/7057] Use GET for quicksearch and add session id to hidden fields Without sid a GET form logs a user out if they have cookies disabled. PHPBB3-7057 --- phpBB/includes/functions.php | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 7cbf314309..ded69d7150 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -4422,6 +4422,12 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 $user_lang = substr($user_lang, 0, strpos($user_lang, '-x-')); } + $s_search_hidden_fields = array(); + if ($_SID) + { + $s_search_hidden_fields['sid'] = $_SID; + } + // The following assigns all _common_ variables that may be used at any point in a template. $template->assign_vars(array( 'SITENAME' => $config['sitename'], @@ -4511,6 +4517,8 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'S_LOAD_UNREADS' => ($config['load_unreads_search'] && ($config['load_anon_lastread'] || $user->data['is_registered'])) ? true : false, + 'S_SEARCH_HIDDEN_FIELDS' => build_hidden_fields($s_search_hidden_fields), + 'T_THEME_PATH' => "{$web_path}styles/" . $user->theme['theme_path'] . '/theme', 'T_TEMPLATE_PATH' => "{$web_path}styles/" . $user->theme['template_path'] . '/template', 'T_SUPER_TEMPLATE_PATH' => (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? "{$web_path}styles/" . $user->theme['template_inherit_path'] . '/template' : "{$web_path}styles/" . $user->theme['template_path'] . '/template', -- cgit v1.2.1 From f11ef89c657b0386ea5686dd8cc35dff79690adb Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 3 Jun 2011 19:06:12 +0200 Subject: [ticket/8138] Add autocomplete="off" to acp_board and ldap settings PHPBB3-8138 --- phpBB/includes/auth/auth_ldap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/auth/auth_ldap.php b/phpBB/includes/auth/auth_ldap.php index e8c957aaa3..5dfa74ddab 100644 --- a/phpBB/includes/auth/auth_ldap.php +++ b/phpBB/includes/auth/auth_ldap.php @@ -335,7 +335,7 @@ function acp_ldap(&$new)

' . $user->lang['LDAP_PASSWORD_EXPLAIN'] . '
-
+
'; -- cgit v1.2.1 From 6b6705b852bcd2a86735fa99d00a77426bf12813 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sun, 5 Jun 2011 01:57:43 +0200 Subject: [ticket/10158] Remove some code duplication from generating the message. PHPBB3-10158 --- phpBB/includes/ucp/ucp_pm_compose.php | 38 +++++++++-------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index 78b2e7a348..05243e3d7a 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -751,37 +751,19 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id); } + $return_box_url = ($action === 'post' || $action === 'edit') ? $outbox_folder_url : $inbox_folder_url; + $return_box_lang = ($action === 'post' || $action === 'edit') ? 'PM_OUTBOX' : 'PM_INBOX'; + + $message = $user->lang['MESSAGE_STORED'] . '

' . sprintf($user->lang['VIEW_PRIVATE_MESSAGE'], '', ''); - switch ($action) - { - case 'post': - case 'edit': - if ($folder_url) - { - $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user_folders[$folder_id]['folder_name']); - $message .= '

' . sprintf($user->lang['CLICK_GOTO_FOLDER'], '', '', $user->lang['PM_OUTBOX']); - } - else - { - $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_OUTBOX']); - } - break; - case 'quote': - case 'quotepost': - case 'reply': - case 'forward': - if ($folder_url) - { - $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user_folders[$folder_id]['folder_name']); - $message .= '

' . sprintf($user->lang['CLICK_GOTO_FOLDER'], '', '', $user->lang['PM_INBOX']); - } - else - { - $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user->lang['PM_INBOX']); - } - break; + $last_click_type = 'CLICK_RETURN_FOLDER'; + if ($folder_url) + { + $message .= '

' . sprintf($user->lang['CLICK_RETURN_FOLDER'], '', '', $user_folders[$folder_id]['folder_name']); + $last_click_type = 'CLICK_GOTO_FOLDER'; } + $message .= '

' . sprintf($user->lang[$last_click_type], '', '', $user->lang[$return_box_lang]); meta_refresh(3, $return_message_url); trigger_error($message); -- cgit v1.2.1 From 26e052bb26a683bff17d86ae2beecc66ffcd93cf Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sun, 5 Jun 2011 09:52:17 +0200 Subject: [ticket/10067] Add separator to h_radio to place options on individual lines The previous mechanism for account activation resulted in two h_radio calls with identical id attributes for two elements. PHPBB3/10067 --- phpBB/includes/acp/acp_board.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 8f7d08cc8f..d38c4d58ba 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -769,18 +769,19 @@ class acp_board { global $user, $config; - $radio_ary = array(USER_ACTIVATION_DISABLE => 'ACC_DISABLE', USER_ACTIVATION_NONE => 'ACC_NONE'); - $radio_text = h_radio('config[require_activation]', $radio_ary, $value, $key); + $radio_ary = array( + USER_ACTIVATION_DISABLE => 'ACC_DISABLE', + USER_ACTIVATION_NONE => 'ACC_NONE', + ); + if ($config['email_enable']) { - $radio_ary = array(USER_ACTIVATION_SELF => 'ACC_USER', USER_ACTIVATION_ADMIN => 'ACC_ADMIN'); - // With longer labels the four options no longer fit - // onto a single line. Separate them onto two lines. - // This also requires two h_radio calls to generate HTML. - $radio_text .= '

'; - $radio_text .= h_radio('config[require_activation]', $radio_ary, $value, $key); + $radio_ary[USER_ACTIVATION_SELF] = 'ACC_USER'; + $radio_ary[USER_ACTIVATION_ADMIN] = 'ACC_ADMIN'; } + $radio_text = h_radio('config[require_activation]', $radio_ary, $value, 'require_activation', $key, '
'); + return $radio_text; } -- cgit v1.2.1 From 16ab0d8c264d88db5e3e961e66e6820b365f45ac Mon Sep 17 00:00:00 2001 From: rxu Date: Sun, 17 Apr 2011 17:58:11 +0800 Subject: [ticket/217] Multiline [url] not converted This is the second attempt parse multiline URL text, see the ticket comments. PHPBB3-217 --- phpBB/includes/message_parser.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 6951dcf820..8f5e72cbf7 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -109,13 +109,15 @@ class bbcode_firstpass extends bbcode // This array holds all bbcode data. BBCodes will be processed in this // order, so it is important to keep [code] in first position and // [quote] in second position. + // To parse multiline URL we enable dotall option setting only for URL text + // but not for link itself, thus [url][/url] is not affected. $this->bbcodes = array( 'code' => array('bbcode_id' => 8, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#uise' => "\$this->bbcode_code('\$1', '\$2')")), 'quote' => array('bbcode_id' => 0, 'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#uise' => "\$this->bbcode_quote('\$0')")), 'attachment' => array('bbcode_id' => 12, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#uise' => "\$this->bbcode_attachment('\$1', '\$2')")), 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#uise' => "\$this->bbcode_strong('\$1')")), 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#uise' => "\$this->bbcode_italic('\$1')")), - 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](.*)\[/url\]#uiUe' => "\$this->validate_url('\$2', '\$3')")), + 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](?(1)((?s).*(?-s))|(.*))\[/url\]#uiUe' => "\$this->validate_url('\$2', '\$3')")), 'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](.*)\[/img\]#uiUe' => "\$this->bbcode_img('\$1')")), 'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#uise' => "\$this->bbcode_size('\$1', '\$2')")), 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!uise' => "\$this->bbcode_color('\$1', '\$2')")), -- cgit v1.2.1 From 6585d938d2c441900d8af6d25da2433d3beec856 Mon Sep 17 00:00:00 2001 From: rxu Date: Sun, 5 Jun 2011 21:55:28 +0800 Subject: [ticket/217] Adjust patch, add tests PHPBB3-217 --- phpBB/includes/message_parser.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 8f5e72cbf7..a6a4e530f0 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -102,7 +102,7 @@ class bbcode_firstpass extends bbcode /** * Init bbcode data for later parsing */ - function bbcode_init() + function bbcode_init($no_custom_bbcode = false) { static $rowset; @@ -117,7 +117,7 @@ class bbcode_firstpass extends bbcode 'attachment' => array('bbcode_id' => 12, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#uise' => "\$this->bbcode_attachment('\$1', '\$2')")), 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#uise' => "\$this->bbcode_strong('\$1')")), 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#uise' => "\$this->bbcode_italic('\$1')")), - 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](?(1)((?s).*(?-s))|(.*))\[/url\]#uiUe' => "\$this->validate_url('\$2', '\$3')")), + 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](?(1)((?s).*(?-s))|(.*))\[/url\]#uiUe' => "\$this->validate_url('\$2', ('\$3') ? '\$3' : '\$4')")), 'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](.*)\[/img\]#uiUe' => "\$this->bbcode_img('\$1')")), 'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#uise' => "\$this->bbcode_size('\$1', '\$2')")), 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!uise' => "\$this->bbcode_color('\$1', '\$2')")), @@ -135,6 +135,11 @@ class bbcode_firstpass extends bbcode $this->parsed_items[$tag] = 0; } + if ($no_custom_bbcode) + { + return; + } + if (!is_array($rowset)) { global $db; @@ -970,7 +975,7 @@ class bbcode_firstpass extends bbcode } // Is this a link to somewhere inside this board? If so then remove the session id from the url - if (strpos($url, generate_board_url()) !== false && strpos($url, 'sid=') !== false) + if (strpos($url, @generate_board_url()) !== false && strpos($url, 'sid=') !== false) { $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}&/', '\1', $url); $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}$/', '', $url); -- cgit v1.2.1 From d44b6ba5caeafe220b4959a6de99d035fe10b4f1 Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 6 Jun 2011 00:50:53 +0800 Subject: [ticket/217] Use positive parameter statement for bbcode_init() PHPBB3-217 --- phpBB/includes/message_parser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index a6a4e530f0..9e0e61d0ba 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -102,7 +102,7 @@ class bbcode_firstpass extends bbcode /** * Init bbcode data for later parsing */ - function bbcode_init($no_custom_bbcode = false) + function bbcode_init($allow_custom_bbcode = true) { static $rowset; @@ -135,7 +135,7 @@ class bbcode_firstpass extends bbcode $this->parsed_items[$tag] = 0; } - if ($no_custom_bbcode) + if (!$allow_custom_bbcode) { return; } -- cgit v1.2.1 From 2d1e426ba745fa5b0b7666e5fe4a5fee97caccd7 Mon Sep 17 00:00:00 2001 From: Oleg Pudeyev Date: Sun, 5 Jun 2011 13:23:55 -0400 Subject: [ticket/217] Silence errors in tests, not code. Use a mock user object for testing bbcode. PHPBB3-217 --- phpBB/includes/message_parser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 9e0e61d0ba..a134fab5d3 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -975,7 +975,7 @@ class bbcode_firstpass extends bbcode } // Is this a link to somewhere inside this board? If so then remove the session id from the url - if (strpos($url, @generate_board_url()) !== false && strpos($url, 'sid=') !== false) + if (strpos($url, generate_board_url()) !== false && strpos($url, 'sid=') !== false) { $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}&/', '\1', $url); $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}$/', '', $url); -- cgit v1.2.1 From 2dee57fd43ebe1cf1f43fb0161cdd5f072eeaa63 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 10 Jun 2011 12:02:59 +0200 Subject: [ticket/9992] Adding a limit on login attempts per IP. A new table was created to save all failed login attempts with corresponding information on username, ip and useragent. By default the limit is 50 login attempts within 6 hours per IP. The limit is relatively high to avoid big problems on sites behind a reverse proxy that don't receive the forwarded-for value as REMOTE_ADDR but see all users as coming from the same IP address. But if these users run into problems a special forwarded-for option is available to limit logins by forwarded-for value instead of ip. PHPBB3-9992 --- phpBB/includes/acp/acp_board.php | 3 ++ phpBB/includes/auth.php | 2 +- phpBB/includes/auth/auth_db.php | 66 +++++++++++++++++++++++++++++++++++++--- phpBB/includes/constants.php | 1 + phpBB/includes/db/db_tools.php | 13 ++++++++ phpBB/includes/session.php | 4 +++ 6 files changed, 84 insertions(+), 5 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index d38c4d58ba..9f00145f3b 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -386,6 +386,9 @@ class acp_board 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true), + 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true), + 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true), + 'ip_login_limit_use_forwarded' => array('lang' => 'IP_LOGIN_LIMIT_USE_FORWARDED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), 'form_token_sid_guests' => array('lang' => 'FORM_SID_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), diff --git a/phpBB/includes/auth.php b/phpBB/includes/auth.php index 8324cb4977..5564de2943 100644 --- a/phpBB/includes/auth.php +++ b/phpBB/includes/auth.php @@ -908,7 +908,7 @@ class auth $method = 'login_' . $method; if (function_exists($method)) { - $login = $method($username, $password); + $login = $method($username, $password, $user->ip, $user->browser, $user->forwarded_for); // If the auth module wants us to create an empty profile do so and then treat the status as LOGIN_SUCCESS if ($login['status'] == LOGIN_SUCCESS_CREATE_PROFILE) diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index e04a6307e9..e155130e04 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -23,8 +23,21 @@ if (!defined('IN_PHPBB')) /** * Login function +* +* @param string $username +* @param string $password +* @param string $ip IP address the login is taking place from. Used to +* limit the number of login attempts per IP address. +* @param string $browser The user agent used to login +* @param string $forwarded_for X_FORWARDED_FOR header sent with login request +* @return array A associative array of the format +* array( +* 'status' => status constant +* 'error_msg' => string +* 'user_row' => array +* ) */ -function login_db(&$username, &$password) +function login_db($username, $password, $ip = '', $browser = '', $forwarded_for = '') { global $db, $config; @@ -47,13 +60,52 @@ function login_db(&$username, &$password) ); } + $username_clean = utf8_clean_string($username); + $sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; + WHERE username_clean = '" . $db->sql_escape($username_clean) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); + if (($ip && !$config['ip_login_limit_use_forwarded']) || + ($forwarded_for && $config['ip_login_limit_use_forwarded'])) + { + $sql = 'SELECT COUNT(attempt_id) AS count + FROM ' . LOGIN_ATTEMPT_TABLE . ' + WHERE attempt_time > ' . (time() - (int) $config['ip_login_limit_time']); + if ($config['ip_login_limit_use_forwarded']) + { + $sql .= " AND attempt_forwarded_for = '" . $db->sql_escape($forwarded_for) . "'"; + } + else + { + $sql .= " AND attempt_ip = '" . $db->sql_escape($ip) . "' "; + } + + $result = $db->sql_query($sql); + $attempts_row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + $attempts = $attempts_row['count']; + + $attempt_data = array( + 'attempt_ip' => $ip, + 'attempt_browser' => $browser, + 'attempt_forwarded_for' => $forwarded_for, + 'attempt_time' => time(), + 'user_id' => ($row) ? (int) $row['user_id'] : 0, + 'username' => $username, + 'username_clean' => $username_clean, + ); + $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $db->sql_build_array('INSERT', $attempt_data); + $result = $db->sql_query($sql); + } + else + { + $attempts = 0; + } + if (!$row) { return array( @@ -62,7 +114,9 @@ function login_db(&$username, &$password) 'user_row' => array('user_id' => ANONYMOUS), ); } - $show_captcha = $config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']; + + $show_captcha = ($config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']) || + ($config['ip_login_limit_max'] && $attempts >= $config['ip_login_limit_max']); // If there are too much login attempts, we need to check for an confirm image // Every auth module is able to define what to do by itself... @@ -90,7 +144,7 @@ function login_db(&$username, &$password) { $captcha->reset(); } - + } // If the password convert flag is set we need to convert it @@ -165,6 +219,10 @@ function login_db(&$username, &$password) $row['user_password'] = $hash; } + $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' + WHERE user_id = ' . $row['user_id']; + $db->sql_query($sql); + if ($row['user_login_attempts'] != 0) { // Successful, reset login attempts (the user passed all stages) diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index ea34eb8e81..b5a0aa893a 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -236,6 +236,7 @@ define('GROUPS_TABLE', $table_prefix . 'groups'); define('ICONS_TABLE', $table_prefix . 'icons'); define('LANG_TABLE', $table_prefix . 'lang'); define('LOG_TABLE', $table_prefix . 'log'); +define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts'); define('MODERATOR_CACHE_TABLE', $table_prefix . 'moderator_cache'); define('MODULES_TABLE', $table_prefix . 'modules'); define('POLL_OPTIONS_TABLE', $table_prefix . 'poll_options'); diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index 483ceee043..fdefda9e26 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -638,6 +638,19 @@ class phpbb_db_tools $sqlite = true; } + // Add tables? + if (!empty($schema_changes['add_tables'])) + { + foreach ($schema_changes['add_tables'] as $table => $table_data) + { + $result = $this->sql_create_table($table, $table_data); + if ($this->return_statements) + { + $statements = array_merge($statements, $result); + } + } + } + // Change columns? if (!empty($schema_changes['change_columns'])) { diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index ceb22c197c..69369ff72d 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -1005,6 +1005,10 @@ class session include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx); } phpbb_captcha_factory::garbage_collect($config['captcha_plugin']); + + $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' + WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']); + $db->sql_query($sql); } return; -- cgit v1.2.1 From c8828473a85a061889f58e900036ddb90f38652c Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Fri, 10 Jun 2011 18:37:29 +0200 Subject: [ticket/9992] Use sql_fetchfield for single row and single column result PHPBB3-9992 --- phpBB/includes/auth/auth_db.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index e155130e04..02c9386f33 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -85,9 +85,8 @@ function login_db($username, $password, $ip = '', $browser = '', $forwarded_for } $result = $db->sql_query($sql); - $attempts_row = $db->sql_fetchrow($result); + $attempts = (int) $db->sql_fetchfield('count'); $db->sql_freeresult($result); - $attempts = $attempts_row['count']; $attempt_data = array( 'attempt_ip' => $ip, -- cgit v1.2.1 From b5cefc400e6a8c3500b8ed5126548e3cbb727858 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Wed, 19 Jan 2011 03:47:51 +0100 Subject: [ticket/9908] Send 301 before stripping SID so bots do (hopefully) not revisit. PHPBB3-9908 --- phpBB/includes/session.php | 1 + 1 file changed, 1 insertion(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index ceb22c197c..7db319493b 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -592,6 +592,7 @@ class session // otherwise they'll index this page with the SID, duplicate content oh my! if ($bot && isset($_GET['sid'])) { + send_status_line(301, 'Moved Permanently'); redirect(build_url(array('sid'))); } -- cgit v1.2.1 From b9f4240c103734b33aeab809312fcef8e32c396e Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 11 Jun 2011 01:47:50 +0200 Subject: [ticket/10110] Remove multi-server syntax from Redis ACM. PHPBB3-10110 --- phpBB/includes/acm/acm_redis.php | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/acm/acm_redis.php b/phpBB/includes/acm/acm_redis.php index 8954b9d0e7..41533eaacb 100644 --- a/phpBB/includes/acm/acm_redis.php +++ b/phpBB/includes/acm/acm_redis.php @@ -31,12 +31,6 @@ if (!defined('PHPBB_ACM_REDIS_HOST')) define('PHPBB_ACM_REDIS_HOST', 'localhost'); } -if (!defined('PHPBB_ACM_REDIS')) -{ - //can define multiple servers with host1/port1,host2/port2 format - define('PHPBB_ACM_REDIS', PHPBB_ACM_REDIS_HOST . '/' . PHPBB_ACM_REDIS_PORT); -} - /** * ACM for Redis * @@ -57,11 +51,7 @@ class acm extends acm_memory parent::acm_memory(); $this->redis = new Redis(); - foreach (explode(',', PHPBB_ACM_REDIS) as $server) - { - $parts = explode('/', $server); - $this->redis->connect(trim($parts[0]), trim($parts[1])); - } + $this->redis->connect(PHPBB_ACM_REDIS_HOST, PHPBB_ACM_REDIS_PORT); if (defined('PHPBB_ACM_REDIS_PASSWORD')) { -- cgit v1.2.1 From 418c3d546a5ea29b5ce338e4710e0d3636009733 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sun, 12 Jun 2011 01:21:55 +0200 Subject: [ticket/9892] column & index name limits, firebird auto increment in db_tools - Column names are limited to 30 characters - Index names are limited to 31 characters. On some dbms the index name contains both table name and actual index name so the limit applies to the sum of the lenghts of table name and index name. - Auto incremented column names are limited to 26 characters to provide an additional 4 characters for sequence names The code for firebird auto increment support using generators/sequences with triggers was copied from create_schema_files.php PHPBB3-9892 --- phpBB/includes/db/db_tools.php | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index fdefda9e26..0e3173c23e 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -417,6 +417,11 @@ class phpbb_db_tools // here lies an array, filled with information compiled on the column's data $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data); + if (isset($prepared_column['auto_increment']) && strlen($column_name) > 26) // "${column_name}_gen" + { + trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); + } + // here we add the definition of the new column to the list of columns switch ($this->sql_layer) { @@ -566,7 +571,13 @@ class phpbb_db_tools case 'firebird': if ($create_sequence) { - $statements[] = "CREATE SEQUENCE {$table_name}_seq;"; + $statements[] = "CREATE GENERATOR {$table_name}_gen;"; + $statements[] = "SET GENERATOR {$table_name}_gen TO 0;"; + + $trigger = "CREATE TRIGGER t_$table_name FOR $table_name\n"; + $trigger .= "BEFORE INSERT\nAS\nBEGIN\n"; + $trigger .= "\tNEW.{$create_sequence} = GEN_ID({$table_name}_gen, 1);\nEND;"; + $statements[] = $trigger; } break; } @@ -1400,6 +1411,11 @@ class phpbb_db_tools */ function sql_prepare_column_data($table_name, $column_name, $column_data) { + if (strlen($column_name) > 30) + { + trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); + } + // Get type if (strpos($column_data[0], ':') !== false) { @@ -2040,6 +2056,11 @@ class phpbb_db_tools { $statements = array(); + if (strlen($table_name . $index_name) > 30) + { + trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); + } + switch ($this->sql_layer) { case 'firebird': @@ -2070,6 +2091,11 @@ class phpbb_db_tools { $statements = array(); + if (strlen($table_name . $index_name) > 30) + { + trigger_error("Index name '${table_name}_$index_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); + } + // remove index length unless MySQL4 if ('mysql_40' != $this->sql_layer) { -- cgit v1.2.1 From 8a5e3781d53e3df379c55166136abd6e71990af4 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sun, 12 Jun 2011 01:25:15 +0200 Subject: [ticket/9892] Shorten the index names on the q&a captcha PHPBB3-9892 --- phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 49a64b9339..45f76bd676 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -319,7 +319,7 @@ class phpbb_captcha_qa ), 'PRIMARY_KEY' => 'question_id', 'KEYS' => array( - 'lang_iso' => array('INDEX', 'lang_iso'), + 'lang' => array('INDEX', 'lang_iso'), ), ), CAPTCHA_ANSWERS_TABLE => array ( @@ -328,7 +328,7 @@ class phpbb_captcha_qa 'answer_text' => array('STEXT_UNI', ''), ), 'KEYS' => array( - 'question_id' => array('INDEX', 'question_id'), + 'qid' => array('INDEX', 'question_id'), ), ), CAPTCHA_QA_CONFIRM_TABLE => array ( -- cgit v1.2.1 From ef544ee095f2decde39cc537d3d675642b7c80f2 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sun, 12 Jun 2011 04:10:51 +0200 Subject: [ticket/9892] Table prefix lengths influence index lengths in db_tools PHPBB3-9892 --- phpBB/includes/db/db_tools.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index 0e3173c23e..c1af2782f8 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -419,7 +419,7 @@ class phpbb_db_tools if (isset($prepared_column['auto_increment']) && strlen($column_name) > 26) // "${column_name}_gen" { - trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); + trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR); } // here we add the definition of the new column to the list of columns @@ -2056,9 +2056,11 @@ class phpbb_db_tools { $statements = array(); - if (strlen($table_name . $index_name) > 30) + $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) + if (strlen($table_name . $index_name) - strlen($table_prefix) > 24) { - trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); + $max_length = $table_prefix + 24; + trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); } switch ($this->sql_layer) @@ -2091,9 +2093,11 @@ class phpbb_db_tools { $statements = array(); - if (strlen($table_name . $index_name) > 30) + $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) + if (strlen($table_name . $index_name) - strlen($table_prefix) > 24) { - trigger_error("Index name '${table_name}_$index_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); + $max_length = $table_prefix + 24; + trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); } // remove index length unless MySQL4 -- cgit v1.2.1 From ef977abe596fdc926e84e10fd994278665d38417 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sun, 12 Jun 2011 11:33:55 +0200 Subject: [ticket/9892] count is a keyword in firebird, so renaming this alias PHPBB3-9892 --- phpBB/includes/auth/auth_db.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index 02c9386f33..fe3ea30b2a 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -72,7 +72,7 @@ function login_db($username, $password, $ip = '', $browser = '', $forwarded_for if (($ip && !$config['ip_login_limit_use_forwarded']) || ($forwarded_for && $config['ip_login_limit_use_forwarded'])) { - $sql = 'SELECT COUNT(attempt_id) AS count + $sql = 'SELECT COUNT(attempt_id) AS attempts FROM ' . LOGIN_ATTEMPT_TABLE . ' WHERE attempt_time > ' . (time() - (int) $config['ip_login_limit_time']); if ($config['ip_login_limit_use_forwarded']) @@ -85,7 +85,7 @@ function login_db($username, $password, $ip = '', $browser = '', $forwarded_for } $result = $db->sql_query($sql); - $attempts = (int) $db->sql_fetchfield('count'); + $attempts = (int) $db->sql_fetchfield('attempts'); $db->sql_freeresult($result); $attempt_data = array( -- cgit v1.2.1 From 7232ca4102f7af992abe80037c3414f4d6b7768d Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sat, 11 Jun 2011 02:29:11 +0200 Subject: [develop-olympus] Bumping version number for 3.0.9-RC1. --- phpBB/includes/constants.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index b5a0aa893a..9cde068773 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB')) */ // phpBB Version -define('PHPBB_VERSION', '3.0.9-dev'); +define('PHPBB_VERSION', '3.0.9-RC1'); // QA-related // define('PHPBB_QA', 1); -- cgit v1.2.1 From c090e1c9e9fc2e435a4ae2f63923955d66dccd6d Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 13 Jun 2011 06:14:59 +0200 Subject: [ticket/10214] Correct Oracle create table query syntax in db_tools Removes the semicolon at end of oracle CREATE TABLE queries and adds a semicolon to the end of a SELECT query inside of the trigger for a new table's auto increment column before the end keyword PHPBB3-10214 --- phpBB/includes/db/db_tools.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index c1af2782f8..50e308dea2 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -543,7 +543,7 @@ class phpbb_db_tools break; case 'oracle': - $table_sql .= "\n);"; + $table_sql .= "\n)"; $statements[] = $table_sql; // do we need to add a sequence and a tigger for auto incrementing columns? @@ -561,7 +561,7 @@ class phpbb_db_tools $trigger .= "BEGIN\n"; $trigger .= "\tSELECT {$table_name}_seq.nextval\n"; $trigger .= "\tINTO :new.{$create_sequence}\n"; - $trigger .= "\tFROM dual\n"; + $trigger .= "\tFROM dual;\n"; $trigger .= "END;"; $statements[] = $trigger; -- cgit v1.2.1 From bf61602a285bce86cb4f26c2155fd781fb09f7c5 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Mon, 13 Jun 2011 22:23:28 +0200 Subject: [develop-olympus] Incrementing the version to 3.0.10-dev in develop-olympus. --- phpBB/includes/constants.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index 9cde068773..03b1102602 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB')) */ // phpBB Version -define('PHPBB_VERSION', '3.0.9-RC1'); +define('PHPBB_VERSION', '3.0.10-dev'); // QA-related // define('PHPBB_QA', 1); -- cgit v1.2.1 From f8eb15471488fe5f84669a9abbc2fc3a705903de Mon Sep 17 00:00:00 2001 From: Yuriy Rusko Date: Tue, 14 Jun 2011 06:11:35 -0400 Subject: [ticket/10218] Moving global deregistration, etc. to startup.php Because startup.php deletes all variables, the constants in database_update are used to preserve settings at the top. PHPBB3-10218 --- phpBB/includes/startup.php | 121 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 phpBB/includes/startup.php (limited to 'phpBB/includes') diff --git a/phpBB/includes/startup.php b/phpBB/includes/startup.php new file mode 100644 index 0000000000..2958277174 --- /dev/null +++ b/phpBB/includes/startup.php @@ -0,0 +1,121 @@ + true, + '_GET' => true, + '_POST' => true, + '_COOKIE' => true, + '_REQUEST' => true, + '_SERVER' => true, + '_SESSION' => true, + '_ENV' => true, + '_FILES' => true, + 'phpEx' => true, + 'phpbb_root_path' => true + ); + + // Not only will array_merge and array_keys give a warning if + // a parameter is not an array, array_merge will actually fail. + // So we check if _SESSION has been initialised. + if (!isset($_SESSION) || !is_array($_SESSION)) + { + $_SESSION = array(); + } + + // Merge all into one extremely huge array; unset this later + $input = array_merge( + array_keys($_GET), + array_keys($_POST), + array_keys($_COOKIE), + array_keys($_SERVER), + array_keys($_SESSION), + array_keys($_ENV), + array_keys($_FILES) + ); + + foreach ($input as $varname) + { + if (isset($not_unset[$varname])) + { + // Hacking attempt. No point in continuing unless it's a COOKIE (so a cookie called GLOBALS doesn't lock users out completely) + if ($varname !== 'GLOBALS' || isset($_GET['GLOBALS']) || isset($_POST['GLOBALS']) || isset($_SERVER['GLOBALS']) || isset($_SESSION['GLOBALS']) || isset($_ENV['GLOBALS']) || isset($_FILES['GLOBALS'])) + { + exit; + } + else + { + $cookie = &$_COOKIE; + while (isset($cookie['GLOBALS'])) + { + if (!is_array($cookie['GLOBALS'])) + { + break; + } + + foreach ($cookie['GLOBALS'] as $registered_var => $value) + { + if (!isset($not_unset[$registered_var])) + { + unset($GLOBALS[$registered_var]); + } + } + $cookie = &$cookie['GLOBALS']; + } + } + } + + unset($GLOBALS[$varname]); + } + + unset($input); +} + +// If we are on PHP >= 6.0.0 we do not need some code +if (version_compare(PHP_VERSION, '6.0.0-dev', '>=')) +{ + /** + * @ignore + */ + define('STRIP', false); +} +else +{ + @set_magic_quotes_runtime(0); + + // Be paranoid with passed vars + if (@ini_get('register_globals') == '1' || strtolower(@ini_get('register_globals')) == 'on' || !function_exists('ini_get')) + { + deregister_globals(); + } + + define('STRIP', (get_magic_quotes_gpc()) ? true : false); +} -- cgit v1.2.1 From 4bb98fb0463d543f60201c3f8435ada3e0b070da Mon Sep 17 00:00:00 2001 From: Yuriy Rusko Date: Wed, 15 Jun 2011 00:50:12 -0400 Subject: [ticket/10218] Prevent startime from being overwritten by deregister_globals() PHPBB3-10218 --- phpBB/includes/startup.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/startup.php b/phpBB/includes/startup.php index 2958277174..be46c17ba6 100644 --- a/phpBB/includes/startup.php +++ b/phpBB/includes/startup.php @@ -13,8 +13,6 @@ if (!defined('IN_PHPBB')) { exit; } -$starttime = explode(' ', microtime()); -$starttime = $starttime[1] + $starttime[0]; // Report all errors, except notices and deprecation messages if (!defined('E_DEPRECATED')) @@ -119,3 +117,6 @@ else define('STRIP', (get_magic_quotes_gpc()) ? true : false); } + +$starttime = explode(' ', microtime()); +$starttime = $starttime[1] + $starttime[0]; -- cgit v1.2.1 From 74785a8bdaab17cd698028ac0c8ccfb3c570cd5d Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Wed, 15 Jun 2011 18:10:15 +0200 Subject: [ticket/10220] Limit user agent value length for storage in login attempt table PHPBB3-10220 --- phpBB/includes/auth/auth_db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index fe3ea30b2a..018d5cce70 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -90,7 +90,7 @@ function login_db($username, $password, $ip = '', $browser = '', $forwarded_for $attempt_data = array( 'attempt_ip' => $ip, - 'attempt_browser' => $browser, + 'attempt_browser' => trim(substr($browser, 0, 149)), 'attempt_forwarded_for' => $forwarded_for, 'attempt_time' => time(), 'user_id' => ($row) ? (int) $row['user_id'] : 0, -- cgit v1.2.1 From 48e5e56146bdf1b2b30556e8fb353e7aa20f7fb6 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Wed, 15 Jun 2011 19:41:14 +0200 Subject: [prep-release-3.0.9] Bumping version number for 3.0.9-RC2. --- phpBB/includes/constants.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index 9cde068773..a372b96017 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB')) */ // phpBB Version -define('PHPBB_VERSION', '3.0.9-RC1'); +define('PHPBB_VERSION', '3.0.9-RC2'); // QA-related // define('PHPBB_QA', 1); -- cgit v1.2.1 From 63b9b91dee9da85b68f4c4316a01be54d24fde9f Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Thu, 16 Jun 2011 16:02:34 +0200 Subject: [ticket/10221] Append unit (seconds) after input field, remove from explanation PHPBB3-10221 --- phpBB/includes/acp/acp_board.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 9f00145f3b..d8ab42ed2d 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -387,7 +387,7 @@ class acp_board 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true), 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true), - 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true), + 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), 'ip_login_limit_use_forwarded' => array('lang' => 'IP_LOGIN_LIMIT_USE_FORWARDED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), -- cgit v1.2.1 From 7de078b26e2a0b2672f24efe715b440cca7f5979 Mon Sep 17 00:00:00 2001 From: rxu Date: Sun, 19 Jun 2011 19:03:53 +0800 Subject: [ticket/10227] Allow persistent connections for mysqli with PHP 5.3.0+ PHPBB3-10227 --- phpBB/includes/db/mysqli.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index 862d62f4ba..dcf8727e18 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -33,13 +33,16 @@ class dbal_mysqli extends dbal */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false , $new_link = false) { - $this->persistency = $persistency; + // Mysqli extension supports persistent connection since PHP 5.3.0 + $this->persistency = (version_compare(PHP_VERSION, '5.3.0', '>=')) ? $persistency : false; $this->user = $sqluser; - $this->server = $sqlserver; + + // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix + $this->server = ($this->persistency) ? 'p:' . (($sqlserver) ? $sqlserver : 'localhost') : $sqlserver; + $this->dbname = $database; $port = (!$port) ? NULL : $port; - // Persistant connections not supported by the mysqli extension? $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port); if ($this->db_connect_id && $this->dbname != '') -- cgit v1.2.1 From 8c01ed578da2a501b9ad1fc8541e3eb237d1b765 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Mon, 20 Jun 2011 00:03:20 +0200 Subject: [ticket/10234] Report E_WARNING errors as "PHP Warning" instead of "PHP Notice" PHPBB3-10234 --- phpBB/includes/functions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index b8d9e0b92e..a89b47b170 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3776,7 +3776,8 @@ function msg_handler($errno, $msg_text, $errfile, $errline) // remove complete path to installation, with the risk of changing backslashes meant to be there $errfile = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $errfile); $msg_text = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $msg_text); - echo '[phpBB Debug] PHP Notice: in file ' . $errfile . ' on line ' . $errline . ': ' . $msg_text . '
' . "\n"; + $error_name = ($errno === E_WARNING) ? 'PHP Warning' : 'PHP Notice'; + echo '[phpBB Debug] ' . $error_name . ': in file ' . $errfile . ' on line ' . $errline . ': ' . $msg_text . '
' . "\n"; // we are writing an image - the user won't see the debug, so let's place it in the log if (defined('IMAGE_OUTPUT') || defined('IN_CRON')) -- cgit v1.2.1 From 578f9dffa607de1da2aa181b49be583f27f3bf28 Mon Sep 17 00:00:00 2001 From: rxu Date: Tue, 21 Jun 2011 00:21:42 +0800 Subject: [ticket/10226] Allow mysqli connections via local sockets/pipes PHPBB3-10226 --- phpBB/includes/db/mysqli.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index dcf8727e18..1901847c0f 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -43,7 +43,23 @@ class dbal_mysqli extends dbal $this->dbname = $database; $port = (!$port) ? NULL : $port; - $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port); + // If port is set and it is not numeric, most likely mysqli socket is set. + // Try to map it to the $socket parameter. + $socket = NULL; + if ($port) + { + if (preg_match('#^[0-9]+$#', $port)) + { + $port = (int) $port; + } + else + { + $socket = $port; + $port = NULL; + } + } + + $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket); if ($this->db_connect_id && $this->dbname != '') { -- cgit v1.2.1 From 18fb3d86cdac01c2dd1469982a51526fa1480b42 Mon Sep 17 00:00:00 2001 From: rxu Date: Tue, 21 Jun 2011 22:03:19 +0800 Subject: [ticket/10226] Use is_numeric() instead of preg_replace() PHPBB3-10226 --- phpBB/includes/db/mysqli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index 1901847c0f..46c2f9210b 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -48,7 +48,7 @@ class dbal_mysqli extends dbal $socket = NULL; if ($port) { - if (preg_match('#^[0-9]+$#', $port)) + if (is_numeric($port)) { $port = (int) $port; } -- cgit v1.2.1 From 9f3b159998a2ffeb5476cd77e08c372a196360a4 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Mon, 20 Jun 2011 01:23:43 +0200 Subject: [ticket/7729] Prevent date/time functions from throwing E_WARNING on PHP 5.3. PHPBB3-7729 --- phpBB/includes/startup.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/startup.php b/phpBB/includes/startup.php index be46c17ba6..ca9665da29 100644 --- a/phpBB/includes/startup.php +++ b/phpBB/includes/startup.php @@ -118,5 +118,33 @@ else define('STRIP', (get_magic_quotes_gpc()) ? true : false); } +// Prevent date/time functions from throwing E_WARNING on PHP 5.3 by setting a default timezone +if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) +{ + // For PHP 5.1.0 the date/time functions have been rewritten + // and setting a timezone is required prior to calling any date/time function. + + // Since PHP 5.2.0 calls to date/time functions without having a timezone set + // result in E_STRICT errors being thrown. + // Note: We already exclude E_STRICT errors + // (to be exact: they are not included in E_ALL in PHP 5.2) + + // In PHP 5.3.0 the error level has been raised to E_WARNING which causes problems + // because we show E_WARNING errors and do not set a default timezone. + // This is because we have our own timezone handling and work in UTC only anyway. + + // So what we basically want to do is set our timezone to UTC, + // but we don't know what other scripts (such as bridges) are involved, + // so we check whether a timezone is already set by calling date_default_timezone_get(). + + // Unfortunately, date_default_timezone_get() itself might throw E_WARNING + // if no timezone has been set, so we have to keep it quiet with @. + + // date_default_timezone_get() tries to guess the correct timezone first + // and then falls back to UTC when everything fails. + // We just set the timezone to whatever date_default_timezone_get() returns. + date_default_timezone_set(@date_default_timezone_get()); +} + $starttime = explode(' ', microtime()); $starttime = $starttime[1] + $starttime[0]; -- cgit v1.2.1 From a5ef6c3b2070f45f88b9d5942cd974c9c26376c5 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sun, 26 Jun 2011 11:01:46 +0200 Subject: [ticket/10188] Prevent semi-compressed output When a non-fatal error occurs at the beginning of the script before any custom error handler is set one of two situations can be encountered: 1) if the ini option output buffer is disabled: - headers are sent to the http client - the error message is output 2) if the ini option output_buffer is enabled or the script is run within an ob_start()/ob_end() wrapper: - the error message is written to the output buffer Once the script reaches page_header() phpbb starts gzip compression if enabled. This is done through ob_start with a ob_gzhandler as a callback. The compression is skipped if headers have already been sent. In situation 1) the error message sent in plain text comes with headers and this gzip compression is skipped. The client receives a plaintext version of the page. However in situation 2) headers have not been sent yet and the rest of the page will be compressed. The result is a plaintext error message followed by compressed output. The client does not understand this output resulting in either an error message or simply a blank page in the browser. In addition to the above situation this problem occurs with errors that are triggered after the custom error handler is loaded. The problem has been noticed before, and a workaround was found. The error handler would call ob_flush() for particular configuration settings before outputting the error message. This resulted in headers being sent when output buffering was enabled thus disabling gzip compression for the rest of the page. The constraints under which ob_flush() was called were lessened over time whenever a new case was found that would trigger this problem. Eventually ob_flush() would be called even when code causing an E_NOTICE was simply run within an ob_start/ob_end. This makes it impossible to use output buffering to retrieve the content of an error message without prohibiting the page from setting headers afterwards. This commit removes all flushing in msg_handler completely and instead fixes the problem for both errors before and after the error handler is registered. GZIP compression is only enabled if there is at most one level of output buffering (e.g. the output_buffer php.ini option is enabled) and if there has not yet been any output in this buffer. This should avoid any partial output compression. PHPBB3-10188 --- phpBB/includes/functions.php | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index a89b47b170..d05cccc440 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3758,21 +3758,6 @@ function msg_handler($errno, $msg_text, $errfile, $errline) if (strpos($errfile, 'cache') === false && strpos($errfile, 'template.') === false) { - // flush the content, else we get a white page if output buffering is on - if (ob_get_level() > 0) - { - @ob_flush(); - } - - // Another quick fix for those having gzip compression enabled, but do not flush if the coder wants to catch "something". ;) - if (!empty($config['gzip_compress'])) - { - if (@extension_loaded('zlib') && !headers_sent() && !ob_get_level()) - { - @ob_flush(); - } - } - // remove complete path to installation, with the risk of changing backslashes meant to be there $errfile = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $errfile); $msg_text = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $msg_text); @@ -4332,7 +4317,21 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 // gzip_compression if ($config['gzip_compress']) { - if (@extension_loaded('zlib') && !headers_sent()) + // to avoid partially compressed output resulting in blank pages in + // the browser or error messages, compression is disabled in a few cases: + // + // 1) if headers have already been sent, this indicates plaintext output + // has been started so further content must not be compressed + // 2) the length of the current output buffer is non-zero. This means + // there is already some uncompressed content in this output buffer + // so further output must not be compressed + // 3) if more than one level of output buffering is used because we + // cannot test all output buffer level content lengths. One level + // could be caused by php.ini output_buffering. Anything + // beyond that is manual, so the code wrapping phpBB in output buffering + // can easily compress the output itself. + // + if (@extension_loaded('zlib') && !headers_sent() && ob_get_level() <= 1 && ob_get_length() == 0) { ob_start('ob_gzhandler'); } -- cgit v1.2.1 From fe0932fdf02a45be914414eca586add1c083cbee Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Sun, 26 Jun 2011 20:47:33 +0200 Subject: [prep-release-3.0.9] Bumping version number for 3.0.9-RC3. --- phpBB/includes/constants.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index a372b96017..2f485fb4d7 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB')) */ // phpBB Version -define('PHPBB_VERSION', '3.0.9-RC2'); +define('PHPBB_VERSION', '3.0.9-RC3'); // QA-related // define('PHPBB_QA', 1); -- cgit v1.2.1 From d8ac2cc5f0c253842185506b174a8355dfd5f3fb Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 5 Jul 2011 00:40:45 +0200 Subject: [prep-release-3.0.9] Bumping version number for the final 3.0.9 release. --- phpBB/includes/constants.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index 2f485fb4d7..3940888216 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB')) */ // phpBB Version -define('PHPBB_VERSION', '3.0.9-RC3'); +define('PHPBB_VERSION', '3.0.9'); // QA-related // define('PHPBB_QA', 1); -- cgit v1.2.1 From 0d602e1722a0a75f2f4a9ab90eeeb2a47042417f Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Mon, 4 Jul 2011 19:57:54 -0400 Subject: [ticket/10247] Use COUNT(*) instead of COUNT(attempt_id) attempt_id column was deleted PHPBB3-10247 --- phpBB/includes/auth/auth_db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index 018d5cce70..6ca69d9174 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -72,7 +72,7 @@ function login_db($username, $password, $ip = '', $browser = '', $forwarded_for if (($ip && !$config['ip_login_limit_use_forwarded']) || ($forwarded_for && $config['ip_login_limit_use_forwarded'])) { - $sql = 'SELECT COUNT(attempt_id) AS attempts + $sql = 'SELECT COUNT(*) AS attempts FROM ' . LOGIN_ATTEMPT_TABLE . ' WHERE attempt_time > ' . (time() - (int) $config['ip_login_limit_time']); if ($config['ip_login_limit_use_forwarded']) -- cgit v1.2.1 From f610f44a4e23eef8ed7698a32b10bc28789bdf00 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 Jul 2011 19:09:09 -0400 Subject: [ticket/10250] Overwrite the site_logo width&height when the phpbb logo is used The new logo is slightly wider than the old logo. If we changed the size in the imageset.cfg we would cause a conflict for everyone who replaced the logo with their own and modified the size. Instead we overwrite the width and height in the img() function in session.php only if its contents are that of the stock phpbb logo. PHPBB3-10250 --- phpBB/includes/session.php | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index 7ef6e02a8d..f509957f96 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -2272,9 +2272,36 @@ class user extends session // Use URL if told so $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; - $img_data['src'] = $root_path . 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename']; + $path = 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename']; + + $img_data['src'] = $root_path . $path; $img_data['width'] = $this->img_array[$img]['image_width']; $img_data['height'] = $this->img_array[$img]['image_height']; + + // We overwrite the width and height to the phpbb logo's width + // and height here if the contents of the site_logo file are + // really equal to the phpbb_logo + // This allows us to change the dimensions of the phpbb_logo without + // modifying the imageset.cfg and causing a conflict for everyone + // who modified it for their custom logo on updating + if ($img == 'site_logo' && file_exists($phpbb_root_path . $path)) + { + global $cache; + + if (($img_file_hash = $cache->get('imageset_site_logo_md5')) === false) + { + $img_file_hash = md5(file_get_contents($phpbb_root_path . $path)); + $cache->put('imageset_site_logo_md5', $img_file_hash); + } + + $phpbb_logo_hash = '0c461a32cd3621643105f0d02a772c10'; + + if ($phpbb_logo_hash == $img_file_hash) + { + $img_data['width'] = '149'; + $img_data['height'] = '52'; + } + } } $alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt; -- cgit v1.2.1 From 8ec737e9c4d36711b09250df72492a8f89e7bfb1 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Tue, 5 Jul 2011 19:38:15 -0400 Subject: [ticket/10250] Destroy cached md5 hash of site_logo on refreshing an imageset PHPBB3-10250 --- phpBB/includes/acp/acp_styles.php | 1 + 1 file changed, 1 insertion(+) (limited to 'phpBB/includes') diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index 37cf8d1f72..3bc8c86500 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -510,6 +510,7 @@ parse_css_file = {PARSE_CSS_FILE} $db->sql_transaction('commit'); $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); + $cache->destroy('imageset_site_logo_md5'); add_log('admin', 'LOG_IMAGESET_REFRESHED', $imageset_row['imageset_name']); trigger_error($user->lang['IMAGESET_REFRESHED'] . adm_back_link($this->u_action)); -- cgit v1.2.1 From b261a1a31ae8500cc090d412ed569123ae3cb9ca Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Wed, 6 Jul 2011 17:53:57 -0400 Subject: [ticket/10250] The site_logo hash is different depending on imageset & language PHPBB3-10250 --- phpBB/includes/session.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index f509957f96..e9e706e2b8 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -2288,15 +2288,23 @@ class user extends session { global $cache; - if (($img_file_hash = $cache->get('imageset_site_logo_md5')) === false) + $img_file_hashes = $cache->get('imageset_site_logo_md5'); + + if ($img_file_hashes === false) + { + $img_file_hashes = array(); + } + + $key = $this->theme['imageset_path'] . '::' . $this->img_array[$img]['image_lang']; + if (!isset($img_file_hashes[$key])) { - $img_file_hash = md5(file_get_contents($phpbb_root_path . $path)); - $cache->put('imageset_site_logo_md5', $img_file_hash); + $img_file_hashes[$key] = md5(file_get_contents($phpbb_root_path . $path)); + $cache->put('imageset_site_logo_md5', $img_file_hashes); } $phpbb_logo_hash = '0c461a32cd3621643105f0d02a772c10'; - if ($phpbb_logo_hash == $img_file_hash) + if ($phpbb_logo_hash == $img_file_hashes[$key]) { $img_data['width'] = '149'; $img_data['height'] = '52'; -- cgit v1.2.1 From a275d17625325e0353b67fabf5a9b0c4fb35877e Mon Sep 17 00:00:00 2001 From: Yuriy Rusko Date: Wed, 6 Jul 2011 20:38:02 -0400 Subject: [ticket/9859] Changing all phpBB footers to match the new credit line PHPBB3-9859 --- phpBB/includes/db/dbal.php | 2 +- phpBB/includes/functions.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php index 2f9619c8ea..9b45c085a2 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/dbal.php @@ -777,7 +777,7 @@ class dbal diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index d05cccc440..b1c1c14d0c 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3851,7 +3851,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) echo ' '; echo ' '; echo ' '; echo ''; echo ''; -- cgit v1.2.1 From b2a65ac76db38e47c0644389ba737492ef6307f6 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 6 Jul 2011 13:40:21 +0200 Subject: [ticket/10237] Use confirm-box to handle unwatching a forum/topic actions PHPBB3-10237 --- phpBB/includes/functions_display.php | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index d7422aa2c9..496da72344 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -1097,22 +1097,34 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $message = $user->lang['ERR_UNWATCHING'] . '

' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '', ''); trigger_error($message); } - if ($_GET['unwatch'] == $mode) - { - $is_watching = 0; + if (confirm_box(true)) + { $sql = 'DELETE FROM ' . $table_sql . " WHERE $where_sql = $match_id AND user_id = $user_id"; $db->sql_query($sql); - } - - $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - meta_refresh(3, $redirect_url); + $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); + $message = $user->lang['NOT_WATCHING_' . strtoupper($mode)] . '

' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '', ''); + meta_refresh(3, $redirect_url); + trigger_error($message); + } + else + { + $s_hidden_fields = array( + 'uid' => $user->data['user_id'], + 'unwatch' => $mode, + 'start' => $start, + 'f' => $forum_id, + ); + if ($mode != 'forum') + { + $s_hidden_fields['t'] = $topic_id; + } - $message = $user->lang['NOT_WATCHING_' . strtoupper($mode)] . '

' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '', ''); - trigger_error($message); + confirm_box(false, 'UNWATCH_' . strtoupper($mode), build_hidden_fields($s_hidden_fields)); + } } else { -- cgit v1.2.1 From 766537035ea2f04c5aa3c59c15edc15f4ecd050f Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Sat, 9 Jul 2011 15:28:33 +0200 Subject: [ticket/10258] Change the DOCTYPE to HTML5 PHPBB3-10258 --- phpBB/includes/db/dbal.php | 8 ++++---- phpBB/includes/functions.php | 14 ++++++++------ phpBB/includes/functions_download.php | 5 +++-- 3 files changed, 15 insertions(+), 12 deletions(-) (limited to 'phpBB/includes') diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php index b29e2791ab..2468f26d39 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/dbal.php @@ -767,11 +767,11 @@ class dbal $mtime = explode(' ', microtime()); $totaltime = $mtime[0] + $mtime[1] - $starttime; - echo ' - + echo ' + - - + + SQL Report diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index ed183b3e76..70cf78e75e 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -2248,10 +2248,11 @@ function redirect($url, $return = false, $disable_cd_check = false) { header('Refresh: 0; URL=' . $url); - echo ''; - echo ''; + echo ''; + echo ''; echo ''; - echo ''; + echo ''; + echo ''; echo ''; echo '' . $user->lang['REDIRECT'] . ''; echo ''; @@ -3756,10 +3757,11 @@ function msg_handler($errno, $msg_text, $errfile, $errline) // Try to not call the adm page data... - echo ''; - echo ''; + echo ''; + echo ''; echo ''; - echo ''; + echo ''; + echo ''; echo '' . $msg_title . ''; echo '