diff options
Diffstat (limited to 'phpBB')
57 files changed, 1552 insertions, 218 deletions
diff --git a/phpBB/adm/images/phpbb_logo.gif b/phpBB/adm/images/phpbb_logo.gif Binary files differdeleted file mode 100644 index 239993182b..0000000000 --- a/phpBB/adm/images/phpbb_logo.gif +++ /dev/null diff --git a/phpBB/adm/images/phpbb_logo.png b/phpBB/adm/images/phpbb_logo.png Binary files differnew file mode 100644 index 0000000000..c3f9248ed7 --- /dev/null +++ b/phpBB/adm/images/phpbb_logo.png diff --git a/phpBB/adm/style/admin.css b/phpBB/adm/style/admin.css index 94f421030d..08613de0dd 100644 --- a/phpBB/adm/style/admin.css +++ b/phpBB/adm/style/admin.css @@ -146,15 +146,15 @@ li { #page-header { clear: both; text-align: right; - background: url("../images/phpbb_logo.gif") top left no-repeat; - height: 49px; + background: url("../images/phpbb_logo.png") top left no-repeat; + height: 54px; font-size: 0.85em; margin-bottom: 10px; } .rtl #page-header { text-align: left; - background: url("../images/phpbb_logo.gif") top right no-repeat; + background: url("../images/phpbb_logo.png") top right no-repeat; } #page-header h1 { diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js index ab1aaa8505..f07a245307 100644 --- a/phpBB/assets/javascript/core.js +++ b/phpBB/assets/javascript/core.js @@ -521,14 +521,47 @@ phpbb.add_ajax_callback = function(id, callback) * the alt-text data attribute, and replaces the text in the attribute with the * current text so that the process can be repeated. */ -phpbb.add_ajax_callback('alt_text', function(data) { +phpbb.add_ajax_callback('alt_text', function() { var el = $(this), alt_text; alt_text = el.attr('data-alt-text'); + el.attr('data-alt-text', el.text()); el.attr('title', alt_text); el.text(alt_text); }); +/** + * This callback is based on the alt_text callback. + * + * It replaces the current text with the text in the alt-text data attribute, + * and replaces the text in the attribute with the current text so that the + * process can be repeated. + * Additionally it replaces the class of the link's parent + * and changes the link itself. + */ +phpbb.add_ajax_callback('toggle_link', function() { + var el = $(this), + toggle_text, + toggle_url, + toggle_class; + + // Toggle link text + + toggle_text = el.attr('data-toggle-text'); + el.attr('data-toggle-text', el.text()); + el.attr('title', toggle_text); + el.text(toggle_text); + + // Toggle link url + toggle_url = el.attr('data-toggle-url'); + el.attr('data-toggle-url', el.attr('href')); + el.attr('href', toggle_url); + + // Toggle class of link parent + toggle_class = el.attr('data-toggle-class'); + el.attr('data-toggle-class', el.parent().attr('class')); + el.parent().attr('class', toggle_class); +}); })(jQuery); // Avoid conflicts with other libraries diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php index 0d239b11f2..6825ba1bf6 100644 --- a/phpBB/develop/create_schema_files.php +++ b/phpBB/develop/create_schema_files.php @@ -237,7 +237,7 @@ $supported_dbms = array('firebird', 'mssql', 'mysql_40', 'mysql_41', 'oracle', ' foreach ($supported_dbms as $dbms) { - $fp = fopen($schema_path . $dbms . '_schema.sql', 'wt'); + $fp = fopen($schema_path . $dbms . '_schema.sql', 'wb'); $line = ''; diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 47cf546ee8..cec11facb6 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -132,7 +132,7 @@ <ul> <li>MySQL 3.23 or above (MySQLi supported)</li> <li>PostgreSQL 7.3+</li> - <li>SQLite 2.8.2+</li> + <li>SQLite 2.8.2+ (SQLite 3 is not supported)</li> <li>Firebird 2.1+</li> <li>MS SQL Server 2000 or above (directly or via ODBC or the native adapter)</li> <li>Oracle</li> diff --git a/phpBB/docs/coding-guidelines.html b/phpBB/docs/coding-guidelines.html index 3f2c142ac6..ae4655e094 100644 --- a/phpBB/docs/coding-guidelines.html +++ b/phpBB/docs/coding-guidelines.html @@ -295,11 +295,17 @@ PHPBB_QA (Set board to QA-Mode, which means the updater also c <p>We will not be using any form of hungarian notation in our naming conventions. Many of us believe that hungarian naming is one of the primary code obfuscation techniques currently in use.</p> <h4>Variable Names:</h4> - <p>Variable names should be in all lowercase, with words separated by an underscore, example:</p> + <p>In PHP, variable names should be in all lowercase, with words separated by an underscore, example:</p> <div class="indent"> <p><code>$current_user</code> is right, but <code>$currentuser</code> and <code> $currentUser</code> are not.</p> </div> + + <p>In JavaScript, variable names should use camel case:</p> + + <div class="indent"> + <p><code>currentUser</code> is right, but <code>currentuser</code> and <code>current_user</code> are not.</p> + </div> <p>Names should be descriptive, but concise. We don't want huge sentences as our variable names, but typing an extra couple of characters is always better than wondering what exactly a certain variable is for. </p> @@ -317,7 +323,7 @@ for ($i = 0; $i < $outer_size; $i++) </pre></div> <h4>Function Names:</h4> - <p>Functions should also be named descriptively. We're not programming in C here, we don't want to write functions called things like "stristr()". Again, all lower-case names with words separated by a single underscore character. Function names should preferably have a verb in them somewhere. Good function names are <code>print_login_status()</code>, <code>get_user_data()</code>, etc. </p> + <p>Functions should also be named descriptively. We're not programming in C here, we don't want to write functions called things like "stristr()". Again, all lower-case names with words separated by a single underscore character in PHP, and camel caps in JavaScript. Function names should preferably have a verb in them somewhere. Good function names are <code>print_login_status()</code>, <code>get_user_data()</code>, etc. Constructor functions in JavaScript should begin with a capital letter.</p> <h4>Function Arguments:</h4> <p>Arguments are subject to the same guidelines as variable names. We don't want a bunch of functions like: <code>do_stuff($a, $b, $c)</code>. In most cases, we'd like to be able to tell how to use a function by just looking at its declaration. </p> @@ -397,7 +403,7 @@ for ($i = 0; $i < size; $i++) </pre></div> <h4>Where to put the braces:</h4> - <p>This one is a bit of a holy war, but we're going to use a style that can be summed up in one sentence: Braces always go on their own line. The closing brace should also always be at the same column as the corresponding opening brace, examples:</p> + <p>In PHP code, braces always go on their own line. The closing brace should also always be at the same column as the corresponding opening brace, examples:</p> <div class="codebox"><pre> if (condition) @@ -427,6 +433,30 @@ function do_stuff() ... } </pre></div> + + <p>In JavaScript code, braces always go on the same line:</p> + + <div class="codebox"><pre> +if (condition) { + while (condition2) { + ... + } +} else { + ... +} + +for (var i = 0; i < size; i++) { + ... +} + +while (condition) { + ... +} + +function do_stuff() { + ... +} + </pre></div> <h4>Use spaces between tokens:</h4> <p>This is another simple, easy step that helps keep code readable without much effort. Whenever you write an assignment, expression, etc.. Always leave <em>one</em> space between the tokens. Basically, write code as if it was English. Put spaces between variable names and operators. Don't put spaces just after an opening bracket or before a closing bracket. Don't put spaces just before a comma or a semicolon. This is best shown with a few examples, examples:</p> @@ -502,7 +532,7 @@ $post_url = "{$phpbb_root_path}posting.$phpEx?mode=$mode&amp;start=$start"; <p>In SQL statements mixing single and double quotes is partly allowed (following the guidelines listed here about SQL formatting), else one should try to only use one method - mostly single quotes.</p> <h4>Commas after every array element:</h4> - <p>If an array is defined with each element on its own line, you still have to modify the previous line to add a comma when appending a new element. PHP allows for trailing (useless) commas in array definitions. These should always be used so each element including the comma can be appended with a single line</p> + <p>If an array is defined with each element on its own line, you still have to modify the previous line to add a comma when appending a new element. PHP allows for trailing (useless) commas in array definitions. These should always be used so each element including the comma can be appended with a single line. In JavaScript, do not use the trailing comma, as it causes browsers to throw errors.</p> <p class="bad">// wrong</p> <div class="codebox"><pre> diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php index 78d6a0b2f3..f098b772ee 100644 --- a/phpBB/includes/acp/acp_inactive.php +++ b/phpBB/includes/acp/acp_inactive.php @@ -136,6 +136,8 @@ class acp_inactive add_log('admin', 'LOG_USER_ACTIVE', $row['username']); add_log('user', $row['user_id'], 'LOG_USER_ACTIVE_USER'); } + + trigger_error(sprintf($user->lang['LOG_INACTIVE_ACTIVATE'], implode($user->lang['COMMA_SEPARATOR'], $user_affected) . ' ' . adm_back_link($this->u_action))); } // For activate we really need to redirect, else a refresh can result in users being deactivated again @@ -159,6 +161,8 @@ class acp_inactive } add_log('admin', 'LOG_INACTIVE_' . strtoupper($action), implode(', ', $user_affected)); + + trigger_error(sprintf($user->lang['LOG_INACTIVE_DELETE'], implode($user->lang['COMMA_SEPARATOR'], $user_affected) . ' ' . adm_back_link($this->u_action))); } else { @@ -230,7 +234,8 @@ class acp_inactive $db->sql_query($sql); add_log('admin', 'LOG_INACTIVE_REMIND', implode(', ', $usernames)); - unset($usernames); + + trigger_error(sprintf($user->lang['LOG_INACTIVE_REMIND'], implode($user->lang['COMMA_SEPARATOR'], $usernames) . ' ' . adm_back_link($this->u_action))); } $db->sql_freeresult($result); diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php index fde917e5b1..444446e9c3 100644 --- a/phpBB/includes/bbcode.php +++ b/phpBB/includes/bbcode.php @@ -130,7 +130,7 @@ class bbcode if (empty($this->template_filename)) { - $this->template_bitfield = new bitfield($user->theme['bbcode_bitfield']); + $this->template_bitfield = new bitfield($user->style['bbcode_bitfield']); $style_resource_locator = new phpbb_style_resource_locator(); $style_path_provider = new phpbb_style_extension_path_provider($phpbb_extension_manager, new phpbb_style_path_provider()); diff --git a/phpBB/includes/cache/service.php b/phpBB/includes/cache/service.php index aa225ade69..37f32aa753 100644 --- a/phpBB/includes/cache/service.php +++ b/phpBB/includes/cache/service.php @@ -321,50 +321,39 @@ class phpbb_cache_service /** * Obtain cfg file data */ - function obtain_cfg_items($theme) + function obtain_cfg_items($style) { global $config, $phpbb_root_path; - $parsed_items = array( - 'theme' => array(), - 'template' => array(), - 'imageset' => array() - ); + $parsed_array = $this->driver->get('_cfg_' . $style['style_path']); - foreach ($parsed_items as $key => $parsed_array) + if ($parsed_array === false) { - $parsed_array = $this->driver->get('_cfg_' . $key . '_' . $theme[$key . '_path']); - - if ($parsed_array === false) - { - $parsed_array = array(); - } + $parsed_array = array(); + } - $reparse = false; - $filename = $phpbb_root_path . 'styles/' . $theme[$key . '_path'] . '/' . $key . '/' . $key . '.cfg'; + $reparse = false; + $filename = $phpbb_root_path . 'styles/' . $style['style_path'] . '/style.cfg'; - if (!file_exists($filename)) - { - continue; - } + if (!file_exists($filename)) + { + continue; + } - if (!isset($parsed_array['filetime']) || (($config['load_tplcompile'] && @filemtime($filename) > $parsed_array['filetime']))) - { - $reparse = true; - } + if (!isset($parsed_array['filetime']) || (($config['load_tplcompile'] && @filemtime($filename) > $parsed_array['filetime']))) + { + $reparse = true; + } - // Re-parse cfg file - if ($reparse) - { - $parsed_array = parse_cfg_file($filename); - $parsed_array['filetime'] = @filemtime($filename); + // Re-parse cfg file + if ($reparse) + { + $parsed_array = parse_cfg_file($filename); + $parsed_array['filetime'] = @filemtime($filename); - $this->driver->put('_cfg_' . $key . '_' . $theme[$key . '_path'], $parsed_array); - } - $parsed_items[$key] = $parsed_array; + $this->driver->put('_cfg_' . $style['style_path'], $parsed_array); } - - return $parsed_items; + return $parsed_array; } /** diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php index cf54d455f7..159703d3be 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/dbal.php @@ -284,6 +284,37 @@ class dbal } /** + * Build a case expression + * + * Note: The two statements action_true and action_false must have the same data type (int, vchar, ...) in the database! + * + * @param string $condition The condition which must be true, to use action_true rather then action_else + * @param string $action_true SQL expression that is used, if the condition is true + * @param string $action_else SQL expression that is used, if the condition is false, optional + * @return string CASE expression including the condition and statements + */ + public function sql_case($condition, $action_true, $action_false = false) + { + $sql_case = 'CASE WHEN ' . $condition; + $sql_case .= ' THEN ' . $action_true; + $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : ''; + $sql_case .= ' END'; + return $sql_case; + } + + /** + * Build a concatenated expression + * + * @param string $expr1 Base SQL expression where we append the second one + * @param string $expr2 SQL expression that is appended to the first expression + * @return string Concatenated string + */ + public function sql_concatenate($expr1, $expr2) + { + return $expr1 . ' || ' . $expr2; + } + + /** * Returns whether results of a query need to be buffered to run a transaction while iterating over them. * * @return bool Whether buffering is required. diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php index abeabc389f..fb044b492f 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/mssql.php @@ -92,6 +92,14 @@ class dbal_mssql extends dbal } /** + * {@inheritDoc} + */ + public function sql_concatenate($expr1, $expr2) + { + return $expr1 . ' + ' . $expr2; + } + + /** * SQL Transaction * @access private */ diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index 6e24f4e9e8..64fa9634d1 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -110,6 +110,14 @@ class dbal_mssql_odbc extends dbal } /** + * {@inheritDoc} + */ + public function sql_concatenate($expr1, $expr2) + { + return $expr1 . ' + ' . $expr2; + } + + /** * SQL Transaction * @access private */ diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 8a4503f111..1f37d54ecb 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -260,6 +260,14 @@ class dbal_mssqlnative extends dbal /** * {@inheritDoc} */ + public function sql_concatenate($expr1, $expr2) + { + return $expr1 . ' + ' . $expr2; + } + + /** + * {@inheritDoc} + */ function sql_buffer_nested_transactions() { return true; @@ -435,7 +443,7 @@ class dbal_mssqlnative extends dbal unset($row['line2'], $row['line3']); } } - return $row; + return (sizeof($row)) ? $row : false; } /** diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index eb38e3e913..8d1f805870 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -120,6 +120,14 @@ class dbal_mysql extends dbal } /** + * {@inheritDoc} + */ + public function sql_concatenate($expr1, $expr2) + { + return 'CONCAT(' . $expr1 . ', ' . $expr2 . ')'; + } + + /** * SQL Transaction * @access private */ diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index 4210a58002..e07cd35e24 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -123,6 +123,14 @@ class dbal_mysqli extends dbal } /** + * {@inheritDoc} + */ + public function sql_concatenate($expr1, $expr2) + { + return 'CONCAT(' . $expr1 . ', ' . $expr2 . ')'; + } + + /** * SQL Transaction * @access private */ diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 3533a4ca00..22e456c7de 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -4922,9 +4922,9 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'T_ASSETS_VERSION' => $config['assets_version'], 'T_ASSETS_PATH' => "{$web_path}assets", - 'T_THEME_PATH' => "{$web_path}styles/" . rawurlencode($user->theme['style_path']) . '/theme', - 'T_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->theme['style_path']) . '/template', - 'T_SUPER_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->theme['style_path']) . '/template', + 'T_THEME_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme', + 'T_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/template', + 'T_SUPER_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/template', 'T_IMAGES_PATH' => "{$web_path}images/", 'T_SMILIES_PATH' => "{$web_path}{$config['smilies_path']}/", 'T_AVATAR_PATH' => "{$web_path}{$config['avatar_path']}/", @@ -4932,16 +4932,15 @@ 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' => "{$web_path}styles/" . rawurlencode($user->theme['style_path']) . '/theme/stylesheet.css?assets_version=' . $config['assets_version'], - 'T_STYLESHEET_LANG_LINK' => "{$web_path}styles/" . rawurlencode($user->theme['style_path']) . '/theme/' . $user->lang_name . '/stylesheet.css?assets_version=' . $config['assets_version'], - 'T_STYLESHEET_NAME' => $user->theme['style_name'], + 'T_STYLESHEET_LINK' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme/stylesheet.css?assets_version=' . $config['assets_version'], + 'T_STYLESHEET_LANG_LINK' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme/' . $user->lang_name . '/stylesheet.css?assets_version=' . $config['assets_version'], 'T_JQUERY_LINK' => ($config['load_jquery_cdn'] && !empty($config['load_jquery_url'])) ? $config['load_jquery_url'] : "{$web_path}assets/javascript/jquery.js?assets_version=" . $config['assets_version'], 'S_JQUERY_FALLBACK' => ($config['load_jquery_cdn']) ? true : false, - 'T_THEME_NAME' => rawurlencode($user->theme['style_path']), + 'T_THEME_NAME' => rawurlencode($user->style['style_path']), 'T_THEME_LANG_NAME' => $user->data['user_lang'], - 'T_TEMPLATE_NAME' => $user->theme['style_path'], - 'T_SUPER_TEMPLATE_NAME' => rawurlencode((isset($user->theme['style_parent_tree']) && $user->theme['style_parent_tree']) ? $user->theme['style_parent_tree'] : $user->theme['style_path']), + 'T_TEMPLATE_NAME' => $user->style['style_path'], + 'T_SUPER_TEMPLATE_NAME' => rawurlencode((isset($user->style['style_parent_tree']) && $user->style['style_parent_tree']) ? $user->style['style_parent_tree'] : $user->style['style_path']), 'T_IMAGES' => 'images', 'T_SMILIES' => $config['smilies_path'], 'T_AVATAR' => $config['avatar_path'], @@ -5137,3 +5136,16 @@ function phpbb_pcre_utf8_support() } return $utf8_pcre_properties; } + +/** +* Casts a numeric string $input to an appropriate numeric type (i.e. integer or float) +* +* @param string $input A numeric string. +* +* @return int|float Integer $input if $input fits integer, +* float $input otherwise. +*/ +function phpbb_to_numeric($input) +{ + return ($input > PHP_INT_MAX) ? (float) $input : (int) $input; +} diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index 1f45d5e8e1..545f75ad67 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -1221,7 +1221,9 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, if ($can_watch) { $s_watching['link'] = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&" . (($is_watching) ? 'unwatch' : 'watch') . "=$mode&start=$start&hash=" . generate_link_hash("{$mode}_$match_id")); + $s_watching['link_toggle'] = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&" . ((!$is_watching) ? 'unwatch' : 'watch') . "=$mode&start=$start&hash=" . generate_link_hash("{$mode}_$match_id")); $s_watching['title'] = $user->lang[(($is_watching) ? 'STOP' : 'START') . '_WATCHING_' . strtoupper($mode)]; + $s_watching['title_toggle'] = $user->lang[((!$is_watching) ? 'STOP' : 'START') . '_WATCHING_' . strtoupper($mode)]; $s_watching['is_watching'] = $is_watching; } diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index 50af8fe019..46541acd44 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -463,17 +463,21 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, } /** -* Removes comments from schema files +* Removes "/* style" as well as "# style" comments from $input. +* +* @param string $input Input string +* +* @return string Input string with comments removed */ -function remove_comments($sql) +function phpbb_remove_comments($input) { // Remove /* */ comments (http://ostermiller.org/findcomment.html) - $sql = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $sql); + $input = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $input); // Remove # style comments - $sql = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $sql)); + $input = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $input)); - return $sql; + return $input; } /** diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index f77f54679f..c549f99091 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -1657,8 +1657,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u // First of all make sure the subject and topic title are having the correct length. // To achieve this without cutting off between special chars we convert to an array and then count the elements. - $subject = truncate_string($subject); - $data['topic_title'] = truncate_string($data['topic_title']); + $subject = truncate_string($subject, 120); + $data['topic_title'] = truncate_string($data['topic_title'], 120); // Collect some basic information about which tables and which rows to update/insert $sql_data = $topic_row = array(); diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index f70e20e616..33cb585b19 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -151,7 +151,8 @@ class filespec */ function is_image() { - return (strpos($this->mimetype, 'image/') !== false) ? true : false; + $mimetype = $this->get_mimetype($this->filename); + return (strpos($mimetype, 'image/') === 0); } /** @@ -200,17 +201,12 @@ class filespec } /** - * Get mimetype. Utilize mime_content_type if the function exist. - * Not used at the moment... + * Get mimetype. Utilises the finfo class. */ function get_mimetype($filename) { - $mimetype = ''; - - if (function_exists('mime_content_type')) - { - $mimetype = mime_content_type($filename); - } + $finfo = new finfo(FILEINFO_MIME_TYPE); + $mimetype = $finfo->file($filename); // Some browsers choke on a mimetype of application/octet-stream if (!$mimetype || $mimetype == 'application/octet-stream') @@ -342,6 +338,7 @@ class filespec // Remove temporary filename @unlink($this->filename); + $this->filename = $this->destination_file; if (sizeof($this->error)) { diff --git a/phpBB/includes/php/ini.php b/phpBB/includes/php/ini.php new file mode 100644 index 0000000000..17e8c54a57 --- /dev/null +++ b/phpBB/includes/php/ini.php @@ -0,0 +1,175 @@ +<?php +/** +* +* @package phpBB +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Wrapper class for ini_get function. +* +* Provides easier handling of the different interpretations of ini values. +* +* @package phpBB +*/ +class phpbb_php_ini +{ + /** + * Simple wrapper for ini_get() + * See http://php.net/manual/en/function.ini-get.php + * + * @param string $varname The configuration option name. + * @return bool|string False if configuration option does not exist, + * the configuration option value (string) otherwise. + */ + public function get($varname) + { + return ini_get($varname); + } + + /** + * Gets the configuration option value as a trimmed string. + * + * @param string $varname The configuration option name. + * @return bool|string False if configuration option does not exist, + * the configuration option value (string) otherwise. + */ + public function get_string($varname) + { + $value = $this->get($varname); + + if ($value === false) + { + return false; + } + + return trim($value); + } + + /** + * Gets configuration option value as a boolean. + * Interprets the string value 'off' as false. + * + * @param string $varname The configuration option name. + * @return bool False if configuration option does not exist. + * False if configuration option is disabled. + * True otherwise. + */ + public function get_bool($varname) + { + $value = $this->get_string($varname); + + if (empty($value) || strtolower($value) == 'off') + { + return false; + } + + return true; + } + + /** + * Gets configuration option value as an integer. + * + * @param string $varname The configuration option name. + * @return bool|int False if configuration option does not exist, + * false if configuration option value is not numeric, + * the configuration option value (integer) otherwise. + */ + public function get_int($varname) + { + $value = $this->get_string($varname); + + if (!is_numeric($value)) + { + return false; + } + + return (int) $value; + } + + /** + * Gets configuration option value as a float. + * + * @param string $varname The configuration option name. + * @return bool|float False if configuration option does not exist, + * false if configuration option value is not numeric, + * the configuration option value (float) otherwise. + */ + public function get_float($varname) + { + $value = $this->get_string($varname); + + if (!is_numeric($value)) + { + return false; + } + + return (float) $value; + } + + /** + * Gets configuration option value in bytes. + * Converts strings like '128M' to bytes (integer or float). + * + * @param string $varname The configuration option name. + * @return bool|int|float False if configuration option does not exist, + * false if configuration option value is not well-formed, + * the configuration option value otherwise. + */ + public function get_bytes($varname) + { + $value = $this->get_string($varname); + + if ($value === false) + { + return false; + } + + if (is_numeric($value)) + { + // Already in bytes. + return phpbb_to_numeric($value); + } + else if (strlen($value) < 2) + { + // Single character. + return false; + } + else if (strlen($value) < 3 && $value[0] === '-') + { + // Two characters but the first one is a minus. + return false; + } + + $value_lower = strtolower($value); + $value_numeric = phpbb_to_numeric($value); + + switch ($value_lower[strlen($value_lower) - 1]) + { + case 'g': + $value_numeric *= 1024; + case 'm': + $value_numeric *= 1024; + case 'k': + $value_numeric *= 1024; + break; + + default: + // It's not already in bytes (and thus numeric) + // and does not carry a unit. + return false; + } + + return $value_numeric; + } +} diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php index 7c94038cc9..20dcb74c0d 100644 --- a/phpBB/includes/search/fulltext_mysql.php +++ b/phpBB/includes/search/fulltext_mysql.php @@ -27,8 +27,6 @@ class phpbb_search_fulltext_mysql extends phpbb_search_base var $split_words = array(); var $search_query; var $common_words = array(); - var $pcre_properties = false; - var $mbstring_regex = false; public function __construct(&$error) { @@ -36,18 +34,6 @@ class phpbb_search_fulltext_mysql extends phpbb_search_base $this->word_length = array('min' => $config['fulltext_mysql_min_word_len'], 'max' => $config['fulltext_mysql_max_word_len']); - // PHP may not be linked with the bundled PCRE lib and instead with an older version - if (phpbb_pcre_utf8_support()) - { - $this->pcre_properties = true; - } - - if (function_exists('mb_ereg')) - { - $this->mbstring_regex = true; - mb_regex_encoding('UTF-8'); - } - $error = false; } @@ -70,7 +56,7 @@ class phpbb_search_fulltext_mysql extends phpbb_search_base if ($db->sql_layer != 'mysql4' && $db->sql_layer != 'mysqli') { - return $user->lang['FULLTEXT_MYSQL_INCOMPATIBLE_VERSION']; + return $user->lang['FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE']; } $result = $db->sql_query('SHOW TABLE STATUS LIKE \'' . POSTS_TABLE . '\''); @@ -133,40 +119,10 @@ class phpbb_search_fulltext_mysql extends phpbb_search_base $split_keywords = preg_replace("#[\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords))); // Split words - if ($this->pcre_properties) - { - $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); - } - else if ($this->mbstring_regex) - { - $split_keywords = mb_ereg_replace('([^\w\'*"()])', '\\1\\1', str_replace('\'\'', '\' \'', trim($split_keywords))); - } - else - { - $split_keywords = preg_replace('#([^\w\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); - } - - if ($this->pcre_properties) - { - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches); - $this->split_words = $matches[1]; - } - else if ($this->mbstring_regex) - { - mb_ereg_search_init($split_keywords, '(?:[^\w*"()]|^)([+\-|]?(?:[\w*"()]+\'?)*[\w*"()])(?:[^\w*"()]|$)'); - - while (($word = mb_ereg_search_regs())) - { - $this->split_words[] = $word[1]; - } - } - else - { - $matches = array(); - preg_match_all('#(?:[^\w*"()]|^)([+\-|]?(?:[\w*"()]+\'?)*[\w*"()])(?:[^\w*"()]|$)#u', $split_keywords, $matches); - $this->split_words = $matches[1]; - } + $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); + $matches = array(); + preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches); + $this->split_words = $matches[1]; // We limit the number of allowed keywords to minimize load on the database if ($config['max_num_search_keywords'] && sizeof($this->split_words) > $config['max_num_search_keywords']) @@ -271,41 +227,10 @@ class phpbb_search_fulltext_mysql extends phpbb_search_base global $config; // Split words - if ($this->pcre_properties) - { - $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); - } - else if ($this->mbstring_regex) - { - $text = mb_ereg_replace('([^\w\'*])', '\\1\\1', str_replace('\'\'', '\' \'', trim($text))); - } - else - { - $text = preg_replace('#([^\w\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); - } - - if ($this->pcre_properties) - { - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches); - $text = $matches[1]; - } - else if ($this->mbstring_regex) - { - mb_ereg_search_init($text, '(?:[^\w*]|^)([+\-|]?(?:[\w*]+\'?)*[\w*])(?:[^\w*]|$)'); - - $text = array(); - while (($word = mb_ereg_search_regs())) - { - $text[] = $word[1]; - } - } - else - { - $matches = array(); - preg_match_all('#(?:[^\w*]|^)([+\-|]?(?:[\w*]+\'?)*[\w*])(?:[^\w*]|$)#u', $text, $matches); - $text = $matches[1]; - } + $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); + $matches = array(); + preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches); + $text = $matches[1]; // remove too short or too long words $text = array_values($text); @@ -748,7 +673,7 @@ class phpbb_search_fulltext_mysql extends phpbb_search_base { if ($db->sql_layer == 'mysqli' || version_compare($db->sql_server_info(true), '4.1.3', '>=')) { - //$alter[] = 'MODIFY post_subject varchar(100) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; + $alter[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; } else { @@ -909,14 +834,6 @@ class phpbb_search_fulltext_mysql extends phpbb_search_base $tpl = ' <dl> - <dt><label>' . $user->lang['FULLTEXT_MYSQL_PCRE'] . '</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_PCRE_EXPLAIN'] . '</span></dt> - <dd>' . (($this->pcre_properties) ? $user->lang['YES'] : $user->lang['NO']) . ' (PHP ' . PHP_VERSION . ')</dd> - </dl> - <dl> - <dt><label>' . $user->lang['FULLTEXT_MYSQL_MBSTRING'] . '</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_MBSTRING_EXPLAIN'] . '</span></dt> - <dd>' . (($this->mbstring_regex) ? $user->lang['YES'] : $user->lang['NO']). '</dd> - </dl> - <dl> <dt><label>' . $user->lang['MIN_SEARCH_CHARS'] . ':</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN'] . '</span></dt> <dd>' . $config['fulltext_mysql_min_word_len'] . '</dd> </dl> diff --git a/phpBB/includes/search/fulltext_postgres.php b/phpBB/includes/search/fulltext_postgres.php new file mode 100644 index 0000000000..84ce674564 --- /dev/null +++ b/phpBB/includes/search/fulltext_postgres.php @@ -0,0 +1,856 @@ +<?php +/** +* +* @package search +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* fulltext_postgres +* Fulltext search for PostgreSQL +* @package search +*/ +class phpbb_search_fulltext_postgres extends phpbb_search_base +{ + private $stats = array(); + private $split_words = array(); + private $tsearch_usable = false; + private $version; + private $tsearch_query; + private $phrase_search = false; + public $search_query; + public $common_words = array(); + public $word_length = array(); + + /** + * Constructor + * Creates a new phpbb_search_fulltext_postgres, which is used as a search backend. + * + * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false + */ + public function __construct(&$error) + { + global $db, $config; + + $this->word_length = array('min' => $config['fulltext_postgres_min_word_len'], 'max' => $config['fulltext_postgres_max_word_len']); + + + if ($db->sql_layer == 'postgres') + { + $pgsql_version = explode(',', substr($db->sql_server_info(), 10)); + $this->version = trim($pgsql_version[0]); + if (version_compare($this->version, '8.3', '>=')) + { + $this->tsearch_usable = true; + } + } + + $error = false; + } + + /** + * Returns the name of this search backend to be displayed to administrators + * + * @return string Name + * + * @access public + */ + public function get_name() + { + return 'PostgreSQL Fulltext'; + } + + /** + * Returns if phrase search is supported or not + * + * @return bool + * + * @access public + */ + public function supports_phrase_search() + { + return $this->phrase_search; + } + + /** + * Checks for correct PostgreSQL version and stores min/max word length in the config + * + * @return string|bool Language key of the error/incompatiblity occured + * + * @access public + */ + function init() + { + global $db, $user; + + if ($db->sql_layer != 'postgres') + { + return $user->lang['FULLTEXT_POSTGRES_INCOMPATIBLE_DATABASE']; + } + + if (!$this->tsearch_usable) + { + return $user->lang['FULLTEXT_POSTGRES_TS_NOT_USABLE']; + } + + return false; + } + + /** + * Splits keywords entered by a user into an array of words stored in $this->split_words + * Stores the tidied search query in $this->search_query + * + * @param string &$keywords Contains the keyword as entered by the user + * @param string $terms is either 'all' or 'any' + * @return bool false if no valid keywords were found and otherwise true + * + * @access public + */ + function split_keywords(&$keywords, $terms) + { + global $config; + + if ($terms == 'all') + { + $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#\+#', '#-#', '#\|#'); + $replace = array(' +', ' |', ' -', ' +', ' -', ' |'); + + $keywords = preg_replace($match, $replace, $keywords); + } + + // Filter out as above + $split_keywords = preg_replace("#[\"\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords))); + + // Split words + $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); + $matches = array(); + preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches); + $this->split_words = $matches[1]; + + foreach ($this->split_words as $i => $word) + { + $clean_word = preg_replace('#^[+\-|"]#', '', $word); + + // check word length + $clean_len = utf8_strlen(str_replace('*', '', $clean_word)); + if (($clean_len < $config['fulltext_postgres_min_word_len']) || ($clean_len > $config['fulltext_postgres_max_word_len'])) + { + $this->common_words[] = $word; + unset($this->split_words[$i]); + } + } + + if ($terms == 'any') + { + $this->search_query = ''; + $this->tsearch_query = ''; + foreach ($this->split_words as $word) + { + if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0) || (strpos($word, '|') === 0)) + { + $word = substr($word, 1); + } + $this->search_query .= $word . ' '; + $this->tsearch_query .= '|' . $word . ' '; + } + } + else + { + $this->search_query = ''; + $this->tsearch_query = ''; + foreach ($this->split_words as $word) + { + if (strpos($word, '+') === 0) + { + $this->search_query .= $word . ' '; + $this->tsearch_query .= '&' . substr($word, 1) . ' '; + } + elseif (strpos($word, '-') === 0) + { + $this->search_query .= $word . ' '; + $this->tsearch_query .= '&!' . substr($word, 1) . ' '; + } + elseif (strpos($word, '|') === 0) + { + $this->search_query .= $word . ' '; + $this->tsearch_query .= '|' . substr($word, 1) . ' '; + } + else + { + $this->search_query .= '+' . $word . ' '; + $this->tsearch_query .= '&' . $word . ' '; + } + } + } + + $this->tsearch_query = substr($this->tsearch_query, 1); + $this->search_query = utf8_htmlspecialchars($this->search_query); + + if ($this->search_query) + { + $this->split_words = array_values($this->split_words); + sort($this->split_words); + return true; + } + return false; + } + + /** + * Turns text into an array of words + * @param string $text contains post text/subject + * + * @access public + */ + function split_message($text) + { + global $config; + + // Split words + $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); + $matches = array(); + preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches); + $text = $matches[1]; + + // remove too short or too long words + $text = array_values($text); + for ($i = 0, $n = sizeof($text); $i < $n; $i++) + { + $text[$i] = trim($text[$i]); + if (utf8_strlen($text[$i]) < $config['fulltext_postgres_min_word_len'] || utf8_strlen($text[$i]) > $config['fulltext_postgres_max_word_len']) + { + unset($text[$i]); + } + } + + return array_values($text); + } + + /** + * Performs a search on keywords depending on display specific params. You have to run split_keywords() first. + * + * @param string $type contains either posts or topics depending on what should be searched for + * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) + * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) + * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query + * @param string $sort_key is the key of $sort_by_sql for the selected sorting + * @param string $sort_dir is either a or d representing ASC and DESC + * @param string $sort_days specifies the maximum amount of days a post may be old + * @param array $ex_fid_ary specifies an array of forum ids which should not be searched + * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts + * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched + * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty + * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match + * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered + * @param int $start indicates the first index of the page + * @param int $per_page number of ids each page is supposed to contain + * @return boolean|int total number of results + * + * @access public + */ + function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) + { + global $config, $db; + + // No keywords? No posts. + if (!$this->search_query) + { + return false; + } + + // generate a search_key from all the options to identify the results + $search_key = md5(implode('#', array( + implode(', ', $this->split_words), + $type, + $fields, + $terms, + $sort_days, + $sort_key, + $topic_id, + implode(',', $ex_fid_ary), + implode(',', $m_approve_fid_ary), + implode(',', $author_ary) + ))); + + // try reading the results from cache + $result_count = 0; + if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) + { + return $result_count; + } + + $id_ary = array(); + + $join_topic = ($type == 'posts') ? false : true; + + // Build sql strings for sorting + $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); + $sql_sort_table = $sql_sort_join = ''; + + switch ($sql_sort[0]) + { + case 'u': + $sql_sort_table = USERS_TABLE . ' u, '; + $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; + break; + + case 't': + $join_topic = true; + break; + + case 'f': + $sql_sort_table = FORUMS_TABLE . ' f, '; + $sql_sort_join = ' AND f.forum_id = p.forum_id '; + break; + } + + // Build some display specific sql strings + switch ($fields) + { + case 'titleonly': + $sql_match = 'p.post_subject'; + $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; + $join_topic = true; + break; + + case 'msgonly': + $sql_match = 'p.post_text'; + $sql_match_where = ''; + break; + + case 'firstpost': + $sql_match = 'p.post_subject, p.post_text'; + $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; + $join_topic = true; + break; + + default: + $sql_match = 'p.post_subject, p.post_text'; + $sql_match_where = ''; + break; + } + + if (!sizeof($m_approve_fid_ary)) + { + $m_approve_fid_sql = ' AND p.post_approved = 1'; + } + else if ($m_approve_fid_ary === array(-1)) + { + $m_approve_fid_sql = ''; + } + else + { + $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')'; + } + + $sql_select = ($type == 'posts') ? 'p.post_id' : 'DISTINCT t.topic_id'; + $sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : ''; + $field = ($type == 'posts') ? 'post_id' : 'topic_id'; + $sql_author = (sizeof($author_ary) == 1) ? ' = ' . $author_ary[0] : 'IN (' . implode(', ', $author_ary) . ')'; + + if (sizeof($author_ary) && $author_name) + { + // first one matches post of registered users, second one guests and deleted users + $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; + } + else if (sizeof($author_ary)) + { + $sql_author = ' AND ' . $db->sql_in_set('p.poster_id', $author_ary); + } + else + { + $sql_author = ''; + } + + $sql_where_options = $sql_sort_join; + $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : ''; + $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : ''; + $sql_where_options .= (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; + $sql_where_options .= $m_approve_fid_sql; + $sql_where_options .= $sql_author; + $sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; + $sql_where_options .= $sql_match_where; + + $tmp_sql_match = array(); + foreach (explode(',', $sql_match) as $sql_match_column) + { + $tmp_sql_match[] = "to_tsvector ('" . $db->sql_escape($config['fulltext_postgres_ts_name']) . "', " . $sql_match_column . ") @@ to_tsquery ('" . $db->sql_escape($config['fulltext_postgres_ts_name']) . "', '" . $db->sql_escape($this->tsearch_query) . "')"; + } + + $sql = "SELECT $sql_select + FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p + WHERE (" . implode(' OR ', $tmp_sql_match) . ") + $sql_where_options + ORDER BY $sql_sort"; + $result = $db->sql_query_limit($sql, $config['search_block_size'], $start); + + while ($row = $db->sql_fetchrow($result)) + { + $id_ary[] = $row[$field]; + } + $db->sql_freeresult($result); + + $id_ary = array_unique($id_ary); + + if (!sizeof($id_ary)) + { + return false; + } + + // if the total result count is not cached yet, retrieve it from the db + if (!$result_count) + { + $result_count = sizeof ($id_ary); + + if (!$result_count) + { + return false; + } + } + + // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page + $this->save_ids($search_key, implode(' ', $this->split_words), $author_ary, $result_count, $id_ary, $start, $sort_dir); + $id_ary = array_slice($id_ary, 0, (int) $per_page); + + return $result_count; + } + + /** + * Performs a search on an author's posts without caring about message contents. Depends on display specific params + * + * @param string $type contains either posts or topics depending on what should be searched for + * @param boolean $firstpost_only if true, only topic starting posts will be considered + * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query + * @param string $sort_key is the key of $sort_by_sql for the selected sorting + * @param string $sort_dir is either a or d representing ASC and DESC + * @param string $sort_days specifies the maximum amount of days a post may be old + * @param array $ex_fid_ary specifies an array of forum ids which should not be searched + * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts + * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched + * @param array $author_ary an array of author ids + * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match + * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered + * @param int $start indicates the first index of the page + * @param int $per_page number of ids each page is supposed to contain + * @return boolean|int total number of results + * + * @access public + */ + function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) + { + global $config, $db; + + // No author? No posts. + if (!sizeof($author_ary)) + { + return 0; + } + + // generate a search_key from all the options to identify the results + $search_key = md5(implode('#', array( + '', + $type, + ($firstpost_only) ? 'firstpost' : '', + '', + '', + $sort_days, + $sort_key, + $topic_id, + implode(',', $ex_fid_ary), + implode(',', $m_approve_fid_ary), + implode(',', $author_ary), + $author_name, + ))); + + // try reading the results from cache + $result_count = 0; + if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) + { + return $result_count; + } + + $id_ary = array(); + + // Create some display specific sql strings + if ($author_name) + { + // first one matches post of registered users, second one guests and deleted users + $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; + } + else + { + $sql_author = $db->sql_in_set('p.poster_id', $author_ary); + } + $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; + $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : ''; + $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; + $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : ''; + + // Build sql strings for sorting + $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); + $sql_sort_table = $sql_sort_join = ''; + switch ($sql_sort[0]) + { + case 'u': + $sql_sort_table = USERS_TABLE . ' u, '; + $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; + break; + + case 't': + $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : ''; + $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : ''; + break; + + case 'f': + $sql_sort_table = FORUMS_TABLE . ' f, '; + $sql_sort_join = ' AND f.forum_id = p.forum_id '; + break; + } + + if (!sizeof($m_approve_fid_ary)) + { + $m_approve_fid_sql = ' AND p.post_approved = 1'; + } + else if ($m_approve_fid_ary == array(-1)) + { + $m_approve_fid_sql = ''; + } + else + { + $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')'; + } + + // Build the query for really selecting the post_ids + if ($type == 'posts') + { + $sql = "SELECT p.post_id + FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " + WHERE $sql_author + $sql_topic_id + $sql_firstpost + $m_approve_fid_sql + $sql_fora + $sql_sort_join + $sql_time + ORDER BY $sql_sort"; + $field = 'post_id'; + } + else + { + $sql = "SELECT t.topic_id + FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p + WHERE $sql_author + $sql_topic_id + $sql_firstpost + $m_approve_fid_sql + $sql_fora + AND t.topic_id = p.topic_id + $sql_sort_join + $sql_time + GROUP BY t.topic_id, $sort_by_sql[$sort_key] + ORDER BY $sql_sort"; + $field = 'topic_id'; + } + + // Only read one block of posts from the db and then cache it + $result = $db->sql_query_limit($sql, $config['search_block_size'], $start); + + while ($row = $db->sql_fetchrow($result)) + { + $id_ary[] = $row[$field]; + } + $db->sql_freeresult($result); + + // retrieve the total result count if needed + if (!$result_count) + { + $result_count = sizeof ($id_ary); + + if (!$result_count) + { + return false; + } + } + + if (sizeof($id_ary)) + { + $this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir); + $id_ary = array_slice($id_ary, 0, $per_page); + + return $result_count; + } + return false; + } + + /** + * Destroys cached search results, that contained one of the new words in a post so the results won't be outdated. + * + * @param string $mode contains the post mode: edit, post, reply, quote ... + * @param int $post_id contains the post id of the post to index + * @param string $message contains the post text of the post + * @param string $subject contains the subject of the post to index + * @param int $poster_id contains the user id of the poster + * @param int $forum_id contains the forum id of parent forum of the post + * + * @access public + */ + function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) + { + global $db; + + // Split old and new post/subject to obtain array of words + $split_text = $this->split_message($message); + $split_title = ($subject) ? $this->split_message($subject) : array(); + + $words = array_unique(array_merge($split_text, $split_title)); + + unset($split_text); + unset($split_title); + + // destroy cached search results containing any of the words removed or added + $this->destroy_cache($words, array($poster_id)); + + unset($words); + } + + /** + * Destroy cached results, that might be outdated after deleting a post + * + * @access public + */ + function index_remove($post_ids, $author_ids, $forum_ids) + { + $this->destroy_cache(array(), $author_ids); + } + + /** + * Destroy old cache entries + * + * @access public + */ + function tidy() + { + global $db, $config; + + // destroy too old cached search results + $this->destroy_cache(array()); + + set_config('search_last_gc', time(), true); + } + + /** + * Create fulltext index + * + * @return string|bool error string is returned incase of errors otherwise false + * + * @access public + */ + function create_index($acp_module, $u_action) + { + global $db, $config; + + // Make sure we can actually use PostgreSQL with fulltext indexes + if ($error = $this->init()) + { + return $error; + } + + if (empty($this->stats)) + { + $this->get_stats(); + } + + if (!isset($this->stats['post_subject'])) + { + $db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $config['fulltext_postgres_ts_name'] . "_post_subject ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $db->sql_escape($config['fulltext_postgres_ts_name']) . "', post_subject))"); + } + + if (!isset($this->stats['post_text'])) + { + $db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $config['fulltext_postgres_ts_name'] . "_post_text ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $db->sql_escape($config['fulltext_postgres_ts_name']) . "', post_text))"); + } + + $db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); + + return false; + } + + /** + * Drop fulltext index + * + * @return string|bool error string is returned incase of errors otherwise false + * + * @access public + */ + function delete_index($acp_module, $u_action) + { + global $db; + + // Make sure we can actually use PostgreSQL with fulltext indexes + if ($error = $this->init()) + { + return $error; + } + + if (empty($this->stats)) + { + $this->get_stats(); + } + + if (isset($this->stats['post_subject'])) + { + $db->sql_query('DROP INDEX ' . $this->stats['post_subject']['relname']); + } + + if (isset($this->stats['post_text'])) + { + $db->sql_query('DROP INDEX ' . $this->stats['post_text']['relname']); + } + + $db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); + + return false; + } + + /** + * Returns true if both FULLTEXT indexes exist + * + * @access public + */ + function index_created() + { + if (empty($this->stats)) + { + $this->get_stats(); + } + + return (isset($this->stats['post_text']) && isset($this->stats['post_subject'])) ? true : false; + } + + /** + * Returns an associative array containing information about the indexes + * + * @access public + */ + function index_stats() + { + global $user; + + if (empty($this->stats)) + { + $this->get_stats(); + } + + return array( + $user->lang['FULLTEXT_POSTGRES_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0, + ); + } + + /** + * Computes the stats and store them in the $this->stats associative array + * + * @access private + */ + function get_stats() + { + global $db, $config; + + if ($db->sql_layer != 'postgres') + { + $this->stats = array(); + return; + } + + $sql = "SELECT c2.relname, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) AS indexdef + FROM pg_catalog.pg_class c1, pg_catalog.pg_index i, pg_catalog.pg_class c2 + WHERE c1.relname = '" . POSTS_TABLE . "' + AND pg_catalog.pg_table_is_visible(c1.oid) + AND c1.oid = i.indrelid + AND i.indexrelid = c2.oid"; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + // deal with older PostgreSQL versions which didn't use Index_type + if (strpos($row['indexdef'], 'to_tsvector') !== false) + { + if ($row['relname'] == POSTS_TABLE . '_' . $config['fulltext_postgres_ts_name'] . '_post_text' || $row['relname'] == POSTS_TABLE . '_post_text') + { + $this->stats['post_text'] = $row; + } + else if ($row['relname'] == POSTS_TABLE . '_' . $config['fulltext_postgres_ts_name'] . '_post_subject' || $row['relname'] == POSTS_TABLE . '_post_subject') + { + $this->stats['post_subject'] = $row; + } + } + } + $db->sql_freeresult($result); + + $this->stats['total_posts'] = $config['num_posts']; + } + + /** + * Display various options that can be configured for the backend from the acp + * + * @return associative array containing template and config variables + * + * @access public + */ + function acp() + { + global $user, $config, $db; + + $tpl = ' + <dl> + <dt><label>' . $user->lang['FULLTEXT_POSTGRES_VERSION_CHECK'] . '</label><br /><span>' . $user->lang['FULLTEXT_POSTGRES_VERSION_CHECK_EXPLAIN'] . '</span></dt> + <dd>' . (($this->tsearch_usable) ? $user->lang['YES'] : $user->lang['NO']) . ' (PostgreSQL ' . $this->version . ')</dd> + </dl> + <dl> + <dt><label>' . $user->lang['FULLTEXT_POSTGRES_TS_NAME'] . '</label><br /><span>' . $user->lang['FULLTEXT_POSTGRES_TS_NAME_EXPLAIN'] . '</span></dt> + <dd><select name="config[fulltext_postgres_ts_name]">'; + + if ($db->sql_layer == 'postgres' && $this->tsearch_usable) + { + $sql = 'SELECT cfgname AS ts_name + FROM pg_ts_config'; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $tpl .= '<option value="' . $row['ts_name'] . '"' . ($row['ts_name'] === $config['fulltext_postgres_ts_name'] ? ' selected="selected"' : '') . '>' . $row['ts_name'] . '</option>'; + } + $db->sql_freeresult($result); + } + else + { + $tpl .= '<option value="' . $config['fulltext_postgres_ts_name'] . '" selected="selected">' . $config['fulltext_postgres_ts_name'] . '</option>'; + } + + $tpl .= '</select></dd> + </dl> + <dl> + <dt><label for="fulltext_postgres_min_word_len">' . $user->lang['FULLTEXT_POSTGRES_MIN_WORD_LEN'] . ':</label><br /><span>' . $user->lang['FULLTEXT_POSTGRES_MIN_WORD_LEN_EXPLAIN'] . '</span></dt> + <dd><input id="fulltext_postgres_min_word_len" type="text" size="3" maxlength="3" name="config[fulltext_postgres_min_word_len]" value="' . (int) $config['fulltext_postgres_min_word_len'] . '" /></dd> + </dl> + <dl> + <dt><label for="fulltext_postgres_max_word_len">' . $user->lang['FULLTEXT_POSTGRES_MAX_WORD_LEN'] . ':</label><br /><span>' . $user->lang['FULLTEXT_POSTGRES_MAX_WORD_LEN_EXPLAIN'] . '</span></dt> + <dd><input id="fulltext_postgres_max_word_len" type="text" size="3" maxlength="3" name="config[fulltext_postgres_max_word_len]" value="' . (int) $config['fulltext_postgres_max_word_len'] . '" /></dd> + </dl> + '; + + // These are fields required in the config table + return array( + 'tpl' => $tpl, + 'config' => array('fulltext_postgres_ts_name' => 'string', 'fulltext_postgres_min_word_len' => 'integer:0:255', 'fulltext_postgres_max_word_len' => 'integer:0:255') + ); + } +} diff --git a/phpBB/includes/style/style.php b/phpBB/includes/style/style.php index 3f470015f6..22e0f1d67a 100644 --- a/phpBB/includes/style/style.php +++ b/phpBB/includes/style/style.php @@ -89,9 +89,9 @@ class phpbb_style */ public function set_style() { - $style_name = $this->user->theme['style_path']; - $style_dirs = ($this->user->theme['style_parent_id']) ? array_reverse(explode('/', $this->user->theme['style_parent_tree'])) : array(); - $paths = array($this->get_style_path($style_name)); + $style_path = $this->user->style['style_path']; + $style_dirs = ($this->user->style['style_parent_id']) ? array_reverse(explode('/', $this->user->style['style_parent_tree'])) : array(); + $paths = array($this->get_style_path($style_path)); foreach ($style_dirs as $dir) { $paths[] = $this->get_style_path($dir); @@ -100,7 +100,7 @@ class phpbb_style // Add 'all' path, used as last fallback path by hooks and extensions $paths[] = $this->get_style_path('all'); - return $this->set_custom_style($style_name, $paths); + return $this->set_custom_style($style_path, $paths); } /** diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 4a2593b757..ad2e35de6a 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -905,12 +905,12 @@ class phpbb_template_filter extends php_user_filter if (substr($filename, 0, strlen($this->phpbb_root_path)) != $this->phpbb_root_path) { // Absolute path, include as is - return ' $_template->_js_include(\'' . addslashes($filename) . '\', false); '; + return ' $_template->_js_include(\'' . addslashes($filename) . '\', false, false); '; } // Relative path, remove root path from it $filename = substr($filename, strlen($this->phpbb_root_path)); - return ' global $phpbb_root_path; $_template->_js_include($phpbb_root_path . \'' . addslashes($filename) . '\', false); '; + return ' $_template->_js_include(\'' . addslashes($filename) . '\', false, true); '; } /** diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index e6512c8417..8ab3c44be3 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -496,14 +496,19 @@ class phpbb_template * * @param string $file file name * @param bool $locate True if file needs to be located + * @param bool $relative True if path is relative to phpBB root directory. Ignored if $locate == true */ - public function _js_include($file, $locate = false) + public function _js_include($file, $locate = false, $relative = false) { // Locate file if ($locate) { $file = $this->locator->get_first_file_location(array($file), true, true); } + else if ($relative) + { + $file = $this->phpbb_root_path . $file; + } $file .= (strpos($file, '?') === false) ? '?' : '&'; $file .= 'assets_version=' . $this->config['assets_version']; diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php index 09c0318de9..968538a178 100644 --- a/phpBB/includes/ucp/info/ucp_profile.php +++ b/phpBB/includes/ucp/info/ucp_profile.php @@ -23,6 +23,7 @@ class ucp_profile_info 'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => '', 'cat' => array('UCP_PROFILE')), 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)', 'cat' => array('UCP_PROFILE')), 'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')), + 'autologin_keys'=> array('title' => 'UCP_PROFILE_AUTOLOGIN_KEYS', 'auth' => '', 'cat' => array('UCP_PROFILE')), ), ); } diff --git a/phpBB/includes/ucp/ucp_pm_options.php b/phpBB/includes/ucp/ucp_pm_options.php index bde5d1dfcf..bf7334b307 100644 --- a/phpBB/includes/ucp/ucp_pm_options.php +++ b/phpBB/includes/ucp/ucp_pm_options.php @@ -327,10 +327,23 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit trigger_error('RULE_ALREADY_DEFINED'); } + // Prevent users from flooding the rules table + $sql = 'SELECT COUNT(rule_id) AS num_rules + FROM ' . PRIVMSGS_RULES_TABLE . ' + WHERE user_id = ' . (int) $user->data['user_id']; + $result = $db->sql_query($sql); + $num_rules = (int) $db->sql_fetchfield('num_rules'); + $db->sql_freeresult($result); + + if ($num_rules >= 5000) + { + trigger_error('RULE_LIMIT_REACHED'); + } + $sql = 'INSERT INTO ' . PRIVMSGS_RULES_TABLE . ' ' . $db->sql_build_array('INSERT', $rule_ary); $db->sql_query($sql); - // Update users message rules + // Set the user_message_rules bit $sql = 'UPDATE ' . USERS_TABLE . ' SET user_message_rules = 1 WHERE user_id = ' . $user->data['user_id']; @@ -377,7 +390,7 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - // Update users message rules + // Unset the user_message_rules bit if (!$row) { $sql = 'UPDATE ' . USERS_TABLE . ' diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index 9d81503f0a..2ac82fb52f 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -618,6 +618,60 @@ class ucp_profile } break; + + case 'autologin_keys': + + add_form_key('ucp_autologin_keys'); + + if ($submit) + { + $keys = request_var('keys', array('')); + + if (!check_form_key('ucp_autologin_keys')) + { + $error[] = 'FORM_INVALID'; + } + + if (!sizeof($error)) + { + if (!empty($keys)) + { + $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' + WHERE user_id = ' . (int) $user->data['user_id'] . ' + AND ' . $db->sql_in_set('key_id', $keys) ; + + $db->sql_query($sql); + + meta_refresh(3, $this->u_action); + $message = $user->lang['AUTOLOGIN_SESSION_KEYS_DELETED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>'); + trigger_error($message); + } + } + + // Replace "error" strings with their real, localised form + $error = array_map(array($user, 'lang'), $error); + } + + $sql = 'SELECT key_id, last_ip, last_login + FROM ' . SESSIONS_KEYS_TABLE . ' + WHERE user_id = ' . (int) $user->data['user_id']; + + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $template->assign_block_vars('sessions', array( + 'errors' => $error, + + 'KEY' => $row['key_id'], + 'IP' => $row['last_ip'], + 'LOGIN_TIME' => $user->format_date($row['last_login']), + )); + } + + $db->sql_freeresult($result); + + break; } $template->assign_vars(array( diff --git a/phpBB/includes/user.php b/phpBB/includes/user.php index 7dfb375a9b..fb6c1552e8 100644 --- a/phpBB/includes/user.php +++ b/phpBB/includes/user.php @@ -27,7 +27,7 @@ class phpbb_user extends phpbb_session { var $lang = array(); var $help = array(); - var $theme = array(); + var $style = array(); var $date_format; /** @@ -168,11 +168,11 @@ class phpbb_user extends phpbb_session FROM ' . STYLES_TABLE . " s WHERE s.style_id = $style_id"; $result = $db->sql_query($sql, 3600); - $this->theme = $db->sql_fetchrow($result); + $this->style = $db->sql_fetchrow($result); $db->sql_freeresult($result); // User has wrong style - if (!$this->theme && $style_id == $this->data['user_style']) + if (!$this->style && $style_id == $this->data['user_style']) { $style_id = $this->data['user_style'] = $config['default_style']; @@ -185,20 +185,17 @@ class phpbb_user extends phpbb_session FROM ' . STYLES_TABLE . " s WHERE s.style_id = $style_id"; $result = $db->sql_query($sql, 3600); - $this->theme = $db->sql_fetchrow($result); + $this->style = $db->sql_fetchrow($result); $db->sql_freeresult($result); } - if (!$this->theme) + if (!$this->style) { trigger_error('Could not get style data', E_USER_ERROR); } // Now parse the cfg file and cache it - $parsed_items = $cache->obtain_cfg_items($this->theme); - - // We are only interested in the theme configuration for now - $parsed_items = $parsed_items['theme']; + $parsed_items = $cache->obtain_cfg_items($this->style); $check_for = array( 'pagination_sep' => (string) ', ' @@ -206,12 +203,12 @@ class phpbb_user extends phpbb_session foreach ($check_for as $key => $default_value) { - $this->theme[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value; - settype($this->theme[$key], gettype($default_value)); + $this->style[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value; + settype($this->style[$key], gettype($default_value)); if (is_string($default_value)) { - $this->theme[$key] = htmlspecialchars($this->theme[$key]); + $this->style[$key] = htmlspecialchars($this->style[$key]); } } diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index dd2d04d3a6..360e12e0b6 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -2248,6 +2248,21 @@ function change_database_data(&$no_updates, $version) set_config('search_type', 'phpbb_search_' . $config['search_type']); } + if (!isset($config['fulltext_postgres_ts_name'])) + { + set_config('fulltext_postgres_ts_name', 'simple'); + } + + if (!isset($config['fulltext_postgres_min_word_len'])) + { + set_config('fulltext_postgres_min_word_len', 4); + } + + if (!isset($config['fulltext_postgres_max_word_len'])) + { + set_config('fulltext_postgres_max_word_len', 254); + } + if (!isset($config['load_jquery_cdn'])) { set_config('load_jquery_cdn', 0); @@ -2346,6 +2361,13 @@ function change_database_data(&$no_updates, $version) 'auth' => 'acl_a_styles', 'cat' => 'ACP_STYLE_MANAGEMENT', ), + 'autologin_keys' => array( + 'base' => 'ucp_profile', + 'class' => 'ucp', + 'title' => 'UCP_PROFILE_AUTOLOGIN_KEYS', + 'auth' => '', + 'cat' => 'UCP_PROFILE', + ), ); _add_modules($modules_to_install); diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index bafcefe3f5..40dee7b3d7 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -1178,7 +1178,7 @@ class install_install extends module $sql_query = preg_replace('#phpbb_#i', $data['table_prefix'], $sql_query); - $sql_query = remove_comments($sql_query); + $sql_query = phpbb_remove_comments($sql_query); $sql_query = split_sql_file($sql_query, $delimiter); @@ -1216,7 +1216,7 @@ class install_install extends module // Change language strings... $sql_query = preg_replace_callback('#\{L_([A-Z0-9\-_]*)\}#s', 'adjust_language_keys_callback', $sql_query); - $sql_query = remove_comments($sql_query); + $sql_query = phpbb_remove_comments($sql_query); $sql_query = split_sql_file($sql_query, ';'); foreach ($sql_query as $sql) diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index 307864825c..0bb1858c11 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -124,6 +124,9 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_native_co INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_native_load_upd', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_native_max_chars', '14'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_native_min_chars', '3'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_postgres_max_word_len', '254'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_postgres_min_word_len', '4'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_postgres_ts_name', 'simple'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('gzip_compress', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('hot_threshold', '25'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('icons_path', 'images/icons'); diff --git a/phpBB/language/en/acp/search.php b/phpBB/language/en/acp/search.php index 3dc89570bf..cd319c66a9 100644 --- a/phpBB/language/en/acp/search.php +++ b/phpBB/language/en/acp/search.php @@ -51,16 +51,24 @@ $lang = array_merge($lang, array( 'DELETING_INDEX_IN_PROGRESS' => 'Deleting the index in progress', 'DELETING_INDEX_IN_PROGRESS_EXPLAIN' => 'The search backend is currently cleaning its index. This can take a few minutes.', - 'FULLTEXT_MYSQL_INCOMPATIBLE_VERSION' => 'The MySQL fulltext backend can only be used with MySQL4 and above.', + 'FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE' => 'The MySQL fulltext backend can only be used with MySQL4 and above.', 'FULLTEXT_MYSQL_NOT_MYISAM' => 'MySQL fulltext indexes can only be used with MyISAM tables.', 'FULLTEXT_MYSQL_TOTAL_POSTS' => 'Total number of indexed posts', - 'FULLTEXT_MYSQL_MBSTRING' => 'Support for non-latin UTF-8 characters using mbstring:', - 'FULLTEXT_MYSQL_PCRE' => 'Support for non-latin UTF-8 characters using PCRE:', - 'FULLTEXT_MYSQL_MBSTRING_EXPLAIN' => 'If PCRE does not have unicode character properties, the search backend will try to use mbstring’s regular expression engine.', - 'FULLTEXT_MYSQL_PCRE_EXPLAIN' => 'This search backend requires PCRE unicode character properties, only available in PHP 4.4, 5.1 and above, if you want to search for non-latin characters.', 'FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN' => 'Words with at least this many characters will be indexed for searching. You or your host can only change this setting by changing the mysql configuration.', 'FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN' => 'Words with no more than this many characters will be indexed for searching. You or your host can only change this setting by changing the mysql configuration.', + 'FULLTEXT_POSTGRES_INCOMPATIBLE_DATABASE' => 'The PostgreSQL fulltext backend can only be used with PostgreSQL.', + 'FULLTEXT_POSTGRES_TS_NOT_USABLE' => 'The PostgreSQL fulltext backend can only be used with PostgreSQL 8.3 and above.', + 'FULLTEXT_POSTGRES_TOTAL_POSTS' => 'Total number of indexed posts', + 'FULLTEXT_POSTGRES_VERSION_CHECK' => 'PostgreSQL version', + 'FULLTEXT_POSTGRES_TS_NAME' => 'Text search Configuration Profile:', + 'FULLTEXT_POSTGRES_MIN_WORD_LEN' => 'Minimum word length for keywords', + 'FULLTEXT_POSTGRES_MAX_WORD_LEN' => 'Maximum word length for keywords', + 'FULLTEXT_POSTGRES_VERSION_CHECK_EXPLAIN' => 'This search backend requires PostgreSQL version 8.3 and above.', + 'FULLTEXT_POSTGRES_TS_NAME_EXPLAIN' => 'The Text search configuration profile used to determine the parser and dictionary.', + 'FULLTEXT_POSTGRES_MIN_WORD_LEN_EXPLAIN' => 'Words with at least this many characters will be included in the query to the database.', + 'FULLTEXT_POSTGRES_MAX_WORD_LEN_EXPLAIN' => 'Words with no more than this many characters will be included in the query to the database.', + 'GENERAL_SEARCH_SETTINGS' => 'General search settings', 'GO_TO_SEARCH_INDEX' => 'Go to search index page', diff --git a/phpBB/language/en/search.php b/phpBB/language/en/search.php index 5b6fdce0e7..d09b4303cd 100644 --- a/phpBB/language/en/search.php +++ b/phpBB/language/en/search.php @@ -72,6 +72,7 @@ $lang = array_merge($lang, array( 'WORDS_IN_NO_POST' => 'No posts were found because the words <strong>%s</strong> are not contained in any post.', 'POST_CHARACTERS' => 'characters of posts', + 'PHRASE_SEARCH_DISABLED' => 'Searching by exact phrase is not supported on this board.', 'RECENT_SEARCHES' => 'Recent searches', 'RESULT_DAYS' => 'Limit results to previous', @@ -81,6 +82,7 @@ $lang = array_merge($lang, array( 'SEARCHED_FOR' => 'Search term used', 'SEARCHED_TOPIC' => 'Searched topic', + 'SEARCHED_QUERY' => 'Searched query', 'SEARCH_ALL_TERMS' => 'Search for all terms or use query as entered', 'SEARCH_ANY_TERMS' => 'Search for any terms', 'SEARCH_AUTHOR' => 'Search for author', diff --git a/phpBB/language/en/ucp.php b/phpBB/language/en/ucp.php index 64a434d89c..14cc3fde27 100644 --- a/phpBB/language/en/ucp.php +++ b/phpBB/language/en/ucp.php @@ -87,6 +87,7 @@ $lang = array_merge($lang, array( 'ATTACHMENTS_EXPLAIN' => 'This is a list of attachments you have made in posts to this board.', 'ATTACHMENTS_DELETED' => 'Attachments successfully deleted.', 'ATTACHMENT_DELETED' => 'Attachment successfully deleted.', + 'AUTOLOGIN_SESSION_KEYS_DELETED'=> 'The selected persistent login keys were successfully deleted.', 'AVATAR_CATEGORY' => 'Category', 'AVATAR_EXPLAIN' => 'Maximum dimensions; width: %1$s, height: %2$s, file size: %3$.2f KiB.', 'AVATAR_FEATURES_DISABLED' => 'The avatar functionality is currently disabled.', @@ -255,6 +256,8 @@ $lang = array_merge($lang, array( 'LINK_REMOTE_SIZE' => 'Avatar dimensions', 'LINK_REMOTE_SIZE_EXPLAIN' => 'Specify the width and height of the avatar, leave blank to attempt automatic verification.', 'LOGIN_EXPLAIN_UCP' => 'Please login in order to access the User Control Panel.', + 'LOGIN_KEY' => 'Login Key', + 'LOGIN_TIME' => 'Login Time', 'LOGIN_REDIRECT' => 'You have been successfully logged in.', 'LOGOUT_FAILED' => 'You were not logged out, as the request did not match your session. Please contact the board administrator if you continue to experience problems.', 'LOGOUT_REDIRECT' => 'You have been successfully logged out.', @@ -376,6 +379,8 @@ $lang = array_merge($lang, array( 'PREFERENCES_UPDATED' => 'Your preferences have been updated.', 'PROFILE_INFO_NOTICE' => 'Please note that this information may be viewable to other members. Be careful when including any personal details. Any fields marked with a * must be completed.', 'PROFILE_UPDATED' => 'Your profile has been updated.', + 'PROFILE_AUTOLOGIN_KEYS' => 'The persistent login keys automatically log you in when you visit the board. If you logout, the persistent login key is deleted only on the computer you are using to logout. Here you can see persistent login keys created on other computers you used to access this site.', + 'PROFILE_NO_AUTOLOGIN_KEYS' => 'There are no saved persistent login keys.', 'RECIPIENT' => 'Recipient', 'RECIPIENTS' => 'Recipients', @@ -398,6 +403,7 @@ $lang = array_merge($lang, array( 'RULE_ADDED' => 'Rule successfully added.', 'RULE_ALREADY_DEFINED' => 'This rule was defined previously.', 'RULE_DELETED' => 'Rule successfully removed.', + 'RULE_LIMIT_REACHED' => 'You cannot add more PM rules. You have reached the maximum number of rules.', 'RULE_NOT_DEFINED' => 'Rule not correctly specified.', 'RULE_REMOVED_MESSAGES' => array( 1 => '%d private message was removed due to private message filters.', @@ -470,6 +476,7 @@ $lang = array_merge($lang, array( 'UCP_PROFILE_PROFILE_INFO' => 'Edit profile', 'UCP_PROFILE_REG_DETAILS' => 'Edit account settings', 'UCP_PROFILE_SIGNATURE' => 'Edit signature', + 'UCP_PROFILE_AUTOLOGIN_KEYS'=> 'Edit persistent login keys', 'UCP_USERGROUPS' => 'Usergroups', 'UCP_USERGROUPS_MEMBER' => 'Edit memberships', diff --git a/phpBB/search.php b/phpBB/search.php index 2b463aec9c..93cd0c31fd 100644 --- a/phpBB/search.php +++ b/phpBB/search.php @@ -596,13 +596,24 @@ if ($keywords || $author || $author_id || $search_id || $submit) $u_search .= ($search_fields != 'all') ? '&sf=' . $search_fields : ''; $u_search .= ($return_chars != 300) ? '&ch=' . $return_chars : ''; + // Check if search backend supports phrase search or not + $phrase_search_disabled = ''; + if (strpos(html_entity_decode($keywords), '"') !== false && method_exists($search, 'supports_phrase_search')) + { + $phrase_search_disabled = $search->supports_phrase_search() ? false : true; + } + $template->assign_vars(array( 'SEARCH_TITLE' => $l_search_title, 'SEARCH_MATCHES' => $l_search_matches, - 'SEARCH_WORDS' => $search->search_query, + 'SEARCH_WORDS' => $keywords, + 'SEARCHED_QUERY' => $search->search_query, 'IGNORED_WORDS' => (sizeof($search->common_words)) ? implode(' ', $search->common_words) : '', 'PAGINATION' => generate_pagination($u_search, $total_match_count, $per_page, $start), 'PAGE_NUMBER' => on_page($total_match_count, $per_page, $start), + + 'PHRASE_SEARCH_DISABLED' => $phrase_search_disabled, + 'TOTAL_MATCHES' => $total_match_count, 'SEARCH_IN_RESULTS' => ($search_id) ? false : true, diff --git a/phpBB/styles/prosilver/template/forumlist_body.html b/phpBB/styles/prosilver/template/forumlist_body.html index ca5e8abb1d..723c2ffeda 100644 --- a/phpBB/styles/prosilver/template/forumlist_body.html +++ b/phpBB/styles/prosilver/template/forumlist_body.html @@ -35,7 +35,12 @@ <!-- IF forumrow.MODERATORS --> <br /><strong>{forumrow.L_MODERATOR_STR}:</strong> {forumrow.MODERATORS} <!-- ENDIF --> - <!-- IF forumrow.SUBFORUMS and forumrow.S_LIST_SUBFORUMS --><br /><strong>{forumrow.L_SUBFORUM_STR}</strong> {forumrow.SUBFORUMS}<!-- ENDIF --> + <!-- IF .forumrow.subforum and forumrow.S_LIST_SUBFORUMS --> + <br /><strong>{forumrow.L_SUBFORUM_STR}</strong> + <!-- BEGIN subforum --> + <a href="{forumrow.subforum.U_SUBFORUM}" class="subforum<!-- IF forumrow.subforum.S_UNREAD --> unread<!-- ELSE --> read<!-- ENDIF -->" title="<!-- IF forumrow.subforum.UNREAD -->{L_UNREAD_POSTS}<!-- ELSE -->{L_NO_UNREAD_POSTS}<!-- ENDIF -->">{forumrow.subforum.SUBFORUM_NAME}</a><!-- IF not forumrow.subforum.S_LAST_ROW -->,<!-- ENDIF --> + <!-- END subforum --> + <!-- ENDIF --> </dt> <!-- IF forumrow.CLICKS --> <dd class="redirect"><span>{L_REDIRECTS}: {forumrow.CLICKS}</span></dd> diff --git a/phpBB/styles/prosilver/template/mcp_topic.html b/phpBB/styles/prosilver/template/mcp_topic.html index 2a6de3ce9d..8d0294d226 100644 --- a/phpBB/styles/prosilver/template/mcp_topic.html +++ b/phpBB/styles/prosilver/template/mcp_topic.html @@ -67,7 +67,7 @@ onload_functions.push('subPanels()'); <dl> <dt><label for="subject">{L_SPLIT_SUBJECT}:</label></dt> - <dd><input type="text" name="subject" id="subject" size="45" maxlength="64" tabindex="2" value="{SPLIT_SUBJECT}" title="{L_SPLIT_SUBJECT}" class="inputbox" /></dd> + <dd><input type="text" name="subject" id="subject" size="45" maxlength="124" tabindex="2" value="{SPLIT_SUBJECT}" title="{L_SPLIT_SUBJECT}" class="inputbox" /></dd> </dl> <dl> <dt><label>{L_SPLIT_FORUM}:</label></dt> diff --git a/phpBB/styles/prosilver/template/overall_footer.html b/phpBB/styles/prosilver/template/overall_footer.html index 2cb721073f..b473e7022c 100644 --- a/phpBB/styles/prosilver/template/overall_footer.html +++ b/phpBB/styles/prosilver/template/overall_footer.html @@ -8,9 +8,9 @@ <ul class="linklist"> <li class="icon-home"><a href="{U_INDEX}" accesskey="h">{L_INDEX}</a></li> <!-- IF not S_IS_BOT --> - <!-- IF S_WATCH_FORUM_LINK --><li <!-- IF S_WATCHING_FORUM -->class="icon-unsubscribe"<!-- ELSE -->class="icon-subscribe"<!-- ENDIF -->><a href="{S_WATCH_FORUM_LINK}" title="{S_WATCH_FORUM_TITLE}" data-ajax="alt_text" data-alt-text="<!-- IF S_WATCHING_FORUM -->{L_START_WATCHING_FORUM}<!-- ELSE -->{L_STOP_WATCHING_FORUM}<!-- ENDIF -->">{S_WATCH_FORUM_TITLE}</a></li><!-- ENDIF --> - <!-- IF U_WATCH_TOPIC --><li <!-- IF S_WATCHING_TOPIC -->class="icon-unsubscribe"<!-- ELSE -->class="icon-subscribe"<!-- ENDIF -->><a href="{U_WATCH_TOPIC}" title="{L_WATCH_TOPIC}" data-ajax="alt_text" data-alt-text="<!-- IF S_WATCHING_TOPIC -->{L_START_WATCHING_TOPIC}<!-- ELSE -->{L_STOP_WATCHING_TOPIC}<!-- ENDIF -->">{L_WATCH_TOPIC}</a></li><!-- ENDIF --> - <!-- IF U_BOOKMARK_TOPIC --><li class="icon-bookmark"><a href="{U_BOOKMARK_TOPIC}" title="{L_BOOKMARK_TOPIC}" data-ajax="alt_text" data-alt-text="<!-- IF S_BOOKMARKED_TOPIC -->{L_BOOKMARK_TOPIC_REAL}<!-- ELSE -->{L_BOOKMARK_TOPIC_REMOVE}<!-- ENDIF -->">{L_BOOKMARK_TOPIC}</a></li><!-- ENDIF --> + <!-- IF U_WATCH_FORUM_LINK --><li <!-- IF S_WATCHING_FORUM -->class="icon-unsubscribe"<!-- ELSE -->class="icon-subscribe"<!-- ENDIF -->><a href="{U_WATCH_FORUM_LINK}" title="{S_WATCH_FORUM_TITLE}" data-ajax="toggle_link" data-toggle-class="icon-<!-- IF not S_WATCHING_FORUM -->unsubscribe<!-- ELSE -->subscribe<!-- ENDIF -->" data-toggle-text="{S_WATCH_FORUM_TOGGLE}" data-toggle-url="{U_WATCH_FORUM_TOGGLE}">{S_WATCH_FORUM_TITLE}</a></li><!-- ENDIF --> + <!-- IF U_WATCH_TOPIC --><li <!-- IF S_WATCHING_TOPIC -->class="icon-unsubscribe"<!-- ELSE -->class="icon-subscribe"<!-- ENDIF -->><a href="{U_WATCH_TOPIC}" title="{S_WATCH_TOPIC_TITLE}" data-ajax="toggle_link" data-toggle-class="<!-- IF not S_WATCHING_TOPIC -->icon-unsubscribe<!-- ELSE -->icon-subscribe<!-- ENDIF -->" data-toggle-text="{S_WATCH_TOPIC_TOGGLE}" data-toggle-url="{U_WATCH_TOPIC_TOGGLE}">{S_WATCH_TOPIC_TITLE}</a></li><!-- ENDIF --> + <!-- IF U_BOOKMARK_TOPIC --><li class="icon-bookmark"><a href="{U_BOOKMARK_TOPIC}" title="{L_BOOKMARK_TOPIC}" data-ajax="alt_text" data-alt-text="{S_BOOKMARK_TOGGLE}">{S_BOOKMARK_TOPIC}</a></li><!-- ENDIF --> <!-- IF U_BUMP_TOPIC --><li class="icon-bump"><a href="{U_BUMP_TOPIC}" title="{L_BUMP_TOPIC}" data-ajax="true">{L_BUMP_TOPIC}</a></li><!-- ENDIF --> <!-- ENDIF --> <li class="rightside"><!-- IF U_TEAM --><a href="{U_TEAM}">{L_THE_TEAM}</a> • <!-- ENDIF --><!-- IF not S_IS_BOT --><a href="{U_DELETE_COOKIES}" data-ajax="true" data-refresh="true">{L_DELETE_COOKIES}</a> • <!-- ENDIF -->{S_TIMEZONE}</li> diff --git a/phpBB/styles/prosilver/template/posting_editor.html b/phpBB/styles/prosilver/template/posting_editor.html index 60766495c6..d1c86e7e13 100644 --- a/phpBB/styles/prosilver/template/posting_editor.html +++ b/phpBB/styles/prosilver/template/posting_editor.html @@ -103,7 +103,7 @@ <!-- IF S_POST_ACTION or S_PRIVMSGS or S_EDIT_DRAFT --> <dl style="clear: left;"> <dt><label for="subject">{L_SUBJECT}:</label></dt> - <dd><input type="text" name="subject" id="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->60<!-- ELSE -->64<!-- ENDIF -->" tabindex="2" value="{SUBJECT}{DRAFT_SUBJECT}" class="inputbox autowidth" /></dd> + <dd><input type="text" name="subject" id="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->120<!-- ELSE -->124<!-- ENDIF -->" tabindex="2" value="{SUBJECT}{DRAFT_SUBJECT}" class="inputbox autowidth" /></dd> </dl> <!-- IF CAPTCHA_TEMPLATE and S_CONFIRM_CODE --> <!-- DEFINE $CAPTCHA_TAB_INDEX = 3 --> diff --git a/phpBB/styles/prosilver/template/quickreply_editor.html b/phpBB/styles/prosilver/template/quickreply_editor.html index 724fdb85b8..5fcdf0f5d4 100644 --- a/phpBB/styles/prosilver/template/quickreply_editor.html +++ b/phpBB/styles/prosilver/template/quickreply_editor.html @@ -5,7 +5,7 @@ <fieldset class="fields1"> <dl style="clear: left;"> <dt><label for="subject">{L_SUBJECT}:</label></dt> - <dd><input type="text" name="subject" id="subject" size="45" maxlength="64" tabindex="2" value="{SUBJECT}" class="inputbox autowidth" /></dd> + <dd><input type="text" name="subject" id="subject" size="45" maxlength="124" tabindex="2" value="{SUBJECT}" class="inputbox autowidth" /></dd> </dl> <div id="message-box"> <textarea style="height: 9em;" name="message" rows="7" cols="76" tabindex="3" class="inputbox"></textarea> diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html index 5d75bd3d56..0a58605b31 100644 --- a/phpBB/styles/prosilver/template/search_results.html +++ b/phpBB/styles/prosilver/template/search_results.html @@ -1,7 +1,9 @@ <!-- INCLUDE overall_header.html --> <h2><!-- IF SEARCH_TITLE -->{SEARCH_TITLE}<!-- ELSE -->{SEARCH_MATCHES}<!-- ENDIF --><!-- IF SEARCH_WORDS -->: <a href="{U_SEARCH_WORDS}">{SEARCH_WORDS}</a><!-- ENDIF --></h2> +<!-- IF SEARCHED_QUERY --> <p>{L_SEARCHED_QUERY}: <strong>{SEARCHED_QUERY}</strong></p><!-- ENDIF --> <!-- IF IGNORED_WORDS --> <p>{L_IGNORED_TERMS}: <strong>{IGNORED_WORDS}</strong></p><!-- ENDIF --> +<!-- IF PHRASE_SEARCH_DISABLED --> <p><strong>{L_PHRASE_SEARCH_DISABLED}</strong></p><!-- ENDIF --> <!-- IF SEARCH_TOPIC --> <p><a class="{S_CONTENT_FLOW_BEGIN}" href="{U_SEARCH_TOPIC}">{L_RETURN_TO}: {SEARCH_TOPIC}</a></p> diff --git a/phpBB/styles/prosilver/template/ucp_groups_membership.html b/phpBB/styles/prosilver/template/ucp_groups_membership.html index a312911ae4..5cb238082a 100644 --- a/phpBB/styles/prosilver/template/ucp_groups_membership.html +++ b/phpBB/styles/prosilver/template/ucp_groups_membership.html @@ -93,7 +93,7 @@ <!-- IF pending.GROUP_DESC --><br />{pending.GROUP_DESC}<!-- ENDIF --> <!-- IF not pending.GROUP_SPECIAL --><br /><i>{pending.GROUP_STATUS}</i><!-- ENDIF --> </dt> - <dd class="mark"><input type="radio" name="selected" value="{pending.GROUP_ID}" <!-- IF pending.GROUP_SPECIAL -->disabled="diabled"<!-- ENDIF --> /></dd> + <dd class="mark"><input type="radio" name="selected" value="{pending.GROUP_ID}" <!-- IF pending.GROUP_SPECIAL -->disabled="disabled"<!-- ENDIF --> /></dd> </dl> </li> <!-- END pending --> diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html index bafb64dbc8..43e7de2e12 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html @@ -17,10 +17,9 @@ <div id="page-header"> <h1>{SITENAME}</h1> - <p>{SITE_DESCRIPTION}<br /><a href="{U_FORUM}">{U_FORUM}</a></p> + <p>{SITE_DESCRIPTION}</p> - <h2>{TOPIC_TITLE}</h2> - <p><a href="{U_TOPIC}">{U_TOPIC}</a></p> + <h2>{L_PRIVATE_MESSAGING}</h2> </div> <div id="page-body"> diff --git a/phpBB/styles/prosilver/template/ucp_profile_autologin_keys.html b/phpBB/styles/prosilver/template/ucp_profile_autologin_keys.html new file mode 100644 index 0000000000..a6c19508e2 --- /dev/null +++ b/phpBB/styles/prosilver/template/ucp_profile_autologin_keys.html @@ -0,0 +1,53 @@ +<!-- INCLUDE ucp_header.html --> + +<form id="ucp" method="post" action="{S_UCP_ACTION}"{S_FORM_ENCTYPE}> + +<h2>{L_TITLE}</h2> +<div class="panel"> + <div class="inner"> + + <fieldset> + <!-- IF .errors --> + <p class="error"> + <!-- BEGIN errors --> + {errors} <br /> + <!-- END errors --> + </p> + <!-- ENDIF --> + + <p>{L_PROFILE_AUTOLOGIN_KEYS}</p><br /> + <table cellspacing="1" class="table1"> + <thead> + <tr> + <th>{L_MARK}</th> + <th>{L_LOGIN_KEY}</th> + <th>{L_IP}</th> + <th>{L_LOGIN_TIME}</th> + </tr> + </thead> + <tbody> + <!-- BEGIN sessions --> + <!-- IF sessions.S_ROW_COUNT is even --><tr class="bg1"><!-- ELSE --><tr class="bg2"><!-- ENDIF --> + <td style="text-align: center"><input type="checkbox" name="keys[]" value="{sessions.KEY}" id="{sessions.KEY}"/></td> + <td><label for="{sessions.KEY}">{sessions.KEY}</label></td> + <td style="text-align: center">{sessions.IP}</td> + <td style="text-align: center">{sessions.LOGIN_TIME}</td> + </tr> + <!-- BEGINELSE --> + <tr><td colspan="4" class="bg1" style="text-align: center">{L_PROFILE_NO_AUTOLOGIN_KEYS}</td></tr> + <!-- END sessions --> + </tbody> + </table> + </fieldset> + </div> +</div> + +<!-- IF .sessions --> + <fieldset class="submit-buttons"> + {S_HIDDEN_FIELDS}<input type="submit" name="submit" value="{L_DELETE}" class="button1" /> + {S_FORM_TOKEN} + </fieldset> +<!-- ENDIF --> +</form> + +<!-- INCLUDE ucp_footer.html --> diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html index 9110cea4e9..1af512732d 100644 --- a/phpBB/styles/prosilver/template/viewtopic_body.html +++ b/phpBB/styles/prosilver/template/viewtopic_body.html @@ -263,7 +263,7 @@ <!-- INCLUDE jumpbox.html --> <!-- IF .quickmod --> - <form method="post" action="{S_MOD_ACTION}" id="quickmodform" data-ajax="true"> + <form method="post" action="{S_MOD_ACTION}" id="quickmodform"> <fieldset class="quickmod"> <label for="quick-mod-select">{L_QUICK_MOD}:</label> <select name="action" id="quick-mod-select"> diff --git a/phpBB/styles/subsilver2/template/forumlist_body.html b/phpBB/styles/subsilver2/template/forumlist_body.html index be32d1fb77..b9a1102df0 100644 --- a/phpBB/styles/subsilver2/template/forumlist_body.html +++ b/phpBB/styles/subsilver2/template/forumlist_body.html @@ -48,8 +48,12 @@ <!-- IF forumrow.MODERATORS --> <p class="forumdesc"><strong>{forumrow.L_MODERATOR_STR}:</strong> {forumrow.MODERATORS}</p> <!-- ENDIF --> - <!-- IF forumrow.SUBFORUMS and forumrow.S_LIST_SUBFORUMS --> - <p class="forumdesc"><strong>{forumrow.L_SUBFORUM_STR}</strong> {forumrow.SUBFORUMS}</p> + <!-- IF .forumrow.subforum and forumrow.S_LIST_SUBFORUMS --> + <p class="forumdesc"><strong>{forumrow.L_SUBFORUM_STR}</strong> + <!-- BEGIN subforum --> + <a href="{forumrow.subforum.U_SUBFORUM}" class="subforum<!-- IF forumrow.subforum.S_UNREAD --> unread<!-- ELSE --> read<!-- ENDIF -->" title="<!-- IF forumrow.subforum.UNREAD -->{L_UNREAD_POSTS}<!-- ELSE -->{L_NO_UNREAD_POSTS}<!-- ENDIF -->">{forumrow.subforum.SUBFORUM_NAME}</a><!-- IF not forumrow.subforum.S_LAST_ROW -->,<!-- ENDIF --> + <!-- END subforum --> + </p> <!-- ENDIF --> </td> <td class="row2" align="center"><p class="topicdetails">{forumrow.TOPICS}</p></td> diff --git a/phpBB/styles/subsilver2/template/mcp_topic.html b/phpBB/styles/subsilver2/template/mcp_topic.html index 8ff648da39..6bbf13e12c 100644 --- a/phpBB/styles/subsilver2/template/mcp_topic.html +++ b/phpBB/styles/subsilver2/template/mcp_topic.html @@ -12,7 +12,7 @@ </tr> <tr> <td class="row1" nowrap="nowrap"><span class="gen">{L_SPLIT_SUBJECT}</span></td> - <td class="row2" colspan="2"><input class="post" style="width: 350px" type="text" size="35" maxlength="64" name="subject" value="{SPLIT_SUBJECT}" /></td> + <td class="row2" colspan="2"><input class="post" style="width: 350px" type="text" size="35" maxlength="124" name="subject" value="{SPLIT_SUBJECT}" /></td> </tr> <tr> <td class="row1" nowrap="nowrap"><span class="gen">{L_SPLIT_FORUM}</span></td> diff --git a/phpBB/styles/subsilver2/template/posting_body.html b/phpBB/styles/subsilver2/template/posting_body.html index 712c02b856..ae7d2f88d6 100644 --- a/phpBB/styles/subsilver2/template/posting_body.html +++ b/phpBB/styles/subsilver2/template/posting_body.html @@ -173,7 +173,7 @@ <tr> <td class="row1" width="22%"><b class="genmed">{L_SUBJECT}:</b></td> - <td class="row2" width="78%"><input class="post" style="width:450px" type="text" name="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->60<!-- ELSE -->64<!-- ENDIF -->" tabindex="2" value="{SUBJECT}" /></td> + <td class="row2" width="78%"><input class="post" style="width:450px" type="text" name="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->120<!-- ELSE -->124<!-- ENDIF -->" tabindex="2" value="{SUBJECT}" /></td> </tr> <tr> <td class="row1" valign="top"><b class="genmed">{L_MESSAGE_BODY}:</b><br /><span class="gensmall">{L_MESSAGE_BODY_EXPLAIN} </span><br /><br /> diff --git a/phpBB/styles/subsilver2/template/quickreply_editor.html b/phpBB/styles/subsilver2/template/quickreply_editor.html index 4c3f7a3d0b..7a68a8f605 100644 --- a/phpBB/styles/subsilver2/template/quickreply_editor.html +++ b/phpBB/styles/subsilver2/template/quickreply_editor.html @@ -6,7 +6,7 @@ </tr> <tr> <td class="row1" width="22%"><b class="genmed">{L_SUBJECT}:</b></td> - <td class="row2" width="78%"><input class="post" style="width:450px" type="text" name="subject" size="45" maxlength="64" tabindex="2" value="{SUBJECT}" /></td> + <td class="row2" width="78%"><input class="post" style="width:450px" type="text" name="subject" size="45" maxlength="124" tabindex="2" value="{SUBJECT}" /></td> </tr> <tr> <td class="row1" width="22%"><b class="genmed">{L_MESSAGE}:</b></td> diff --git a/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html b/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html new file mode 100644 index 0000000000..1dab9acb9c --- /dev/null +++ b/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html @@ -0,0 +1,49 @@ +<!-- INCLUDE ucp_header.html --> + +<table class="tablebg" width="100%" cellspacing="1"> +<tr> + <th colspan="4" valign="middle">{L_TITLE}</th> +</tr> +<!-- IF .errors --> + <tr> + <td class="row3" colspan="2" align="center"><span class="gensmall error"> + <!-- BEGIN errors --> + {errors} <br /> + <!-- END errors --> + </td> + </tr> +<!-- ENDIF --> + +<tr> + <td colspan="4" class="row1">{L_PROFILE_AUTOLOGIN_KEYS}</td> +</tr> +<tr> + <th>{L_MARK}</th> + <th>{L_LOGIN_KEY}</th> + <th>{L_IP}</th> + <th>{L_LOGIN_TIME}</th> +</tr> +<!-- BEGIN sessions --> + <!-- IF sessions.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF --> + <td class="genmed" style="text-align: center"><input type="checkbox" name="keys[]" value="{sessions.KEY}" id="{sessions.KEY}"/></td> + <td class="genmed"><label for="{sessions.KEY}">{sessions.KEY}</label></td> + <td class="genmed" style="text-align: center">{sessions.IP}</td> + <td class="genmed" style="text-align: center">{sessions.LOGIN_TIME}</td> + </tr> +<!-- BEGINELSE --> + <tr> + <td colspan="4" class="row1" style="text-align: center">{L_PROFILE_NO_AUTOLOGIN_KEYS}</td> + </tr> +<!-- END sessions --> + +<!-- IF .sessions --> + <tr> + <td class="cat" colspan="4" align="center"> + {S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_DELETE}" /> + {S_FORM_TOKEN} + </td> + </tr> +<!-- ENDIF --> +</table> + +<!-- INCLUDE ucp_footer.html --> diff --git a/phpBB/styles/subsilver2/template/viewforum_body.html b/phpBB/styles/subsilver2/template/viewforum_body.html index f132185716..afb8426799 100644 --- a/phpBB/styles/subsilver2/template/viewforum_body.html +++ b/phpBB/styles/subsilver2/template/viewforum_body.html @@ -154,7 +154,7 @@ <td class="cat" colspan="<!-- IF S_TOPIC_ICONS -->7<!-- ELSE -->6<!-- ENDIF -->"> <table width="100%" cellspacing="0"> <tr class="nav"> - <td valign="middle"> <!-- IF S_WATCH_FORUM_LINK and not S_IS_BOT --><a href="{S_WATCH_FORUM_LINK}">{S_WATCH_FORUM_TITLE}</a><!-- ENDIF --></td> + <td valign="middle"> <!-- IF U_WATCH_FORUM_LINK and not S_IS_BOT --><a href="{U_WATCH_FORUM_LINK}">{S_WATCH_FORUM_TITLE}</a><!-- ENDIF --></td> <td align="{S_CONTENT_FLOW_END}" valign="middle"><!-- IF not S_IS_BOT and U_MARK_TOPICS --><a href="{U_MARK_TOPICS}">{L_MARK_TOPICS_READ}</a><!-- ENDIF --> </td> </tr> </table> diff --git a/phpBB/styles/subsilver2/template/viewtopic_body.html b/phpBB/styles/subsilver2/template/viewtopic_body.html index 2c5351b926..a4e2dd886a 100644 --- a/phpBB/styles/subsilver2/template/viewtopic_body.html +++ b/phpBB/styles/subsilver2/template/viewtopic_body.html @@ -52,8 +52,8 @@ <tr> <td class="nav" nowrap="nowrap"> <!-- IF not S_IS_BOT --> - <!-- IF U_WATCH_TOPIC --><a href="{U_WATCH_TOPIC}" title="{L_WATCH_TOPIC}">{L_WATCH_TOPIC}</a><!-- IF U_PRINT_TOPIC or U_EMAIL_TOPIC or U_BUMP_TOPIC or U_BOOKMARK_TOPIC --> | <!-- ENDIF --><!-- ENDIF --> - <!-- IF U_BOOKMARK_TOPIC --><a href="{U_BOOKMARK_TOPIC}" title="{L_BOOKMARK_TOPIC}">{L_BOOKMARK_TOPIC}</a><!-- IF U_PRINT_TOPIC or U_EMAIL_TOPIC or U_BUMP_TOPIC --> | <!-- ENDIF --><!-- ENDIF --> + <!-- IF U_WATCH_TOPIC --><a href="{U_WATCH_TOPIC}" title="{S_WATCH_TOPIC_TITLE}">{S_WATCH_TOPIC_TITLE}</a><!-- IF U_PRINT_TOPIC or U_EMAIL_TOPIC or U_BUMP_TOPIC or U_BOOKMARK_TOPIC --> | <!-- ENDIF --><!-- ENDIF --> + <!-- IF U_BOOKMARK_TOPIC --><a href="{U_BOOKMARK_TOPIC}" title="{S_BOOKMARK_TOPIC}">{S_BOOKMARK_TOPIC}</a><!-- IF U_PRINT_TOPIC or U_EMAIL_TOPIC or U_BUMP_TOPIC --> | <!-- ENDIF --><!-- ENDIF --> <!-- IF U_PRINT_TOPIC --><a href="{U_PRINT_TOPIC}" title="{L_PRINT_TOPIC}">{L_PRINT_TOPIC}</a><!-- IF U_EMAIL_TOPIC or U_BUMP_TOPIC --> | <!-- ENDIF --><!-- ENDIF --> <!-- IF U_EMAIL_TOPIC --><a href="{U_EMAIL_TOPIC}" title="{L_EMAIL_TOPIC}">{L_EMAIL_TOPIC}</a><!-- IF U_BUMP_TOPIC --> | <!-- ENDIF --><!-- ENDIF --> <!-- IF U_BUMP_TOPIC --><a href="{U_BUMP_TOPIC}" title="{L_BUMP_TOPIC}">{L_BUMP_TOPIC}</a><!-- ENDIF --> diff --git a/phpBB/viewforum.php b/phpBB/viewforum.php index 2d91581cf4..6a39f10394 100644 --- a/phpBB/viewforum.php +++ b/phpBB/viewforum.php @@ -204,7 +204,9 @@ if (!$config['use_system_cron']) // Forum rules and subscription info $s_watching_forum = array( 'link' => '', + 'link_toggle' => '', 'title' => '', + 'title_toggle' => '', 'is_watching' => false, ); @@ -318,8 +320,10 @@ $template->assign_vars(array( 'S_SELECT_SORT_KEY' => $s_sort_key, 'S_SELECT_SORT_DAYS' => $s_limit_days, 'S_TOPIC_ICONS' => ($s_display_active && sizeof($active_forum_ary)) ? max($active_forum_ary['enable_icons']) : (($forum_data['enable_icons']) ? true : false), - 'S_WATCH_FORUM_LINK' => $s_watching_forum['link'], + 'U_WATCH_FORUM_LINK' => $s_watching_forum['link'], + 'U_WATCH_FORUM_TOGGLE' => $s_watching_forum['link_toggle'], 'S_WATCH_FORUM_TITLE' => $s_watching_forum['title'], + 'S_WATCH_FORUM_TOGGLE' => $s_watching_forum['title_toggle'], 'S_WATCHING_FORUM' => $s_watching_forum['is_watching'], 'S_FORUM_ACTION' => append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . (($start == 0) ? '' : "&start=$start")), 'S_DISPLAY_SEARCHBOX' => ($auth->acl_get('u_search') && $auth->acl_get('f_search', $forum_id) && $config['load_search']) ? true : false, diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php index 65237a7a02..dbebc793fd 100644 --- a/phpBB/viewtopic.php +++ b/phpBB/viewtopic.php @@ -449,7 +449,9 @@ $viewtopic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&a // Are we watching this topic? $s_watching_topic = array( 'link' => '', + 'link_toggle' => '', 'title' => '', + 'title_toggle' => '', 'is_watching' => false, ); @@ -649,13 +651,15 @@ $template->assign_vars(array( 'U_PRINT_TOPIC' => ($auth->acl_get('f_print', $forum_id)) ? $viewtopic_url . '&view=print' : '', 'U_EMAIL_TOPIC' => ($auth->acl_get('f_email', $forum_id) && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&t=$topic_id") : '', - 'U_WATCH_TOPIC' => $s_watching_topic['link'], - 'L_WATCH_TOPIC' => $s_watching_topic['title'], + 'U_WATCH_TOPIC' => $s_watching_topic['link'], + 'U_WATCH_TOPIC_TOGGLE' => $s_watching_topic['link_toggle'], + 'S_WATCH_TOPIC_TITLE' => $s_watching_topic['title'], + 'S_WATCH_TOPIC_TOGGLE' => $s_watching_topic['title_toggle'], 'S_WATCHING_TOPIC' => $s_watching_topic['is_watching'], 'U_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks']) ? $viewtopic_url . '&bookmark=1&hash=' . generate_link_hash("topic_$topic_id") : '', - 'L_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], - 'L_BOOKMARK_TOPIC_REAL' => $user->lang['BOOKMARK_TOPIC'], + 'S_BOOKMARK_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], + 'S_BOOKMARK_TOGGLE' => (!$user->data['is_registered'] || !$config['allow_bookmarks'] || !$topic_data['bookmarked']) ? $user->lang['BOOKMARK_TOPIC_REMOVE'] : $user->lang['BOOKMARK_TOPIC'], 'S_BOOKMARKED_TOPIC' => ($user->data['is_registered'] && $config['allow_bookmarks'] && $topic_data['bookmarked']) ? true : false, 'U_POST_NEW_TOPIC' => ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=post&f=$forum_id") : '', |