diff options
79 files changed, 818 insertions, 1492 deletions
diff --git a/phpBB/adm/style/acp_attachments.html b/phpBB/adm/style/acp_attachments.html index 6129d6a1a5..7a66f170ac 100644 --- a/phpBB/adm/style/acp_attachments.html +++ b/phpBB/adm/style/acp_attachments.html @@ -110,7 +110,7 @@ <!-- ELSEIF S_EXTENSION_GROUPS --> <!-- IF S_EDIT_GROUP --> - <script type="text/javascript" defer="defer"> + <script> // <![CDATA[ function update_image(newimage) { diff --git a/phpBB/adm/style/acp_ban.html b/phpBB/adm/style/acp_ban.html index f2249941a5..d0eab75ad8 100644 --- a/phpBB/adm/style/acp_ban.html +++ b/phpBB/adm/style/acp_ban.html @@ -8,7 +8,7 @@ <p>{L_EXPLAIN}</p> -<script type="text/javascript"> +<script> // <![CDATA[ var ban_length = new Array(); diff --git a/phpBB/adm/style/acp_contact.html b/phpBB/adm/style/acp_contact.html index f1752d0055..c46a2d7fed 100644 --- a/phpBB/adm/style/acp_contact.html +++ b/phpBB/adm/style/acp_contact.html @@ -1,6 +1,6 @@ <!-- INCLUDE overall_header.html --> -<script type="text/javascript"> +<script> // <![CDATA[ var form_name = 'acp_contact'; diff --git a/phpBB/adm/style/acp_database.html b/phpBB/adm/style/acp_database.html index cc0b57b411..d3433a8aa6 100644 --- a/phpBB/adm/style/acp_database.html +++ b/phpBB/adm/style/acp_database.html @@ -35,7 +35,7 @@ <p>{L_ACP_BACKUP_EXPLAIN}</p> - <script type="text/javascript"> + <script> // <![CDATA[ function selector(bool) diff --git a/phpBB/adm/style/acp_forums.html b/phpBB/adm/style/acp_forums.html index 965438ff67..20bcd2e9f9 100644 --- a/phpBB/adm/style/acp_forums.html +++ b/phpBB/adm/style/acp_forums.html @@ -4,7 +4,7 @@ <!-- IF S_EDIT_FORUM --> - <script type="text/javascript"> + <script> // <![CDATA[ /** * Handle displaying/hiding several options based on the forum type @@ -405,7 +405,7 @@ <!-- ELSEIF S_CONTINUE_SYNC --> - <script type="text/javascript"> + <script> // <![CDATA[ var close_waitscreen = 0; // no scrollbars... @@ -421,7 +421,7 @@ <!-- ELSE --> - <script type="text/javascript"> + <script> // <![CDATA[ /** * Popup search progress bar @@ -447,7 +447,7 @@ <!-- ENDIF --> <!-- IF S_RESYNCED --> - <script type="text/javascript"> + <script> // <![CDATA[ var close_waitscreen = 1; // ]]> diff --git a/phpBB/adm/style/acp_icons.html b/phpBB/adm/style/acp_icons.html index 5493cbde0a..45fe7f8ebc 100644 --- a/phpBB/adm/style/acp_icons.html +++ b/phpBB/adm/style/acp_icons.html @@ -4,7 +4,7 @@ <!-- IF S_EDIT --> - <script type="text/javascript" defer="defer"> + <script> // <![CDATA[ <!-- IF S_ADD_CODE --> diff --git a/phpBB/adm/style/acp_modules.html b/phpBB/adm/style/acp_modules.html index 3c97706e6a..f4040daaed 100644 --- a/phpBB/adm/style/acp_modules.html +++ b/phpBB/adm/style/acp_modules.html @@ -4,7 +4,7 @@ <!-- IF S_EDIT_MODULE --> - <script type="text/javascript"> + <script> // <![CDATA[ function display_options(value) { diff --git a/phpBB/adm/style/acp_permission_roles.html b/phpBB/adm/style/acp_permission_roles.html index b3137f134c..670d5e14c0 100644 --- a/phpBB/adm/style/acp_permission_roles.html +++ b/phpBB/adm/style/acp_permission_roles.html @@ -4,7 +4,7 @@ <!-- IF S_EDIT --> - <script type="text/javascript"> + <script> // <![CDATA[ var active_pmask = '0'; var active_fmask = '0'; @@ -20,7 +20,7 @@ // ]]> </script> - <script type="text/javascript" src="style/permissions.js"></script> + <script src="style/permissions.js"></script> <a href="{U_BACK}" style="float: {S_CONTENT_FLOW_END};">« {L_BACK}</a> diff --git a/phpBB/adm/style/acp_posting_buttons.html b/phpBB/adm/style/acp_posting_buttons.html index 36fc285537..614d6fae40 100644 --- a/phpBB/adm/style/acp_posting_buttons.html +++ b/phpBB/adm/style/acp_posting_buttons.html @@ -1,4 +1,4 @@ -<script type="text/javascript"> +<script> // <![CDATA[ // Define the bbCode tags diff --git a/phpBB/adm/style/acp_ranks.html b/phpBB/adm/style/acp_ranks.html index e67c9acd80..d373657114 100644 --- a/phpBB/adm/style/acp_ranks.html +++ b/phpBB/adm/style/acp_ranks.html @@ -6,7 +6,7 @@ <a href="{U_BACK}" style="float: {S_CONTENT_FLOW_END};">« {L_BACK}</a> - <script type="text/javascript"> + <script> // <![CDATA[ function update_image(newimage) { diff --git a/phpBB/adm/style/acp_search.html b/phpBB/adm/style/acp_search.html index f7ad3c5e89..99620058dc 100644 --- a/phpBB/adm/style/acp_search.html +++ b/phpBB/adm/style/acp_search.html @@ -69,7 +69,7 @@ <!-- ELSEIF S_INDEX --> - <script type="text/javascript"> + <script> // <![CDATA[ /** * Popup search progress bar diff --git a/phpBB/adm/style/acp_users_overview.html b/phpBB/adm/style/acp_users_overview.html index 506101c3f7..2af669a41f 100644 --- a/phpBB/adm/style/acp_users_overview.html +++ b/phpBB/adm/style/acp_users_overview.html @@ -79,7 +79,7 @@ <!-- IF not S_USER_FOUNDER or S_FOUNDER --> - <script type="text/javascript"> + <script> // <![CDATA[ function display_reason(option) diff --git a/phpBB/adm/style/acp_users_prefs.html b/phpBB/adm/style/acp_users_prefs.html index 484c5b3976..358f3d5248 100644 --- a/phpBB/adm/style/acp_users_prefs.html +++ b/phpBB/adm/style/acp_users_prefs.html @@ -1,4 +1,4 @@ -<script type="text/javascript"> +<script> // <![CDATA[ var default_dateformat = '{A_DEFAULT_DATEFORMAT}'; // ]]> diff --git a/phpBB/adm/style/acp_users_signature.html b/phpBB/adm/style/acp_users_signature.html index 2e57700fd1..40f0fc25d9 100644 --- a/phpBB/adm/style/acp_users_signature.html +++ b/phpBB/adm/style/acp_users_signature.html @@ -1,4 +1,4 @@ -<script type="text/javascript"> +<script> // <![CDATA[ var form_name = 'user_signature'; diff --git a/phpBB/adm/style/installer_footer.html b/phpBB/adm/style/installer_footer.html index 54e6951a12..8b3b04d8a5 100644 --- a/phpBB/adm/style/installer_footer.html +++ b/phpBB/adm/style/installer_footer.html @@ -13,7 +13,7 @@ </div> </div> -<script type="text/javascript"> +<script> <!-- installLang = { title: '{LA_TIMEOUT_DETECTED_TITLE}', @@ -22,9 +22,9 @@ installLang = { //--> </script> -<script type="text/javascript" src="{T_JQUERY_LINK}"></script> -<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js">\x3C/script>');</script><!-- ENDIF --> -<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script> +<script src="{T_JQUERY_LINK}"></script> +<!-- IF S_ALLOW_CDN --><script>window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js">\x3C/script>');</script><!-- ENDIF --> +<script src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script> <!-- INCLUDEJS admin.js --> {$SCRIPTS} diff --git a/phpBB/adm/style/overall_footer.html b/phpBB/adm/style/overall_footer.html index 8745286d64..3ab633e04b 100644 --- a/phpBB/adm/style/overall_footer.html +++ b/phpBB/adm/style/overall_footer.html @@ -33,9 +33,9 @@ </div> </div> -<script type="text/javascript" src="{T_JQUERY_LINK}"></script> -<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF --> -<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script> +<script src="{T_JQUERY_LINK}"></script> +<!-- IF S_ALLOW_CDN --><script>window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF --> +<script src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script> <!-- INCLUDEJS ajax.js --> <!-- INCLUDEJS admin.js --> diff --git a/phpBB/adm/style/overall_header.html b/phpBB/adm/style/overall_header.html index 8279ac34dc..fa361d6016 100644 --- a/phpBB/adm/style/overall_header.html +++ b/phpBB/adm/style/overall_header.html @@ -10,7 +10,7 @@ <link href="{T_FONT_AWESOME_LINK}" rel="stylesheet"> <link href="style/admin.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="screen" /> -<script type="text/javascript"> +<script> // <![CDATA[ var jump_page = '{LA_JUMP_PAGE}{L_COLON}'; var on_page = '{CURRENT_PAGE}'; diff --git a/phpBB/adm/style/permission_mask.html b/phpBB/adm/style/permission_mask.html index 23294d60df..26aa5e098f 100644 --- a/phpBB/adm/style/permission_mask.html +++ b/phpBB/adm/style/permission_mask.html @@ -1,5 +1,5 @@ -<script type="text/javascript"> +<script> // <![CDATA[ var active_pmask = '0'; var active_fmask = '0'; @@ -16,7 +16,7 @@ <!-- ENDIF --> // ]]> </script> -<script type="text/javascript" src="style/permissions.js"></script> +<script src="style/permissions.js"></script> <!-- BEGIN p_mask --> <div class="clearfix"></div> diff --git a/phpBB/adm/style/progress_bar.html b/phpBB/adm/style/progress_bar.html index 1822675c15..1e58257ff0 100644 --- a/phpBB/adm/style/progress_bar.html +++ b/phpBB/adm/style/progress_bar.html @@ -1,6 +1,6 @@ <!-- INCLUDE simple_header.html --> -<script type="text/javascript"> +<script> // <![CDATA[ /** * Close previously opened popup @@ -31,7 +31,7 @@ <p>{L_PROGRESS_EXPLAIN}</p> </div> -<script type="text/javascript"> +<script> // <![CDATA[ close_popup(); // ]]> diff --git a/phpBB/adm/style/simple_footer.html b/phpBB/adm/style/simple_footer.html index 08ee0a739f..4b54b83373 100644 --- a/phpBB/adm/style/simple_footer.html +++ b/phpBB/adm/style/simple_footer.html @@ -16,9 +16,9 @@ </div> -<script type="text/javascript" src="{T_JQUERY_LINK}"></script> -<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF --> -<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script> +<script src="{T_JQUERY_LINK}"></script> +<!-- IF S_ALLOW_CDN --><script>window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF --> +<script src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script> <!-- EVENT acp_simple_footer_after --> {$SCRIPTS} diff --git a/phpBB/adm/style/simple_header.html b/phpBB/adm/style/simple_header.html index 439645a211..a8a32bf768 100644 --- a/phpBB/adm/style/simple_header.html +++ b/phpBB/adm/style/simple_header.html @@ -9,7 +9,7 @@ <link href="style/admin.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="screen" /> -<script type="text/javascript"> +<script> // <![CDATA[ var jump_page = '{LA_JUMP_PAGE}{L_COLON}'; var on_page = '{CURRENT_PAGE}'; diff --git a/phpBB/config/default/container/services.yml b/phpBB/config/default/container/services.yml index 3ead1e6181..2d4720029d 100644 --- a/phpBB/config/default/container/services.yml +++ b/phpBB/config/default/container/services.yml @@ -27,6 +27,7 @@ imports: - { resource: services_text_formatter.yml } - { resource: services_text_reparser.yml } - { resource: services_twig.yml } + - { resource: services_ucp.yml } - { resource: services_user.yml } - { resource: tables.yml } diff --git a/phpBB/config/default/container/services_ucp.yml b/phpBB/config/default/container/services_ucp.yml new file mode 100644 index 0000000000..861fa4ac75 --- /dev/null +++ b/phpBB/config/default/container/services_ucp.yml @@ -0,0 +1,17 @@ +services: + phpbb.ucp.controller.reset_password: + class: phpbb\ucp\controller\reset_password + arguments: + - '@config' + - '@dbal.conn' + - '@dispatcher' + - '@controller.helper' + - '@language' + - '@log' + - '@passwords.manager' + - '@request' + - '@template' + - '@user' + - '%tables.users%' + - '%core.root_path%' + - '%core.php_ext%' diff --git a/phpBB/config/default/routing/routing.yml b/phpBB/config/default/routing/routing.yml index 199c5229b0..a5e9265dc3 100644 --- a/phpBB/config/default/routing/routing.yml +++ b/phpBB/config/default/routing/routing.yml @@ -26,3 +26,7 @@ phpbb_help_routing: phpbb_report_routing: resource: report.yml + +phpbb_ucp_routing: + resource: ucp.yml + prefix: /user diff --git a/phpBB/config/default/routing/ucp.yml b/phpBB/config/default/routing/ucp.yml new file mode 100644 index 0000000000..06bd7c3a58 --- /dev/null +++ b/phpBB/config/default/routing/ucp.yml @@ -0,0 +1,7 @@ +phpbb_ucp_reset_password_controller: + path: /reset_password + defaults: { _controller: phpbb.ucp.controller.reset_password:reset } + +phpbb_ucp_forgot_password_controller: + path: /forgot_password + defaults: { _controller: phpbb.ucp.controller.reset_password:request } diff --git a/phpBB/develop/add_permissions.php b/phpBB/develop/add_permissions.php index d7308a1acc..d2c8bffd90 100644 --- a/phpBB/develop/add_permissions.php +++ b/phpBB/develop/add_permissions.php @@ -210,7 +210,7 @@ foreach ($prefixes as $prefix) ); $db->sql_query('INSERT INTO ' . ACL_OPTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - + echo "<p><b>Adding $auth_option...</b></p>\n"; mass_auth('group', 0, 'guests', $auth_option, ACL_NEVER); @@ -231,7 +231,7 @@ $db->sql_query($sql); $cache->destroy('_acl_options'); echo "<p><b>Done</b></p>\n"; - + /* $ug_type = user|group $forum_id = forum ids (array|int|0) -> 0 == all forums @@ -374,11 +374,6 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting) case 'insert': switch ($db->get_sql_layer()) { - case 'mysql': - case 'mysql4': - $sql = 'VALUES ' . implode(', ', preg_replace('#^(.*?)$#', '(\1)', $sql_subary)); - break; - case 'sqlite3': $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); break; diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php index 6e0a082045..fdaa285f99 100644 --- a/phpBB/develop/create_schema_files.php +++ b/phpBB/develop/create_schema_files.php @@ -21,7 +21,6 @@ $schema_path = dirname(__FILE__) . '/../install/schemas/'; $supported_dbms = array( 'mssql', - 'mysql_40', 'mysql_41', 'oracle', 'postgres', diff --git a/phpBB/develop/mysql_upgrader.php b/phpBB/develop/mysql_upgrader.php deleted file mode 100644 index 276c010e84..0000000000 --- a/phpBB/develop/mysql_upgrader.php +++ /dev/null @@ -1,212 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* This file creates SQL statements to upgrade phpBB on MySQL 3.x/4.0.x to 4.1.x/5.x -*/ - -// -// Security message: -// -// This script is potentially dangerous. -// Remove or comment the next line (die(".... ) to enable this script. -// Do NOT FORGET to either remove this script or disable it after you have used it. -// -die("Please read the first lines of this script for instructions on how to enable it"); - -define('IN_PHPBB', true); -$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); -include($phpbb_root_path . 'common.' . $phpEx); - -$prefix = $table_prefix; - -$newline = "\n"; - -if (PHP_SAPI !== 'cli') -{ - $newline = '<br>'; -} - -$sql = 'DESCRIBE ' . POSTS_TABLE . ' post_text'; -$result = $db->sql_query($sql); - -$row = $db->sql_fetchrow($result); - -$db->sql_freeresult($result); - -$mysql_indexer = $drop_index = false; - -if (strtolower($row['Type']) === 'mediumtext') -{ - $mysql_indexer = true; -} - -if (strtolower($row['Key']) === 'mul') -{ - $drop_index = true; -} - -echo "USE $dbname;$newline$newline"; - - -@set_time_limit(0); - -$finder = new \phpbb\finder(new \phpbb\filesystem\filesystem(), $phpbb_root_path); -$classes = $finder->core_path('phpbb/') - ->directory('/db/migration/data') - ->get_classes(); - -$factory = new \phpbb\db\tools\factory(); -$db_tools = $factory->get($db, true); - -$schema_generator = new \phpbb\db\migration\schema_generator($classes, $config, $db, $db_tools, $phpbb_root_path, $phpEx, $table_prefix); -$schema_data = $schema_generator->get_schema(); -$dbms_type_map = \phpbb\db\tools\tools::get_dbms_type_map(); - -foreach ($schema_data as $table_name => $table_data) -{ - $table_name = str_replace('phpbb_', $prefix, $table_name); - // Write comment about table - echo "# Table: '{$table_name}'$newline"; - - // Create Table statement - $generator = $textimage = false; - - // Do we need to DROP a fulltext index before we alter the table? - if ($table_name == ($prefix . 'posts') && $drop_index) - { - echo "ALTER TABLE {$table_name}{$newline}"; - echo "DROP INDEX post_text,{$newline}DROP INDEX post_subject,{$newline}DROP INDEX post_content;{$newline}{$newline}"; - } - - $line = "ALTER TABLE {$table_name} $newline"; - - // Table specific so we don't get overlap - $modded_array = array(); - - // Write columns one by one... - foreach ($table_data['COLUMNS'] as $column_name => $column_data) - { - // Get type - if (strpos($column_data[0], ':') !== false) - { - list($orig_column_type, $column_length) = explode(':', $column_data[0]); - $column_type = sprintf($dbms_type_map['mysql_41'][$orig_column_type . ':'], $column_length); - - if (isset($dbms_type_map['mysql_40'][$orig_column_type . ':']['limit']) && - isset($dbms_type_map['mysql_40'][$orig_column_type . ':']['limit'][0])) - { - switch ($dbms_type_map['mysql_40'][$orig_column_type . ':']['limit'][0]) - { - case 'mult': - if (($column_length * $dbms_type_map['mysql_40'][$orig_column_type . ':']['limit'][1]) > $dbms_type_map['mysql_40'][$orig_column_type . ':']['limit'][2]) - { - $modded_array[$column_name] = $column_type; - } - break; - } - } - - $orig_column_type .= ':'; - } - else - { - $orig_column_type = $column_data[0]; - $other_column_type = $dbms_type_map['mysql_40'][$column_data[0]]; - if ($other_column_type == 'text' || $other_column_type == 'blob') - { - $modded_array[$column_name] = $column_type; - } - $column_type = $dbms_type_map['mysql_41'][$column_data[0]]; - } - - // Adjust default value if db-dependent specified - if (is_array($column_data[1])) - { - $column_data[1] = (isset($column_data[1][$dbms])) ? $column_data[1][$dbms] : $column_data[1]['default']; - } - - $line .= "\tMODIFY {$column_name} {$column_type} "; - - // For hexadecimal values do not use single quotes - if (!is_null($column_data[1]) && substr($column_type, -4) !== 'text' && substr($column_type, -4) !== 'blob') - { - $line .= (strpos($column_data[1], '0x') === 0) ? "DEFAULT {$column_data[1]} " : "DEFAULT '{$column_data[1]}' "; - } - $line .= 'NOT NULL'; - - if (isset($column_data[2])) - { - if ($column_data[2] == 'auto_increment') - { - $line .= ' auto_increment'; - } - else if ($column_data[2] == 'true_sort') - { - $line .= ' COLLATE utf8_unicode_ci'; - } - else if ($column_data[2] == 'no_sort') - { - $line .= ' COLLATE utf8_bin'; - } - } - else if (preg_match('/(?:var)?char|(?:medium)?text/i', $column_type)) - { - $line .= ' COLLATE utf8_bin'; - } - - $line .= ",$newline"; - } - - // Write Keys - if (isset($table_data['KEYS'])) - { - foreach ($table_data['KEYS'] as $key_name => $key_data) - { - $temp = ''; - if (!is_array($key_data[1])) - { - $key_data[1] = array($key_data[1]); - } - - $temp .= ($key_data[0] == 'INDEX') ? "\tADD KEY" : ''; - $temp .= ($key_data[0] == 'UNIQUE') ? "\tADD UNIQUE" : ''; - $repair = false; - foreach ($key_data[1] as $key => $col_name) - { - if (isset($modded_array[$col_name])) - { - $repair = true; - } - } - if ($repair) - { - $line .= "\tDROP INDEX " . $key_name . ",$newline"; - $line .= $temp; - $line .= ' ' . $key_name . ' (' . implode(', ', $key_data[1]) . "),$newline"; - } - } - } - - //$line .= "\tCONVERT TO CHARACTER SET `utf8`$newline"; - $line .= "\tDEFAULT CHARSET=utf8 COLLATE=utf8_bin;$newline$newline"; - - echo $line . "$newline"; - - // Do we now need to re-add the fulltext index? ;) - if ($table_name == ($prefix . 'posts') && $drop_index) - { - echo "ALTER TABLE $table_name ADD FULLTEXT (post_subject), ADD FULLTEXT (post_text), ADD FULLTEXT post_content (post_subject, post_text);{$newline}"; - } -} diff --git a/phpBB/docs/coding-guidelines.html b/phpBB/docs/coding-guidelines.html index 72ad115e71..6cf647c55f 100644 --- a/phpBB/docs/coding-guidelines.html +++ b/phpBB/docs/coding-guidelines.html @@ -738,7 +738,7 @@ static private function f()</pre> <a name="sql"></a><h3>2.iii. SQL/SQL Layout</h3> <h4>Common SQL Guidelines: </h4> - <p>All SQL should be cross-DB compatible, if DB specific SQL is used alternatives must be provided which work on all supported DB's (MySQL3/4/5, MSSQL (7.0 and 2000), PostgreSQL (8.3+), SQLite, Oracle8, ODBC (generalised if possible)).</p> + <p>All SQL should be cross-DB compatible, if DB specific SQL is used alternatives must be provided which work on all supported DB's (MySQL4/5, MSSQL (7.0 and 2000), PostgreSQL (8.3+), SQLite, Oracle8, ODBC (generalised if possible)).</p> <p>All SQL commands should utilise the DataBase Abstraction Layer (DBAL)</p> <h4>SQL code layout:</h4> diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 7cbd0903bd..05871e4157 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -254,7 +254,6 @@ class acp_board 'vars' => array( 'legend1' => 'GENERAL_SETTINGS', 'max_name_chars' => array('lang' => 'USERNAME_LENGTH', 'validate' => 'int:8:180', 'type' => false, 'method' => false, 'explain' => false,), - 'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,), 'require_activation' => array('lang' => 'ACC_ACTIVATION', 'validate' => 'int', 'type' => 'select', 'method' => 'select_acc_activation', 'explain' => true), 'new_member_post_limit' => array('lang' => 'NEW_MEMBER_POST_LIMIT', 'validate' => 'int:0:255', 'type' => 'number:0:255', 'explain' => true, 'append' => ' ' . $user->lang['POSTS']), @@ -417,7 +416,6 @@ class acp_board 'remote_upload_verify' => array('lang' => 'UPLOAD_CERT_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'check_dnsbl' => array('lang' => 'CHECK_DNSBL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'email_check_mx' => array('lang' => 'EMAIL_CHECK_MX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,), 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), @@ -895,13 +893,13 @@ class acp_board } /** - * Maximum/Minimum password length + * Minimum password length */ function password_length($value, $key) { global $user; - return '<input id="' . $key . '" type="number" min="1" max="999" name="config[min_pass_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . ' <input type="number" min="8" max="255" name="config[max_pass_chars]" value="' . $this->new_config['max_pass_chars'] . '" /> ' . $user->lang['MAX_CHARS']; + return '<input id="' . $key . '" type="number" min="1" max="999" name="config[min_pass_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS']; } /** diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index 677fce7217..c1c748832b 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -248,8 +248,6 @@ class acp_database switch ($db->get_sql_layer()) { - case 'mysql': - case 'mysql4': case 'mysqli': case 'sqlite3': while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false) diff --git a/phpBB/includes/acp/acp_forums.php b/phpBB/includes/acp/acp_forums.php index cb0593b14a..9044cd0e97 100644 --- a/phpBB/includes/acp/acp_forums.php +++ b/phpBB/includes/acp/acp_forums.php @@ -1878,7 +1878,6 @@ class acp_forums switch ($db->get_sql_layer()) { - case 'mysql4': case 'mysqli': // Delete everything else and thank MySQL for offering multi-table deletion diff --git a/phpBB/includes/acp/acp_reasons.php b/phpBB/includes/acp/acp_reasons.php index dfb2ccbfd3..f3f82bdfca 100644 --- a/phpBB/includes/acp/acp_reasons.php +++ b/phpBB/includes/acp/acp_reasons.php @@ -222,8 +222,6 @@ class acp_reasons { // The ugly one! case 'mysqli': - case 'mysql4': - case 'mysql': // Change the reports using this reason to 'other' $sql = 'UPDATE ' . REPORTS_TABLE . ' SET reason_id = ' . $other_reason_id . ", report_text = CONCAT('" . $db->sql_escape($reason_row['reason_description']) . "\n\n', report_text) diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index fd4b5e8c24..1b66943490 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -844,9 +844,9 @@ class acp_users // Validation data - we do not check the password complexity setting here $check_ary = array( 'new_password' => array( - array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), + array('string', true, $config['min_pass_chars'], 0), array('password')), - 'password_confirm' => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), + 'password_confirm' => array('string', true, $config['min_pass_chars'], 0), ); // Check username if altered @@ -1130,7 +1130,7 @@ class acp_users $template->assign_vars(array( 'L_NAME_CHARS_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), - 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars']), $user->lang('CHARACTERS', (int) $config['max_pass_chars'])), + 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars'])), 'L_POSTS_IN_QUEUE' => $user->lang('NUM_POSTS_IN_QUEUE', $user_row['posts_in_queue']), 'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false, diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 667aa2df19..e1f6fa3d1b 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -2516,11 +2516,14 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa $s_hidden_fields = build_hidden_fields($s_hidden_fields); + /** @var \phpbb\controller\helper $controller_helper */ + $controller_helper = $phpbb_container->get('controller.helper'); + $login_box_template_data = array( 'LOGIN_ERROR' => $err, 'LOGIN_EXPLAIN' => $l_explain, - 'U_SEND_PASSWORD' => ($config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') : '', + 'U_SEND_PASSWORD' => ($config['email_enable']) ? $controller_helper->route('phpbb_ucp_forgot_password_controller') : '', 'U_RESEND_ACTIVATION' => ($config['require_activation'] == USER_ACTIVATION_SELF && $config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=resend_act') : '', 'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'), 'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'), diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index ce5f0812aa..4629706048 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -1384,7 +1384,6 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $db->sql_transaction('begin'); switch ($db->get_sql_layer()) { - case 'mysql4': case 'mysqli': $sql = 'DELETE FROM ' . TOPICS_TABLE . ' USING ' . TOPICS_TABLE . ' t1, ' . TOPICS_TABLE . " t2 @@ -2683,8 +2682,7 @@ function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false) switch ($db->get_sql_layer()) { case 'mysqli': - case 'mysql4': - $sql = 'DELETE ' . (($db->get_sql_layer() === 'mysqli' || version_compare($db->sql_server_info(true), '4.1', '>=')) ? 'z.*' : ZEBRA_TABLE) . ' + $sql = 'DELETE z.* FROM ' . ZEBRA_TABLE . ' z, ' . USER_GROUP_TABLE . ' ug WHERE z.zebra_id = ug.user_id AND z.foe = 1 @@ -2840,8 +2838,6 @@ function get_database_size() // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0 switch ($db->get_sql_layer()) { - case 'mysql': - case 'mysql4': case 'mysqli': $sql = 'SELECT VERSION() AS mysql_version'; $result = $db->sql_query($sql); diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php index 2cfbe9541d..13e01afe51 100644 --- a/phpBB/includes/functions_convert.php +++ b/phpBB/includes/functions_convert.php @@ -1647,11 +1647,6 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO) case 'insert': switch ($db->get_sql_layer()) { - case 'mysql': - case 'mysql4': - $sql = 'VALUES ' . implode(', ', preg_replace('#^(.*?)$#', '(\1)', $sql_subary)); - break; - case 'sqlite3': case 'mssqlnative': $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php index f5a56fda82..95036a95bc 100644 --- a/phpBB/includes/questionnaire/questionnaire.php +++ b/phpBB/includes/questionnaire/questionnaire.php @@ -402,7 +402,6 @@ class phpbb_questionnaire_phpbb_data_provider 'max_login_attempts' => true, 'max_name_chars' => true, 'max_num_search_keywords' => true, - 'max_pass_chars' => true, 'max_poll_options' => true, 'max_post_chars' => true, 'max_post_font_size' => true, diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index 36ab3d0463..6d98362e08 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -70,9 +70,9 @@ class ucp_profile // Do not check cur_password, it is the old one. $check_ary = array( 'new_password' => array( - array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), + array('string', true, $config['min_pass_chars'], 0), array('password')), - 'password_confirm' => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), + 'password_confirm' => array('string', true, $config['min_pass_chars'], 0), 'email' => array( array('string', false, 6, 60), array('user_email')), @@ -267,7 +267,7 @@ class ucp_profile 'CUR_PASSWORD' => '', 'L_USERNAME_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), - 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars']), $user->lang('CHARACTERS', (int) $config['max_pass_chars'])), + 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars'])), 'S_FORCE_PASSWORD' => ($auth->acl_get('u_chgpasswd') && $config['chg_passforce'] && $user->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) ? true : false, 'S_CHANGE_USERNAME' => ($config['allow_namechange'] && $auth->acl_get('u_chgname')) ? true : false, diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index 0e3ff50268..97d2631224 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -275,9 +275,9 @@ class ucp_register array('string', false, $config['min_name_chars'], $config['max_name_chars']), array('username', '')), 'new_password' => array( - array('string', false, $config['min_pass_chars'], $config['max_pass_chars']), + array('string', false, $config['min_pass_chars'], 0), array('password')), - 'password_confirm' => array('string', false, $config['min_pass_chars'], $config['max_pass_chars']), + 'password_confirm' => array('string', false, $config['min_pass_chars'], 0), 'email' => array( array('string', false, 6, 60), array('user_email')), @@ -638,7 +638,7 @@ class ucp_register 'L_REG_COND' => $l_reg_cond, 'L_USERNAME_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), - 'L_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars']), $user->lang('CHARACTERS', (int) $config['max_pass_chars'])), + 'L_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars'])), 'S_LANG_OPTIONS' => language_select($data['lang']), 'S_TZ_PRESELECT' => !$submit, diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php deleted file mode 100644 index e50428bfea..0000000000 --- a/phpBB/includes/ucp/ucp_remind.php +++ /dev/null @@ -1,174 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* ucp_remind -* Sending password reminders -*/ -class ucp_remind -{ - var $u_action; - - function main($id, $mode) - { - global $config, $phpbb_root_path, $phpEx, $request; - global $db, $user, $template, $phpbb_container, $phpbb_dispatcher; - - if (!$config['allow_password_reset']) - { - trigger_error($user->lang('UCP_PASSWORD_RESET_DISABLED', '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>')); - } - - $username = $request->variable('username', '', true); - $email = strtolower($request->variable('email', '')); - $submit = (isset($_POST['submit'])) ? true : false; - - add_form_key('ucp_remind'); - - if ($submit) - { - if (!check_form_key('ucp_remind')) - { - trigger_error('FORM_INVALID'); - } - - if (empty($email)) - { - trigger_error('NO_EMAIL_USER'); - } - - $sql_array = array( - 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type, user_lang, user_inactive_reason', - 'FROM' => array(USERS_TABLE => 'u'), - 'WHERE' => "user_email_hash = '" . $db->sql_escape(phpbb_email_hash($email)) . "'" . - (!empty($username) ? " AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'" : ''), - ); - - /** - * Change SQL query for fetching user data - * - * @event core.ucp_remind_modify_select_sql - * @var string email User's email from the form - * @var string username User's username from the form - * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE - * @since 3.1.11-RC1 - */ - $vars = array( - 'email', - 'username', - 'sql_array', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_remind_modify_select_sql', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query_limit($sql, 2); // don't waste resources on more rows than we need - $rowset = $db->sql_fetchrowset($result); - - if (count($rowset) > 1) - { - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'USERNAME_REQUIRED' => true, - 'EMAIL' => $email, - )); - } - else - { - $message = $user->lang['PASSWORD_UPDATED_IF_EXISTED'] . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>'); - - if (empty($rowset)) - { - trigger_error($message); - } - - $user_row = $rowset[0]; - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error($message); - } - - if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) - { - trigger_error($message); - } - - // Check users permissions - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($user_row); - - if (!$auth2->acl_get('u_chgpasswd')) - { - trigger_error($message); - } - - $server_url = generate_board_url(); - - // Make password at least 8 characters long, make it longer if admin wants to. - // gen_rand_string() however has a limit of 12 or 13. - $user_password = gen_rand_string_friendly(max(8, mt_rand((int) $config['min_pass_chars'], (int) $config['max_pass_chars']))); - - // For the activation key a random length between 6 and 10 will do. - $user_actkey = gen_rand_string(mt_rand(6, 10)); - - // Instantiate passwords manager - /* @var $manager \phpbb\passwords\manager */ - $passwords_manager = $phpbb_container->get('passwords.manager'); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_newpasswd = '" . $db->sql_escape($passwords_manager->hash($user_password)) . "', user_actkey = '" . $db->sql_escape($user_actkey) . "' - WHERE user_id = " . $user_row['user_id']; - $db->sql_query($sql); - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $messenger = new messenger(false); - - $messenger->template('user_activate_passwd', $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'PASSWORD' => htmlspecialchars_decode($user_password), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey") - ); - - $messenger->send($user_row['user_notify_type']); - - trigger_error($message); - } - } - - $template->assign_vars(array( - 'USERNAME' => $username, - 'EMAIL' => $email, - 'S_PROFILE_ACTION' => append_sid($phpbb_root_path . 'ucp.' . $phpEx, 'mode=sendpassword')) - ); - - $this->tpl_name = 'ucp_remind'; - $this->page_title = 'UCP_REMIND'; - } -} diff --git a/phpBB/install/convert/convertor.php b/phpBB/install/convert/convertor.php index e79ad64012..09088fe824 100644 --- a/phpBB/install/convert/convertor.php +++ b/phpBB/install/convert/convertor.php @@ -148,16 +148,6 @@ class convertor $convert->src_truncate_statement = 'DELETE FROM '; break; - // Thanks MySQL, for silently converting... - case 'mysql': - case 'mysql4': - if (version_compare($src_db->sql_server_info(true, false), '4.1.3', '>=')) - { - $convert->mysql_convert = true; - } - $convert->src_truncate_statement = 'TRUNCATE TABLE '; - break; - case 'mysqli': $convert->mysql_convert = true; $convert->src_truncate_statement = 'TRUNCATE TABLE '; @@ -748,8 +738,6 @@ class convertor switch ($db->get_sql_layer()) { // If MySQL, we'll wait to have num_wait_rows rows to submit at once - case 'mysql': - case 'mysql4': case 'mysqli': $waiting_rows[] = '(' . implode(', ', $insert_values) . ')'; @@ -1258,9 +1246,7 @@ class convertor global $db, $user; global $convert; - // Can we use IGNORE with this DBMS? - $sql_ignore = (strpos($db->get_sql_layer(), 'mysql') === 0 && !defined('DEBUG')) ? 'IGNORE ' : ''; - $insert_query = 'INSERT ' . $sql_ignore . 'INTO ' . $schema['target'] . ' ('; + $insert_query = 'INSERT INTO ' . $schema['target'] . ' ('; $aliases = array(); diff --git a/phpBB/install/convertors/functions_phpbb20.php b/phpBB/install/convertors/functions_phpbb20.php index 69dc7bb4bc..b89c086533 100644 --- a/phpBB/install/convertors/functions_phpbb20.php +++ b/phpBB/install/convertors/functions_phpbb20.php @@ -1754,21 +1754,6 @@ function phpbb_create_userconv_table() switch ($db->get_sql_layer()) { - case 'mysql': - $map_dbms = 'mysql_40'; - break; - - case 'mysql4': - if (version_compare($db->sql_server_info(true), '4.1.3', '>=')) - { - $map_dbms = 'mysql_41'; - } - else - { - $map_dbms = 'mysql_40'; - } - break; - case 'mysqli': $map_dbms = 'mysql_41'; break; @@ -1794,13 +1779,6 @@ function phpbb_create_userconv_table() )'; break; - case 'mysql_40': - $create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' ( - user_id mediumint(8) NOT NULL, - username_clean blob NOT NULL - )'; - break; - case 'mysql_41': $create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' ( user_id mediumint(8) NOT NULL, diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index 2854f71606..f859d1674e 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -206,7 +206,6 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_filesize_pm', INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_login_attempts', '3'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_name_chars', '20'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_num_search_keywords', '10'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_pass_chars', '100'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_poll_options', '10'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_post_chars', '60000'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_post_font_size', '200'); diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index 5f47fbe6ed..d050c1b109 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -530,7 +530,7 @@ $lang = array_merge($lang, array( 'NO_POSTS_TIME_FRAME' => 'No posts exist inside this topic for the selected time frame.', 'NO_FEED_ENABLED' => 'Feeds are not available on this board.', 'NO_FEED' => 'The requested feed is not available.', - 'NO_STYLE_DATA' => 'Could not get style data', + 'NO_STYLE_DATA' => 'Could not get style data for user_style %s and set for user_id %s', 'NO_STYLE_CFG' => 'Could not get the style configuration file for: %s', 'NO_SUBJECT' => 'No subject specified', // Used for posts having no subject defined but displayed within management pages. 'NO_SUCH_SEARCH_MODULE' => 'The specified search backend doesn’t exist.', diff --git a/phpBB/language/en/email/user_activate_passwd.txt b/phpBB/language/en/email/user_activate_passwd.txt deleted file mode 100644 index 965d5a552c..0000000000 --- a/phpBB/language/en/email/user_activate_passwd.txt +++ /dev/null @@ -1,17 +0,0 @@ -Subject: New password activation - -Hello {USERNAME} - -You are receiving this notification because you have (or someone pretending to be you has) requested a new password be sent for your account on "{SITENAME}". If you did not request this notification then please ignore it, if you keep receiving it please contact the board administrator. - -To use the new password you need to activate it. To do this click the link provided below. - -{U_ACTIVATE} - -If successful you will be able to login using the following password: - -Password: {PASSWORD} - -You can of course change this password yourself via the profile page. If you have any difficulties please contact the board administrator. - -{EMAIL_SIG} diff --git a/phpBB/language/en/email/user_forgot_password.txt b/phpBB/language/en/email/user_forgot_password.txt new file mode 100644 index 0000000000..4826a7bfd9 --- /dev/null +++ b/phpBB/language/en/email/user_forgot_password.txt @@ -0,0 +1,13 @@ +Subject: Account password reset + +Hello {USERNAME} + +You are receiving this notification because you have requested to recover a forgotten password for your account on "{SITENAME}". + +To reset your password, please click the link provided below: + +{U_RESET_PASSWORD} + +If you did not authorize the request you can ignore this email. Please contact the board administrator if you keep receiving it. + +{EMAIL_SIG} diff --git a/phpBB/language/en/install.php b/phpBB/language/en/install.php index 2fd2cfd89f..53d9940560 100644 --- a/phpBB/language/en/install.php +++ b/phpBB/language/en/install.php @@ -186,7 +186,6 @@ $lang = array_merge($lang, array( // Database options 'DB_OPTION_MSSQL_ODBC' => 'MSSQL Server 2000+ via ODBC', 'DB_OPTION_MSSQLNATIVE' => 'MSSQL Server 2005+ [ Native ]', - 'DB_OPTION_MYSQL' => 'MySQL', 'DB_OPTION_MYSQLI' => 'MySQL with MySQLi Extension', 'DB_OPTION_ORACLE' => 'Oracle', 'DB_OPTION_POSTGRES' => 'PostgreSQL', diff --git a/phpBB/language/en/ucp.php b/phpBB/language/en/ucp.php index 66fb554f78..57319ae26b 100644 --- a/phpBB/language/en/ucp.php +++ b/phpBB/language/en/ucp.php @@ -402,6 +402,7 @@ $lang = array_merge($lang, array( 'NO_OLDER_PM' => 'No older messages.', 'NO_PASSWORD_SUPPLIED' => 'You cannot login without a password.', 'NO_RECIPIENT' => 'No recipient defined.', + 'NO_RESET_TOKEN' => 'You did not provide a password reset token.', 'NO_RULES_DEFINED' => 'No rules defined.', 'NO_SAVED_DRAFTS' => 'No drafts saved.', 'NO_TO_RECIPIENT' => 'None', @@ -409,13 +410,14 @@ $lang = array_merge($lang, array( 'NO_WATCHED_SELECTED' => 'You have not selected any subscribed topics or forums.', 'NO_WATCHED_TOPICS' => 'You are not subscribed to any topics.', - 'PASS_TYPE_ALPHA_EXPLAIN' => 'Password must be between %1$s and %2$s long, must contain letters in mixed case and must contain numbers.', - 'PASS_TYPE_ANY_EXPLAIN' => 'Must be between %1$s and %2$s.', - 'PASS_TYPE_CASE_EXPLAIN' => 'Password must be between %1$s and %2$s long and must contain letters in mixed case.', - 'PASS_TYPE_SYMBOL_EXPLAIN' => 'Password must be between %1$s and %2$s long, must contain letters in mixed case, must contain numbers and must contain symbols.', + 'PASS_TYPE_ALPHA_EXPLAIN' => 'Password must be at least %1$s long, must contain letters in mixed case and must contain numbers.', + 'PASS_TYPE_ANY_EXPLAIN' => 'Must be at least %1$s long.', + 'PASS_TYPE_CASE_EXPLAIN' => 'Password must be at least %1$s long and must contain letters in mixed case.', + 'PASS_TYPE_SYMBOL_EXPLAIN' => 'Password must be at least %1$s long, must contain letters in mixed case, must contain numbers and must contain symbols.', 'PASSWORD' => 'Password', 'PASSWORD_ACTIVATED' => 'Your new password has been activated.', - 'PASSWORD_UPDATED_IF_EXISTED' => 'If your account exists, a new password was sent to your registered email address. If you do not receive an email, it may be because you are banned, your account is not activated, or you are not allowed to change your password. Contact admin if any of those reasons apply. Also, check your spam filter.', + 'PASSWORD_RESET' => 'Your password has been successfully reset.', + 'PASSWORD_RESET_LINK_SENT' => 'If your account exists, a password reset link was sent to your registered email address. If you do not receive an email, it may be because you are banned, your account is not activated, you have requested multiple password resets within a short time frame, or you are not allowed to change your password. Contact an administrator if any of those reasons apply. Also, please check your spam filter.', 'PERMISSIONS_RESTORED' => 'Successfully restored original permissions.', 'PERMISSIONS_TRANSFERRED' => 'Successfully transferred permissions from <strong>%s</strong>, you are now able to browse the board with this user’s permissions.<br />Please note that admin permissions were not transferred. You are able to revert to your permission set at any time.', 'PM_DISABLED' => 'Private messaging has been disabled on this board.', @@ -463,6 +465,8 @@ $lang = array_merge($lang, array( 'REPLIED_MESSAGE' => 'Replied to message', 'REPLY_TO_ALL' => 'Reply to sender and all recipients.', 'REPORT_PM' => 'Report private message', + 'RESET_PASSWORD' => 'Reset password', + 'RESET_TOKEN_EXPIRED_OR_INVALID' => 'The password reset token you supplied is invalid or has expired.', 'RESIGN_SELECTED' => 'Resign selected', 'RETURN_FOLDER' => '%1$sReturn to previous folder%2$s', 'RETURN_UCP' => '%sReturn to the User Control Panel%s', @@ -478,7 +482,6 @@ $lang = array_merge($lang, array( 'SAME_PASSWORD_ERROR' => 'The new password you entered is the same as your current password.', 'SEARCH_YOUR_POSTS' => 'Show your posts', - 'SEND_PASSWORD' => 'Send password', 'SENT_AT' => 'Sent', // Used before dates in private messages 'SHOW_EMAIL' => 'Users can contact me by email', 'SIGNATURE_EXPLAIN' => 'This is a block of text that can be added to posts you make. There is a %d character limit.', @@ -562,7 +565,6 @@ $lang = array_merge($lang, array( 'UCP_PASSWORD_RESET_DISABLED' => 'The password reset functionality has been disabled. If you need help accessing your account, please contact the %sBoard Administrator%s', 'UCP_REGISTER_DISABLE' => 'Creating a new account is currently not possible.', - 'UCP_REMIND' => 'Send password', 'UCP_RESEND' => 'Send activation email', 'UCP_WELCOME' => 'Welcome to the User Control Panel. From here you can monitor, view and update your profile, preferences, subscribed forums and topics. You can also send messages to other users (if permitted). Please ensure you read any announcements before continuing.', 'UCP_ZEBRA' => 'Friends & Foes', diff --git a/phpBB/phpbb/cache/driver/apc.php b/phpBB/phpbb/cache/driver/apc.php deleted file mode 100644 index 521d5d41ea..0000000000 --- a/phpBB/phpbb/cache/driver/apc.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\cache\driver; - -/** -* ACM for APC -*/ -class apc extends \phpbb\cache\driver\memory -{ - var $extension = 'apc'; - - /** - * {@inheritDoc} - */ - function purge() - { - apc_clear_cache('user'); - - parent::purge(); - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - return apc_fetch($this->key_prefix . $var); - } - - /** - * Store data in the cache - * - * @access protected - * @param string $var Cache key - * @param mixed $data Data to store - * @param int $ttl Time-to-live of cached data - * @return bool True if the operation succeeded - */ - function _write($var, $data, $ttl = 2592000) - { - return apc_store($this->key_prefix . $var, $data, $ttl); - } - - /** - * Remove an item from the cache - * - * @access protected - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - function _delete($var) - { - return apc_delete($this->key_prefix . $var); - } -} diff --git a/phpBB/phpbb/config_php_file.php b/phpBB/phpbb/config_php_file.php index 7445e7df22..e3f7357720 100644 --- a/phpBB/phpbb/config_php_file.php +++ b/phpBB/phpbb/config_php_file.php @@ -155,6 +155,12 @@ class config_php_file return $dbms; } + // Force use of mysqli when specifying mysql + if (preg_match('/(phpbb\\\db\\\driver\\\)?mysql$/i', $dbms)) + { + return 'phpbb\db\driver\mysqli'; + } + throw new \RuntimeException("You have specified an invalid dbms driver: $dbms"); } } diff --git a/phpBB/phpbb/console/command/user/add.php b/phpBB/phpbb/console/command/user/add.php index c60a059251..303216a93d 100644 --- a/phpBB/phpbb/console/command/user/add.php +++ b/phpBB/phpbb/console/command/user/add.php @@ -239,7 +239,7 @@ class add extends command array('string', false, $this->config['min_name_chars'], $this->config['max_name_chars']), array('username', '')), 'new_password' => array( - array('string', false, $this->config['min_pass_chars'], $this->config['max_pass_chars']), + array('string', false, $this->config['min_pass_chars'], 0), array('password')), 'email' => array( array('string', false, 6, 60), diff --git a/phpBB/phpbb/db/driver/mysql.php b/phpBB/phpbb/db/driver/mysql.php deleted file mode 100644 index 8ce70444c2..0000000000 --- a/phpBB/phpbb/db/driver/mysql.php +++ /dev/null @@ -1,502 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\db\driver; - -/** -* MySQL4 Database Abstraction Layer -* Compatible with: -* MySQL 3.23+ -* MySQL 4.0+ -* MySQL 4.1+ -* MySQL 5.0+ -*/ -class mysql extends \phpbb\db\driver\mysql_base -{ - var $multi_insert = true; - var $connect_error = ''; - - /** - * {@inheritDoc} - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $this->persistency = $persistency; - $this->user = $sqluser; - $this->server = $sqlserver . (($port) ? ':' . $port : ''); - $this->dbname = $database; - - $this->sql_layer = 'mysql4'; - - if ($this->persistency) - { - if (!function_exists('mysql_pconnect')) - { - $this->connect_error = 'mysql_pconnect function does not exist, is mysql extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @mysql_pconnect($this->server, $this->user, $sqlpassword); - } - else - { - if (!function_exists('mysql_connect')) - { - $this->connect_error = 'mysql_connect function does not exist, is mysql extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); - } - - if ($this->db_connect_id && $this->dbname != '') - { - if (@mysql_select_db($this->dbname, $this->db_connect_id)) - { - // Determine what version we are using and if it natively supports UNICODE - if (version_compare($this->sql_server_info(true), '4.1.0', '>=')) - { - @mysql_query("SET NAMES 'utf8'", $this->db_connect_id); - - // enforce strict mode on databases that support it - if (version_compare($this->sql_server_info(true), '5.0.2', '>=')) - { - $result = @mysql_query('SELECT @@session.sql_mode AS sql_mode', $this->db_connect_id); - if ($result) - { - $row = mysql_fetch_assoc($result); - mysql_free_result($result); - $modes = array_map('trim', explode(',', $row['sql_mode'])); - } - else - { - $modes = array(); - } - - // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES - if (!in_array('TRADITIONAL', $modes)) - { - if (!in_array('STRICT_ALL_TABLES', $modes)) - { - $modes[] = 'STRICT_ALL_TABLES'; - } - - if (!in_array('STRICT_TRANS_TABLES', $modes)) - { - $modes[] = 'STRICT_TRANS_TABLES'; - } - } - - $mode = implode(',', $modes); - @mysql_query("SET SESSION sql_mode='{$mode}'", $this->db_connect_id); - } - } - else if (version_compare($this->sql_server_info(true), '4.0.0', '<')) - { - $this->sql_layer = 'mysql'; - } - - return $this->db_connect_id; - } - } - - return $this->sql_error(''); - } - - /** - * {@inheritDoc} - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysql_version')) === false) - { - $result = @mysql_query('SELECT VERSION() AS version', $this->db_connect_id); - if ($result) - { - $row = mysql_fetch_assoc($result); - mysql_free_result($result); - - $this->sql_server_version = $row['version']; - - if (!empty($cache) && $use_cache) - { - $cache->put('mysql_version', $this->sql_server_version); - } - } - } - - return ($raw) ? $this->sql_server_version : 'MySQL ' . $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @mysql_query('BEGIN', $this->db_connect_id); - break; - - case 'commit': - return @mysql_query('COMMIT', $this->db_connect_id); - break; - - case 'rollback': - return @mysql_query('ROLLBACK', $this->db_connect_id); - break; - } - - return true; - } - - /** - * {@inheritDoc} - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - if ($this->debug_sql_explain) - { - $this->sql_report('start', $query); - } - else if ($this->debug_load_time) - { - $this->curtime = microtime(true); - } - - $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - if (($this->query_result = @mysql_query($query, $this->db_connect_id)) === false) - { - $this->sql_error($query); - } - - if ($this->debug_sql_explain) - { - $this->sql_report('stop', $query); - } - else if ($this->debug_load_time) - { - $this->sql_time += microtime(true) - $this->curtime; - } - - if (!$this->query_result) - { - return false; - } - - if ($cache && $cache_ttl) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if ($this->debug_sql_explain) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * {@inheritDoc} - */ - function sql_affectedrows() - { - if ($this->db_connect_id) - { - // We always want the number of matched rows - // instead of changed rows, when running an update. - // So when mysql_info() returns the number of matched rows - // we return that one instead of mysql_affected_rows() - $mysql_info = @mysql_info($this->db_connect_id); - if ($mysql_info !== false) - { - $match = array(); - preg_match('#^Rows matched: (\d)+ Changed: (\d)+ Warnings: (\d)+$#', $mysql_info, $match); - if (isset($match[1])) - { - return $match[1]; - } - } - - return @mysql_affected_rows($this->db_connect_id); - } - return false; - } - - /** - * {@inheritDoc} - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($cache && $cache->sql_exists($query_id)) - { - return $cache->sql_fetchrow($query_id); - } - - return ($query_id) ? mysql_fetch_assoc($query_id) : false; - } - - /** - * {@inheritDoc} - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($cache && $cache->sql_exists($query_id)) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - return ($query_id !== false) ? @mysql_data_seek($query_id, $rownum) : false; - } - - /** - * {@inheritDoc} - */ - function sql_nextid() - { - return ($this->db_connect_id) ? @mysql_insert_id($this->db_connect_id) : false; - } - - /** - * {@inheritDoc} - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($cache && !is_object($query_id) && $cache->sql_exists($query_id)) - { - return $cache->sql_freeresult($query_id); - } - - if (isset($this->open_queries[(int) $query_id])) - { - unset($this->open_queries[(int) $query_id]); - return mysql_free_result($query_id); - } - - return false; - } - - /** - * {@inheritDoc} - */ - function sql_escape($msg) - { - if (!$this->db_connect_id) - { - return @mysql_real_escape_string($msg); - } - - return @mysql_real_escape_string($msg, $this->db_connect_id); - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if ($this->db_connect_id) - { - $error = array( - 'message' => @mysql_error($this->db_connect_id), - 'code' => @mysql_errno($this->db_connect_id), - ); - } - else if (function_exists('mysql_error')) - { - $error = array( - 'message' => @mysql_error(), - 'code' => @mysql_errno(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @mysql_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - static $test_prof; - - // current detection method, might just switch to see the existence of INFORMATION_SCHEMA.PROFILING - if ($test_prof === null) - { - $test_prof = false; - if (version_compare($this->sql_server_info(true), '5.0.37', '>=') && version_compare($this->sql_server_info(true), '5.1', '<')) - { - $test_prof = true; - } - } - - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - // begin profiling - if ($test_prof) - { - @mysql_query('SET profiling = 1;', $this->db_connect_id); - } - - if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id)) - { - while ($row = mysql_fetch_assoc($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - mysql_free_result($result); - } - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - - if ($test_prof) - { - $html_table = false; - - // get the last profile - if ($result = @mysql_query('SHOW PROFILE ALL;', $this->db_connect_id)) - { - $this->html_hold .= '<br />'; - while ($row = mysql_fetch_assoc($result)) - { - // make <unknown> HTML safe - if (!empty($row['Source_function'])) - { - $row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']); - } - - // remove unsupported features - foreach ($row as $key => $val) - { - if ($val === null) - { - unset($row[$key]); - } - } - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - mysql_free_result($result); - } - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - - @mysql_query('SET profiling = 0;', $this->db_connect_id); - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @mysql_query($query, $this->db_connect_id); - if ($result) - { - while ($void = mysql_fetch_assoc($result)) - { - // Take the time spent on parsing rows into account - } - mysql_free_result($result); - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} diff --git a/phpBB/phpbb/db/extractor/mysql_extractor.php b/phpBB/phpbb/db/extractor/mysql_extractor.php index 534e8b7653..f3cb0db457 100644 --- a/phpBB/phpbb/db/extractor/mysql_extractor.php +++ b/phpBB/phpbb/db/extractor/mysql_extractor.php @@ -79,14 +79,7 @@ class mysql_extractor extends base_extractor throw new extractor_not_initialized_exception(); } - if ($this->db->get_sql_layer() === 'mysqli') - { - $this->write_data_mysqli($table_name); - } - else - { - $this->write_data_mysql($table_name); - } + $this->write_data_mysqli($table_name); } /** @@ -180,101 +173,6 @@ class mysql_extractor extends base_extractor } /** - * Extracts data from database table (for MySQL driver) - * - * @param string $table_name name of the database table - * @return null - * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor() - */ - protected function write_data_mysql($table_name) - { - if (!$this->is_initialized) - { - throw new extractor_not_initialized_exception(); - } - - $sql = "SELECT * - FROM $table_name"; - $result = mysql_unbuffered_query($sql, $this->db->get_db_connect_id()); - - if ($result != false) - { - $fields_cnt = mysql_num_fields($result); - - // Get field information - $field = array(); - for ($i = 0; $i < $fields_cnt; $i++) - { - $field[] = mysql_fetch_field($result, $i); - } - $field_set = array(); - - for ($j = 0; $j < $fields_cnt; $j++) - { - $field_set[] = $field[$j]->name; - } - - $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"'); - $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"'); - $fields = implode(', ', $field_set); - $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES '; - $first_set = true; - $query_len = 0; - $max_len = get_usable_memory(); - - while ($row = mysql_fetch_row($result)) - { - $values = array(); - if ($first_set) - { - $query = $sql_data . '('; - } - else - { - $query .= ',('; - } - - for ($j = 0; $j < $fields_cnt; $j++) - { - if (!isset($row[$j]) || is_null($row[$j])) - { - $values[$j] = 'NULL'; - } - else if ($field[$j]->numeric && ($field[$j]->type !== 'timestamp')) - { - $values[$j] = $row[$j]; - } - else - { - $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'"; - } - } - $query .= implode(', ', $values) . ')'; - - $query_len += strlen($query); - if ($query_len > $max_len) - { - $this->flush($query . ";\n\n"); - $query = ''; - $query_len = 0; - $first_set = true; - } - else - { - $first_set = false; - } - } - mysql_free_result($result); - - // check to make sure we have nothing left to flush - if (!$first_set && $query) - { - $this->flush($query . ";\n\n"); - } - } - } - - /** * Extracts database table structure (for MySQLi or MySQL 3.23.20+) * * @param string $table_name name of the database table diff --git a/phpBB/phpbb/db/migration/data/v330/remove_max_pass_chars.php b/phpBB/phpbb/db/migration/data/v330/remove_max_pass_chars.php new file mode 100644 index 0000000000..10e5ee385d --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/remove_max_pass_chars.php @@ -0,0 +1,43 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\migration\data\v330; + +class remove_max_pass_chars extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return !$this->config->offsetExists('max_pass_chars'); + } + + public static function depends_on() + { + return [ + '\phpbb\db\migration\data\v330\dev', + ]; + } + + public function update_data() + { + return [ + ['config.remove', ['max_pass_chars']], + ]; + } + + public function revert_data() + { + return [ + ['config.add', ['max_pass_chars', 100]], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v330/reset_password.php b/phpBB/phpbb/db/migration/data/v330/reset_password.php new file mode 100644 index 0000000000..953d478ccc --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/reset_password.php @@ -0,0 +1,48 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\migration\data\v330; + +class reset_password extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return [ + '\phpbb\db\migration\data\v330\dev', + ]; + } + + public function update_schema() + { + return [ + 'add_columns' => [ + $this->table_prefix . 'users' => [ + 'reset_token' => ['VCHAR:64', '', 'after' => 'user_actkey'], + 'reset_token_expiration' => ['TIMESTAMP', 0, 'after' => 'reset_token'], + ], + ], + ]; + } + + public function revert_schema() + { + return [ + 'drop_columns' => [ + $this->table_prefix . 'users' => [ + 'reset_token', + 'reset_token_expiration', + ], + ], + ]; + } +} diff --git a/phpBB/phpbb/db/tools/tools.php b/phpBB/phpbb/db/tools/tools.php index d128df96c4..1250a8901d 100644 --- a/phpBB/phpbb/db/tools/tools.php +++ b/phpBB/phpbb/db/tools/tools.php @@ -74,37 +74,6 @@ class tools implements tools_interface 'VARBINARY' => 'varbinary(255)', ), - 'mysql_40' => array( - 'INT:' => 'int(%d)', - 'BINT' => 'bigint(20)', - 'ULINT' => 'INT(10) UNSIGNED', - 'UINT' => 'mediumint(8) UNSIGNED', - 'UINT:' => 'int(%d) UNSIGNED', - 'TINT:' => 'tinyint(%d)', - 'USINT' => 'smallint(4) UNSIGNED', - 'BOOL' => 'tinyint(1) UNSIGNED', - 'VCHAR' => 'varbinary(255)', - 'VCHAR:' => 'varbinary(%d)', - 'CHAR:' => 'binary(%d)', - 'XSTEXT' => 'blob', - 'XSTEXT_UNI'=> 'blob', - 'STEXT' => 'blob', - 'STEXT_UNI' => 'blob', - 'TEXT' => 'blob', - 'TEXT_UNI' => 'blob', - 'MTEXT' => 'mediumblob', - 'MTEXT_UNI' => 'mediumblob', - 'TIMESTAMP' => 'int(11) UNSIGNED', - 'DECIMAL' => 'decimal(5,2)', - 'DECIMAL:' => 'decimal(%d,2)', - 'PDECIMAL' => 'decimal(6,3)', - 'PDECIMAL:' => 'decimal(%d,3)', - 'VCHAR_UNI' => 'blob', - 'VCHAR_UNI:'=> array('varbinary(%d)', 'limit' => array('mult', 3, 255, 'blob')), - 'VCHAR_CI' => 'blob', - 'VARBINARY' => 'varbinary(255)', - ), - 'oracle' => array( 'INT:' => 'number(%d)', 'BINT' => 'number(20)', @@ -197,21 +166,6 @@ class tools implements tools_interface // Determine mapping database type switch ($this->db->get_sql_layer()) { - case 'mysql': - $this->sql_layer = 'mysql_40'; - break; - - case 'mysql4': - if (version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) - { - $this->sql_layer = 'mysql_41'; - } - else - { - $this->sql_layer = 'mysql_40'; - } - break; - case 'mysqli': $this->sql_layer = 'mysql_41'; break; @@ -240,8 +194,6 @@ class tools implements tools_interface { switch ($this->db->get_sql_layer()) { - case 'mysql': - case 'mysql4': case 'mysqli': $sql = 'SHOW TABLES'; break; @@ -359,7 +311,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': case 'sqlite3': $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')'; @@ -381,7 +332,6 @@ class tools implements tools_interface $statements[] = $table_sql; break; - case 'mysql_40': case 'sqlite3': $table_sql .= "\n);"; $statements[] = $table_sql; @@ -834,7 +784,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $sql = "SHOW COLUMNS FROM $table_name"; break; @@ -911,7 +860,6 @@ class tools implements tools_interface { switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $sql = 'SHOW KEYS FROM ' . $table_name; @@ -936,7 +884,7 @@ class tools implements tools_interface $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { - if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) + if ($this->sql_layer == 'mysql_41' && !$row['Non_unique']) { continue; } @@ -971,7 +919,6 @@ class tools implements tools_interface { switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $sql = 'SHOW KEYS FROM ' . $table_name; @@ -996,7 +943,7 @@ class tools implements tools_interface $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { - if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY')) + if ($this->sql_layer == 'mysql_41' && ($row['Non_unique'] || $row[$col] == 'PRIMARY')) { continue; } @@ -1094,7 +1041,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $sql .= " {$column_type} "; @@ -1248,7 +1194,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : ''; $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after; @@ -1281,7 +1226,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $statements[] = 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column_name . '`'; break; @@ -1360,7 +1304,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $index_name = $this->check_index_name_length($table_name, $index_name, false); $statements[] = 'DROP INDEX ' . $index_name . ' ON ' . $table_name; @@ -1422,7 +1365,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')'; break; @@ -1500,7 +1442,6 @@ class tools implements tools_interface $statements[] = 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; - case 'mysql_40': case 'mysql_41': $index_name = $this->check_index_name_length($table_name, $index_name); $statements[] = 'ALTER TABLE ' . $table_name . ' ADD UNIQUE INDEX ' . $index_name . '(' . implode(', ', $column) . ')'; @@ -1517,11 +1458,7 @@ class tools implements tools_interface { $statements = array(); - // remove index length unless MySQL4 - if ('mysql_40' != $this->sql_layer) - { - $column = preg_replace('#:.*$#', '', $column); - } + $column = preg_replace('#:.*$#', '', $column); switch ($this->sql_layer) { @@ -1531,17 +1468,6 @@ class tools implements tools_interface $statements[] = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; - case 'mysql_40': - // add index size to definition as required by MySQL4 - foreach ($column as $i => $col) - { - if (false !== strpos($col, ':')) - { - list($col, $index_size) = explode(':', $col); - $column[$i] = "$col($index_size)"; - } - } - // no break case 'mysql_41': $index_name = $this->check_index_name_length($table_name, $index_name); $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . ' (' . implode(', ', $column) . ')'; @@ -1609,7 +1535,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $sql = 'SHOW KEYS FROM ' . $table_name; @@ -1634,7 +1559,7 @@ class tools implements tools_interface $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { - if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) + if ($this->sql_layer == 'mysql_41' && !$row['Non_unique']) { continue; } @@ -1677,7 +1602,6 @@ class tools implements tools_interface switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': $statements[] = 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_name . '` `' . $column_name . '` ' . $column_data['column_type_sql']; break; @@ -1826,7 +1750,6 @@ class tools implements tools_interface { switch ($this->sql_layer) { - case 'mysql_40': case 'mysql_41': case 'sqlite3': // Not supported diff --git a/phpBB/phpbb/install/helper/database.php b/phpBB/phpbb/install/helper/database.php index fa5a10c6fc..51fd18f874 100644 --- a/phpBB/phpbb/install/helper/database.php +++ b/phpBB/phpbb/install/helper/database.php @@ -45,15 +45,6 @@ class database 'AVAILABLE' => true, '2.0.x' => true, ), - 'mysql' => array( - 'LABEL' => 'MySQL', - 'SCHEMA' => 'mysql', - 'MODULE' => 'mysql', - 'DELIM' => ';', - 'DRIVER' => 'phpbb\db\driver\mysql', - 'AVAILABLE' => true, - '2.0.x' => true, - ), 'mssql_odbc'=> array( 'LABEL' => 'MS SQL Server [ ODBC ]', 'SCHEMA' => 'mssql', @@ -256,7 +247,6 @@ class database $dbms_info = $this->get_available_dbms($dbms); switch ($dbms_info[$dbms]['SCHEMA']) { - case 'mysql': case 'mysql_41': $prefix_length = 36; break; @@ -382,14 +372,6 @@ class database // Check if database version is supported switch ($dbms) { - case 'mysqli': - if (version_compare($db->sql_server_info(true), '4.1.3', '<')) - { - $errors[] = array( - 'title' => 'INST_ERR_DB_NO_MYSQLI', - ); - } - break; case 'sqlite3': if (version_compare($db->sql_server_info(true), '3.6.15', '<')) { diff --git a/phpBB/phpbb/install/module/install_database/task/create_schema.php b/phpBB/phpbb/install/module/install_database/task/create_schema.php index a5635d5dbe..983bb42122 100644 --- a/phpBB/phpbb/install/module/install_database/task/create_schema.php +++ b/phpBB/phpbb/install/module/install_database/task/create_schema.php @@ -129,14 +129,7 @@ class create_schema extends \phpbb\install\task_base if ($dbms === 'mysql') { - if (version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) - { - $schema_name .= '_41'; - } - else - { - $schema_name .= '_40'; - } + $schema_name .= '_41'; } $db_schema_path = $this->phpbb_root_path . 'install/schemas/' . $schema_name . '_schema.sql'; diff --git a/phpBB/phpbb/install/module/install_database/task/set_up_database.php b/phpBB/phpbb/install/module/install_database/task/set_up_database.php index 49c8ea23ad..4da5ece228 100644 --- a/phpBB/phpbb/install/module/install_database/task/set_up_database.php +++ b/phpBB/phpbb/install/module/install_database/task/set_up_database.php @@ -102,14 +102,7 @@ class set_up_database extends \phpbb\install\task_base if ($dbms === 'mysql') { - if (version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) - { - $schema_name .= '_41'; - } - else - { - $schema_name .= '_40'; - } + $schema_name .= '_41'; } $this->schema_file_path = $this->phpbb_root_path . 'install/schemas/' . $schema_name . '_schema.sql'; diff --git a/phpBB/phpbb/search/fulltext_mysql.php b/phpBB/phpbb/search/fulltext_mysql.php index 4d3e13663d..8bdc31e128 100644 --- a/phpBB/phpbb/search/fulltext_mysql.php +++ b/phpBB/phpbb/search/fulltext_mysql.php @@ -154,7 +154,7 @@ class fulltext_mysql extends \phpbb\search\base */ public function init() { - if ($this->db->get_sql_layer() != 'mysql4' && $this->db->get_sql_layer() != 'mysqli') + if ($this->db->get_sql_layer() != 'mysqli') { return $this->user->lang['FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE']; } @@ -1005,14 +1005,7 @@ class fulltext_mysql extends \phpbb\search\base if (!isset($this->stats['post_subject'])) { $alter_entry = array(); - if ($this->db->get_sql_layer() == 'mysqli' || version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) - { - $alter_entry[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; - } - else - { - $alter_entry[] = 'MODIFY post_subject text NOT NULL'; - } + $alter_entry[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; $alter_entry[] = 'ADD FULLTEXT (post_subject)'; $alter_list[] = $alter_entry; } @@ -1020,15 +1013,7 @@ class fulltext_mysql extends \phpbb\search\base if (!isset($this->stats['post_content'])) { $alter_entry = array(); - if ($this->db->get_sql_layer() == 'mysqli' || version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) - { - $alter_entry[] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL'; - } - else - { - $alter_entry[] = 'MODIFY post_text mediumtext NOT NULL'; - } - + $alter_entry[] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL'; $alter_entry[] = 'ADD FULLTEXT post_content (post_text, post_subject)'; $alter_list[] = $alter_entry; } diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php index ecebbd37cd..295c2cf33c 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -889,7 +889,6 @@ class fulltext_native extends \phpbb\search\base switch ($this->db->get_sql_layer()) { - case 'mysql4': case 'mysqli': // 3.x does not support SQL_CALC_FOUND_ROWS @@ -1184,7 +1183,6 @@ class fulltext_native extends \phpbb\search\base { switch ($this->db->get_sql_layer()) { - case 'mysql4': case 'mysqli': // $select = 'SQL_CALC_FOUND_ROWS ' . $select; $is_mysql = true; diff --git a/phpBB/phpbb/search/fulltext_sphinx.php b/phpBB/phpbb/search/fulltext_sphinx.php index d8331d3815..6230f92da3 100644 --- a/phpBB/phpbb/search/fulltext_sphinx.php +++ b/phpBB/phpbb/search/fulltext_sphinx.php @@ -214,7 +214,7 @@ class fulltext_sphinx */ public function init() { - if ($this->db->get_sql_layer() != 'mysql' && $this->db->get_sql_layer() != 'mysql4' && $this->db->get_sql_layer() != 'mysqli' && $this->db->get_sql_layer() != 'postgres') + if ($this->db->get_sql_layer() != 'mysqli' && $this->db->get_sql_layer() != 'postgres') { return $this->user->lang['FULLTEXT_SPHINX_WRONG_DATABASE']; } @@ -233,7 +233,7 @@ class fulltext_sphinx protected function config_generate() { // Check if Database is supported by Sphinx - if ($this->db->get_sql_layer() =='mysql' || $this->db->get_sql_layer() == 'mysql4' || $this->db->get_sql_layer() == 'mysqli') + if ($this->db->get_sql_layer() == 'mysqli') { $this->dbtype = 'mysql'; } diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php new file mode 100644 index 0000000000..7bd1b20cb3 --- /dev/null +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -0,0 +1,443 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\ucp\controller; + +use phpbb\auth\auth; +use phpbb\config\config; +use phpbb\controller\helper; +use phpbb\db\driver\driver_interface; +use phpbb\event\dispatcher; +use phpbb\exception\http_exception; +use phpbb\language\language; +use phpbb\log\log_interface; +use phpbb\passwords\manager; +use phpbb\request\request_interface; +use phpbb\template\template; +use phpbb\user; +use Symfony\Component\HttpFoundation\Response; + +/** +* Handling forgotten passwords via reset password functionality +*/ +class reset_password +{ + /** @var config */ + protected $config; + + /** @var driver_interface */ + protected $db; + + /** @var dispatcher */ + protected $dispatcher; + + /** @var helper */ + protected $helper; + + /** @var language */ + protected $language; + + /** @var log_interface */ + protected $log; + + /** @var manager */ + protected $passwords_manager; + + /** @var request_interface */ + protected $request; + + /** @var template */ + protected $template; + + /** @var user */ + protected $user; + + /** @var array phpBB DB table names */ + protected $users_table; + + /** @var string phpBB root path */ + protected $root_path; + + /** @var string PHP extension */ + protected $php_ext; + + /** + * Reset password controller constructor. + * + * @param config $config + * @param driver_interface $db + * @param dispatcher $dispatcher + * @param helper $helper + * @param language $language + * @param log_interface $log + * @param manager $passwords_manager + * @param request_interface $request + * @param template $template + * @param user $user + * @param string $users_table + * @param string $root_path + * @param string $php_ext + */ + public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, helper $helper, + language $language, log_interface $log, manager $passwords_manager, + request_interface $request, template $template, user $user, string $users_table, + string $root_path, string $php_ext) + { + $this->config = $config; + $this->db = $db; + $this->dispatcher = $dispatcher; + $this->helper = $helper; + $this->language = $language; + $this->log = $log; + $this->passwords_manager = $passwords_manager; + $this->request = $request; + $this->template = $template; + $this->user = $user; + $this->users_table = $users_table; + $this->root_path = $root_path; + $this->php_ext = $php_ext; + } + + /** + * Init controller + */ + protected function init_controller() + { + $this->language->add_lang('ucp'); + + if (!$this->config['allow_password_reset']) + { + throw new http_exception(Response::HTTP_OK, 'UCP_PASSWORD_RESET_DISABLED', [ + '<a href="mailto:' . htmlspecialchars($this->config['board_contact']) . '">', + '</a>' + ]); + } + } + + /** + * Remove reset token for specified user + * + * @param int $user_id User ID + */ + protected function remove_reset_token(int $user_id) + { + $sql_ary = [ + 'reset_token' => '', + 'reset_token_expiration' => 0, + ]; + + $sql = 'UPDATE ' . $this->users_table . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . $user_id; + $this->db->sql_query($sql); + } + + /** + * Handle password reset request + * + * @return Response + */ + public function request() + { + $this->init_controller(); + + $submit = $this->request->is_set_post('submit'); + $username = $this->request->variable('username', '', true); + $email = strtolower($this->request->variable('email', '')); + + add_form_key('ucp_reset_password'); + + if ($submit) + { + if (!check_form_key('ucp_reset_password')) + { + throw new http_exception(Response::HTTP_UNAUTHORIZED, 'FORM_INVALID'); + } + + if (empty($email)) + { + return $this->helper->message('NO_EMAIL_USER'); + } + + $sql_array = [ + 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type,' + . ' user_lang, user_inactive_reason, reset_token, reset_token_expiration', + 'FROM' => [$this->users_table => 'u'], + 'WHERE' => "user_email_hash = '" . $this->db->sql_escape(phpbb_email_hash($email)) . "'" . + (!empty($username) ? " AND username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'" : ''), + ]; + + /** + * Change SQL query for fetching user data + * + * @event core.ucp_remind_modify_select_sql + * @var string email User's email from the form + * @var string username User's username from the form + * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE + * @since 3.1.11-RC1 + * @changed 3.3.0-b1 Moved to reset password controller + */ + $vars = [ + 'email', + 'username', + 'sql_array', + ]; + extract($this->dispatcher->trigger_event('core.ucp_remind_modify_select_sql', compact($vars))); + + $sql = $this->db->sql_build_query('SELECT', $sql_array); + $result = $this->db->sql_query_limit($sql, 2); // don't waste resources on more rows than we need + $rowset = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + if (count($rowset) > 1) + { + $this->template->assign_vars([ + 'USERNAME_REQUIRED' => true, + 'EMAIL' => $email, + ]); + } + else + { + $message = $this->language->lang('PASSWORD_RESET_LINK_SENT') . '<br /><br />' . $this->language->lang('RETURN_INDEX', '<a href="' . append_sid("{$this->root_path}index.{$this->php_ext}") . '">', '</a>'); + + if (empty($rowset)) + { + return $this->helper->message($message); + } + + $user_row = $rowset[0]; + + if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) + { + return $this->helper->message($message); + } + + // Do not create multiple valid reset tokens + if (!empty($user_row['reset_token']) && (int) $user_row['reset_token_expiration'] >= time()) + { + return $this->helper->message($message); + } + + // Check users permissions + $auth = new auth(); + $auth->acl($user_row); + + if (!$auth->acl_get('u_chgpasswd')) + { + return $this->helper->message($message); + } + + // Generate reset token + $reset_token = strtolower(gen_rand_string(32)); + + $sql_ary = [ + 'reset_token' => $reset_token, + 'reset_token_expiration' => strtotime('+1 day'), + ]; + + $sql = 'UPDATE ' . $this->users_table . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . $user_row['user_id']; + $this->db->sql_query($sql); + + if (!class_exists('messenger')) + { + include($this->root_path . 'includes/functions_messenger.' . $this->php_ext); + } + + /** @var \messenger $messenger */ + $messenger = new \messenger(false); + + $messenger->template('user_forgot_password', $user_row['user_lang']); + + $messenger->set_addresses($user_row); + + $messenger->anti_abuse_headers($this->config, $this->user); + + $messenger->assign_vars([ + 'USERNAME' => htmlspecialchars_decode($user_row['username']), + 'U_RESET_PASSWORD' => generate_board_url(true) . $this->helper->route('phpbb_ucp_reset_password_controller', [ + 'u' => $user_row['user_id'], + 'token' => $reset_token, + ], false) + ]); + + $messenger->send($user_row['user_notify_type']); + + return $this->helper->message($message); + } + } + + $this->template->assign_vars([ + 'USERNAME' => $username, + 'EMAIL' => $email, + 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_forgot_password_controller'), + ]); + + return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); + } + + /** + * Handle controller requests + * + * @return Response + */ + public function reset() + { + $this->init_controller(); + + $submit = $this->request->is_set_post('submit'); + $reset_token = $this->request->variable('token', ''); + $user_id = $this->request->variable('u', 0); + + if (empty($reset_token)) + { + return $this->helper->message('NO_RESET_TOKEN'); + } + + if (!$user_id) + { + return $this->helper->message('NO_USER'); + } + + add_form_key('ucp_reset_password'); + + $sql_array = [ + 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type,' + . ' user_lang, user_inactive_reason, reset_token, reset_token_expiration', + 'FROM' => [$this->users_table => 'u'], + 'WHERE' => 'user_id = ' . $user_id, + ]; + + /** + * Change SQL query for fetching user data + * + * @event core.ucp_reset_password_modify_select_sql + * @var int user_id User ID from the form + * @var string reset_token Reset token + * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE + * @since 3.3.0-b1 + */ + $vars = [ + 'user_id', + 'reset_token', + 'sql_array', + ]; + extract($this->dispatcher->trigger_event('core.ucp_reset_password_modify_select_sql', compact($vars))); + + $sql = $this->db->sql_build_query('SELECT', $sql_array); + $result = $this->db->sql_query_limit($sql, 1); + $user_row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $message = $this->language->lang('RESET_TOKEN_EXPIRED_OR_INVALID') . '<br /><br />' . $this->language->lang('RETURN_INDEX', '<a href="' . append_sid("{$this->root_path}index.{$this->php_ext}") . '">', '</a>'); + + if (empty($user_row)) + { + return $this->helper->message($message); + } + + if (!hash_equals($reset_token, $user_row['reset_token'])) + { + return $this->helper->message($message); + } + + if ($user_row['reset_token_expiration'] < time()) + { + $this->remove_reset_token($user_id); + + return $this->helper->message($message); + } + + $errors = []; + + if ($submit) + { + if (!check_form_key('ucp_reset_password')) + { + return $this->helper->message('FORM_INVALID'); + } + + if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) + { + return $this->helper->message($message); + } + + // Check users permissions + $auth = new auth(); + $auth->acl($user_row); + + if (!$auth->acl_get('u_chgpasswd')) + { + return $this->helper->message($message); + } + + if (!function_exists('validate_data')) + { + include($this->root_path . 'includes/functions_user.' . $this->php_ext); + } + + $data = [ + 'new_password' => $this->request->untrimmed_variable('new_password', '', true), + 'password_confirm' => $this->request->untrimmed_variable('new_password_confirm', '', true), + ]; + $check_data = [ + 'new_password' => [ + ['string', false, $this->config['min_pass_chars'], 0], + ['password'], + ], + 'password_confirm' => ['string', true, $this->config['min_pass_chars'], 0], + ]; + $errors = array_merge($errors, validate_data($data, $check_data)); + if (strcmp($data['new_password'], $data['password_confirm']) !== 0) + { + $errors[] = $data['password_confirm'] ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; + } + if (empty($errors)) + { + $sql_ary = [ + 'user_password' => $this->passwords_manager->hash($data['new_password']), + 'user_login_attempts' => 0, + 'reset_token' => '', + 'reset_token_expiration' => 0, + ]; + $sql = 'UPDATE ' . $this->users_table . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . (int) $user_row['user_id']; + $this->db->sql_query($sql); + $this->log->add('user', $user_row['user_id'], $this->user->ip, 'LOG_USER_NEW_PASSWORD', false, [ + 'reportee_id' => $user_row['user_id'], + $user_row['username'] + ]); + meta_refresh(3, append_sid("{$this->root_path}index.{$this->php_ext}")); + return $this->helper->message($this->language->lang('PASSWORD_RESET')); + } + } + + if (!empty($errors)) + { + $this->template->assign_block_vars_array('PASSWORD_RESET_ERRORS', array_map([$this->language, 'lang'], $errors)); + } + + $this->template->assign_vars([ + 'S_IS_PASSWORD_RESET' => true, + 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), + 'S_HIDDEN_FIELDS' => build_hidden_fields([ + 'u' => $user_id, + 'token' => $reset_token, + ]), + ]); + + return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); + } +} diff --git a/phpBB/phpbb/user.php b/phpBB/phpbb/user.php index 5a06becb52..21d156e060 100644 --- a/phpBB/phpbb/user.php +++ b/phpBB/phpbb/user.php @@ -281,9 +281,43 @@ class user extends \phpbb\session $db->sql_freeresult($result); } + // Fallback to board's default style if (!$this->style) { - trigger_error('NO_STYLE_DATA', E_USER_ERROR); + // Verify default style exists in the database + $sql = 'SELECT style_id + FROM ' . STYLES_TABLE . ' + WHERE style_id = ' . (int) $config['default_style']; + $result = $db->sql_query($sql); + $style_id = (int) $db->sql_fetchfield('style_id'); + $db->sql_freeresult($result); + + if ($style_id > 0) + { + $db->sql_transaction('begin'); + + // Update $user row + $sql = 'SELECT * + FROM ' . STYLES_TABLE . ' + WHERE style_id = ' . (int) $config['default_style']; + $result = $db->sql_query($sql); + $this->style = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + // Update user style preference + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_style = ' . (int) $style_id . ' + WHERE user_id = ' . (int) $this->data['user_id']; + $db->sql_query($sql); + + $db->sql_transaction('commit'); + } + } + + // This should never happen + if (!$this->style) + { + trigger_error($this->language->lang('NO_STYLE_DATA', $this->data['user_style'], $this->data['user_id']), E_USER_ERROR); } // Now parse the cfg file and cache it diff --git a/phpBB/styles/prosilver/template/navbar_header.html b/phpBB/styles/prosilver/template/navbar_header.html index ecb67012a4..4a1a436d4a 100644 --- a/phpBB/styles/prosilver/template/navbar_header.html +++ b/phpBB/styles/prosilver/template/navbar_header.html @@ -183,16 +183,16 @@ <!-- EVENT overall_header_breadcrumbs_before --> <li class="breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList"> <!-- IF U_SITE_HOME --> - <span class="crumb" {$MICRODATA}><a href="{U_SITE_HOME}" itemtype="https://schema.org/Thing" itemprop="item" data-navbar-reference="home"><i class="icon fa-home fa-fw" aria-hidden="true"></i><span itemprop="name">{L_SITE_HOME}</span></a><meta itemprop="position" content="{{ navlink_position }}{% set navlink_position = navlink_position + 1 %}" /></span> + <span class="crumb" {$MICRODATA}><a href="{U_SITE_HOME}" itemtype="https://schema.org/Thing" itemscope itemprop="item" data-navbar-reference="home"><i class="icon fa-home fa-fw" aria-hidden="true"></i><span itemprop="name">{L_SITE_HOME}</span></a><meta itemprop="position" content="{{ navlink_position }}{% set navlink_position = navlink_position + 1 %}" /></span> <!-- ENDIF --> <!-- EVENT overall_header_breadcrumb_prepend --> - <span class="crumb" {$MICRODATA}><a href="{U_INDEX}" itemtype="https://schema.org/Thing" itemprop="item" accesskey="h" data-navbar-reference="index"><!-- IF not U_SITE_HOME --><i class="icon fa-home fa-fw"></i><!-- ENDIF --><span itemprop="name">{L_INDEX}</span></a><meta itemprop="position" content="{{ navlink_position }}{% set navlink_position = navlink_position + 1 %}" /></span> + <span class="crumb" {$MICRODATA}><a href="{U_INDEX}" itemtype="https://schema.org/Thing" itemscope itemprop="item" accesskey="h" data-navbar-reference="index"><!-- IF not U_SITE_HOME --><i class="icon fa-home fa-fw"></i><!-- ENDIF --><span itemprop="name">{L_INDEX}</span></a><meta itemprop="position" content="{{ navlink_position }}{% set navlink_position = navlink_position + 1 %}" /></span> <!-- BEGIN navlinks --> {% set NAVLINK_NAME = navlinks.BREADCRUMB_NAME | default(navlinks.FORUM_NAME) %} {% set NAVLINK_LINK = navlinks.U_BREADCRUMB | default(navlinks.U_VIEW_FORUM) %} <!-- EVENT overall_header_navlink_prepend --> - <span class="crumb" {$MICRODATA}<!-- IF navlinks.MICRODATA --> {navlinks.MICRODATA}<!-- ENDIF -->><a href="{{ NAVLINK_LINK }}" itemtype="https://schema.org/Thing" itemprop="item"><span itemprop="name">{{ NAVLINK_NAME }}</span></a><meta itemprop="position" content="{{ navlink_position }}{% set navlink_position = navlink_position + 1 %}" /></span> + <span class="crumb" {$MICRODATA}<!-- IF navlinks.MICRODATA --> {navlinks.MICRODATA}<!-- ENDIF -->><a href="{{ NAVLINK_LINK }}" itemtype="https://schema.org/Thing" itemscope itemprop="item"><span itemprop="name">{{ NAVLINK_NAME }}</span></a><meta itemprop="position" content="{{ navlink_position }}{% set navlink_position = navlink_position + 1 %}" /></span> <!-- EVENT overall_header_navlink_append --> <!-- END navlinks --> <!-- EVENT overall_header_breadcrumb_append --> diff --git a/phpBB/styles/prosilver/template/overall_footer.html b/phpBB/styles/prosilver/template/overall_footer.html index bdff1a0c05..cd245decc4 100644 --- a/phpBB/styles/prosilver/template/overall_footer.html +++ b/phpBB/styles/prosilver/template/overall_footer.html @@ -17,7 +17,7 @@ </p> <!-- ENDIF --> <!-- EVENT overall_footer_copyright_append --> - <p class="footer-row"> + <p class="footer-row" role="menu"> <a class="footer-link" href="{{ U_PRIVACY }}" title="{{ lang('PRIVACY_LINK') }}" role="menuitem"> <span class="footer-link-text">{{ lang('PRIVACY_LINK') }}</span> </a> diff --git a/phpBB/styles/prosilver/template/ucp_remind.html b/phpBB/styles/prosilver/template/ucp_remind.html deleted file mode 100644 index 8b700de430..0000000000 --- a/phpBB/styles/prosilver/template/ucp_remind.html +++ /dev/null @@ -1,37 +0,0 @@ -<!-- INCLUDE overall_header.html --> - -<form action="{S_PROFILE_ACTION}" method="post" id="remind"> - -<div class="panel"> - <div class="inner"> - - <div class="content"> - <h2>{L_SEND_PASSWORD}</h2> - - <fieldset> - {% if USERNAME_REQUIRED %} - <p class="error">{{ lang('EMAIL_NOT_UNIQUE') }}</p> - {% endif %} - <dl> - <dt><label for="email">{L_EMAIL_ADDRESS}{L_COLON}</label><br /><span>{L_EMAIL_REMIND}</span></dt> - <dd><input class="inputbox narrow" type="email" name="email" id="email" size="25" maxlength="100" value="{{ EMAIL }}" autofocus /></dd> - </dl> - {% if USERNAME_REQUIRED %} - <dl> - <dt><label for="username">{L_USERNAME}{L_COLON}</label></dt> - <dd><input class="inputbox narrow" type="text" name="username" id="username" size="25" /></dd> - </dl> - {% endif %} - <dl> - <dt> </dt> - <dd>{S_HIDDEN_FIELDS}<input type="submit" name="submit" id="submit" class="button1" value="{L_SUBMIT}" tabindex="2" /> <input type="reset" value="{L_RESET}" name="reset" class="button2" /></dd> - </dl> - {S_FORM_TOKEN} - </fieldset> - </div> - - </div> -</div> -</form> - -<!-- INCLUDE overall_footer.html --> diff --git a/phpBB/styles/prosilver/template/ucp_reset_password.html b/phpBB/styles/prosilver/template/ucp_reset_password.html new file mode 100644 index 0000000000..0a05f69aed --- /dev/null +++ b/phpBB/styles/prosilver/template/ucp_reset_password.html @@ -0,0 +1,49 @@ +<!-- INCLUDE overall_header.html --> + +<form action="{{ U_RESET_PASSWORD_ACTION }}" method="post" id="reset_password"> + +<div class="panel"> + <div class="inner"> + + <div class="content"> + <h2>{{ lang('RESET_PASSWORD') }}</h2> + + <fieldset> + {% if S_IS_PASSWORD_RESET %} + {% if PASSWORD_RESET_ERRORS %}<p class="error">{{ PASSWORD_RESET_ERRORS | join('<br>') }}</p>{% endif %} + <dl> + <dt><label for="new_password">{{ lang('NEW_PASSWORD') ~ lang('COLON') }}</label></dt> + <dd><input type="password" name="new_password" id="new_password" size="25" maxlength="255" title="{{ lang('CHANGE_PASSWORD') }}" autocomplete="off" /></dd> + </dl> + <dl> + <dt><label for="new_password_confirm">{{ lang('CONFIRM_PASSWORD') ~ lang('COLON') }}</label></dt> + <dd><input type="password" name="new_password_confirm" id="new_password_confirm" size="25" maxlength="255" title="{{ lang('CONFIRM_PASSWORD') }}" autocomplete="off" /></dd> + </dl> + {% else %} + {% if USERNAME_REQUIRED %} + <p class="error">{{ lang('EMAIL_NOT_UNIQUE') }}</p> + {% endif %} + <dl> + <dt><label for="email">{{ lang('EMAIL_ADDRESS') ~ lang('COLON') }}</label><br /><span>{{ lang('EMAIL_REMIND') }}</span></dt> + <dd><input class="inputbox narrow" type="email" name="email" id="email" size="25" maxlength="100" value="{{ EMAIL }}" autofocus /></dd> + </dl> + {% if USERNAME_REQUIRED %} + <dl> + <dt><label for="username">{{ lang('USERNAME') ~ lang('COLON') }}</label></dt> + <dd><input class="inputbox narrow" type="text" name="username" id="username" size="25" /></dd> + </dl> + {% endif %} + {% endif %} + <dl> + <dt> </dt> + <dd>{{ S_HIDDEN_FIELDS }}<input type="submit" name="submit" id="submit" class="button1" value="{{ lang('SUBMIT') }}" tabindex="2" /> <input type="reset" value="{{ lang('RESET') }}" name="reset" class="button2" /></dd> + </dl> + {{ S_FORM_TOKEN }} + </fieldset> + </div> + + </div> +</div> +</form> + +<!-- INCLUDE overall_footer.html --> diff --git a/phpBB/ucp.php b/phpBB/ucp.php index c60d9930fc..0992e3ef90 100644 --- a/phpBB/ucp.php +++ b/phpBB/ucp.php @@ -63,8 +63,10 @@ switch ($mode) break; case 'sendpassword': - $module->load('ucp', 'remind'); - $module->display($user->lang['UCP_REMIND']); + /** @var \phpbb\controller\helper $controller_helper */ + $controller_helper = $phpbb_container->get('controller.helper'); + + redirect($controller_helper->route('phpbb_ucp_forgot_password_controller')); break; case 'register': diff --git a/tests/RUNNING_TESTS.md b/tests/RUNNING_TESTS.md index 56f2818078..516541151c 100644 --- a/tests/RUNNING_TESTS.md +++ b/tests/RUNNING_TESTS.md @@ -30,11 +30,9 @@ Some of the functionality in phpBB and/or the test suite uses additional PHP extensions. If these extensions are not loaded, respective tests will be skipped: -- apc (APC cache driver, php5 only) - apcu (APCu cache driver - native API, php7+) - apcu_bc, apcu (APCu cache driver - APC API, php7+) - bz2 (compress tests) -- mysql, pdo_mysql (MySQL database driver) - mysqli, pdo_mysql (MySQLi database driver) - pcntl (flock class) - pdo (any database tests) diff --git a/tests/auth/provider_apache_test.php b/tests/auth/provider_apache_test.php index 0c26a0a186..58d6354228 100644 --- a/tests/auth/provider_apache_test.php +++ b/tests/auth/provider_apache_test.php @@ -202,6 +202,8 @@ class phpbb_auth_provider_apache_test extends phpbb_database_test_case 'user_new' => '1', 'user_reminded' => '0', 'user_reminded_time' => '0', + 'reset_token' => '', + 'reset_token_expiration' => '0', ); $this->assertEquals($expected, $this->provider->autologin()); diff --git a/tests/cache/apc_driver_test.php b/tests/cache/apc_driver_test.php deleted file mode 100644 index 276cbeb3e1..0000000000 --- a/tests/cache/apc_driver_test.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -// Important: apc.enable_cli=1 must be in php.ini. -// http://forums.devshed.com/php-development-5/apc-problem-561290.html -// http://php.net/manual/en/apc.configuration.php - -require_once dirname(__FILE__) . '/common_test_case.php'; - -class phpbb_cache_apc_driver_test extends phpbb_cache_common_test_case -{ - protected static $config; - - public function getDataSet() - { - return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/config.xml'); - } - - static public function setUpBeforeClass() - { - if (!extension_loaded('apc')) - { - self::markTestSkipped('APC extension is not loaded'); - } - - $php_ini = new \bantu\IniGetWrapper\IniGetWrapper; - - if (!$php_ini->getBool('apc.enabled')) - { - self::markTestSkipped('APC is not enabled. Make sure apc.enabled=1 in php.ini'); - } - - if (PHP_SAPI == 'cli' && !$php_ini->getBool('apc.enable_cli')) - { - self::markTestSkipped('APC is not enabled for CLI. Set apc.enable_cli=1 in php.ini'); - } - } - - protected function setUp(): void - { - parent::setUp(); - - $this->driver = new \phpbb\cache\driver\apc; - $this->driver->purge(); - } -} diff --git a/tests/console/user/base.php b/tests/console/user/base.php index 94a51eb896..b845ab1639 100644 --- a/tests/console/user/base.php +++ b/tests/console/user/base.php @@ -51,7 +51,6 @@ abstract class phpbb_console_user_base extends phpbb_database_test_case 'min_name_chars' => 3, 'max_name_chars' => 10, 'min_pass_chars' => 3, - 'max_pass_chars' => 10, 'pass_complex' => 'PASS_TYPE_ANY', )); diff --git a/tests/functional/forgot_password_test.php b/tests/functional/forgot_password_test.php index 2fd5b45f7d..10946fe5a9 100644 --- a/tests/functional/forgot_password_test.php +++ b/tests/functional/forgot_password_test.php @@ -20,8 +20,8 @@ class phpbb_functional_forgot_password_test extends phpbb_functional_test_case { global $config; $this->add_lang('ucp'); - $crawler = self::request('GET', 'ucp.php?mode=sendpassword'); - $this->assertEquals($this->lang('SEND_PASSWORD'), $crawler->filter('h2')->text()); + $crawler = self::request('GET', 'app.php/user/forgot_password'); + $this->assertEquals($this->lang('RESET_PASSWORD'), $crawler->filter('h2')->text()); } public function test_forgot_password_disabled() @@ -40,7 +40,7 @@ class phpbb_functional_forgot_password_test extends phpbb_functional_test_case $this->logout(); - $crawler = self::request('GET', 'ucp.php?mode=sendpassword'); + $crawler = self::request('GET', 'app.php/user/forgot_password'); $this->assertContains($this->lang('UCP_PASSWORD_RESET_DISABLED', '', ''), $crawler->text()); } diff --git a/tests/functional/user_password_reset_test.php b/tests/functional/user_password_reset_test.php index 2361eed066..a97300b9ee 100644 --- a/tests/functional/user_password_reset_test.php +++ b/tests/functional/user_password_reset_test.php @@ -25,36 +25,53 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca // test without email $crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}"); + $this->assertContains('app.php/user/forgot_password', $crawler->getUri()); $form = $crawler->selectButton('submit')->form(); $crawler = self::submit($form); $this->assertContainsLang('NO_EMAIL_USER', $crawler->text()); // test with non-existent email - $crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}"); + $crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}"); $form = $crawler->selectButton('submit')->form(array( 'email' => 'non-existent@email.com', )); $crawler = self::submit($form); - $this->assertContainsLang('PASSWORD_UPDATED_IF_EXISTED', $crawler->text()); + $this->assertContainsLang('PASSWORD_RESET_LINK_SENT', $crawler->text()); // test with correct email - $crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}"); + $crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}"); $form = $crawler->selectButton('submit')->form(array( 'email' => 'reset-password-test-user@test.com', )); $crawler = self::submit($form); - $this->assertContainsLang('PASSWORD_UPDATED_IF_EXISTED', $crawler->text()); + $this->assertContainsLang('PASSWORD_RESET_LINK_SENT', $crawler->text()); // Check if columns in database were updated for password reset $this->get_user_data('reset-password-test-user'); - $this->assertNotNull($this->user_data['user_actkey']); - $this->assertNotNull($this->user_data['user_newpasswd']); + $this->assertNotEmpty($this->user_data['reset_token']); + $this->assertNotEmpty($this->user_data['reset_token_expiration']); + $reset_token = $this->user_data['reset_token']; + $reset_token_expiration = $this->user_data['reset_token_expiration']; + + // Check that reset token is only created once per day + $crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}"); + $form = $crawler->selectButton('submit')->form(array( + 'email' => 'reset-password-test-user@test.com', + )); + $crawler = self::submit($form); + $this->assertContainsLang('PASSWORD_RESET_LINK_SENT', $crawler->text()); + + $this->get_user_data('reset-password-test-user'); + $this->assertNotEmpty($this->user_data['reset_token']); + $this->assertNotEmpty($this->user_data['reset_token_expiration']); + $this->assertEquals($reset_token, $this->user_data['reset_token']); + $this->assertEquals($reset_token_expiration, $this->user_data['reset_token_expiration']); // Create another user with the same email $this->create_user('reset-password-test-user1', 'reset-password-test-user@test.com'); // Test that username is now also required - $crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}"); + $crawler = self::request('GET', "app.php/user/forgot_password?sid={$this->sid}"); $form = $crawler->selectButton('submit')->form(array( 'email' => 'reset-password-test-user@test.com', )); @@ -67,20 +84,13 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca 'username' => 'reset-password-test-user1', )); $crawler = self::submit($form); - $this->assertContainsLang('PASSWORD_UPDATED_IF_EXISTED', $crawler->text()); + $this->assertContainsLang('PASSWORD_RESET_LINK_SENT', $crawler->text()); // Check if columns in database were updated for password reset $this->get_user_data('reset-password-test-user1'); - $this->assertNotNull($this->user_data['user_actkey']); - $this->assertNotNull($this->user_data['user_newpasswd']); - - // Make sure we know the password - $db = $this->get_db(); - $this->passwords_manager = $this->get_passwords_manager(); - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_newpasswd = '" . $db->sql_escape($this->passwords_manager->hash('reset-password-test-user')) . "' - WHERE user_id = " . $user_id; - $db->sql_query($sql); + $this->assertNotEmpty($this->user_data['reset_token']); + $this->assertNotEmpty($this->user_data['reset_token_expiration']); + $this->assertGreaterThan(time(), $this->user_data['reset_token_expiration']); } public function test_login_after_reset() @@ -88,28 +98,45 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca $this->login('reset-password-test-user'); } - public function data_activate_new_password() + public function data_reset_user_password() { - return array( - array('WRONG_ACTIVATION', false, 'FOOBAR'), - array('ALREADY_ACTIVATED', 2, 'FOOBAR'), - array('PASSWORD_ACTIVATED', false, false), - array('ALREADY_ACTIVATED', false, false), - ); + return [ + ['RESET_TOKEN_EXPIRED_OR_INVALID', 0, 'abcdef'], + ['NO_USER', ' ', 'abcdef'], + ['NO_RESET_TOKEN', 0, ' '], + ['RESET_TOKEN_EXPIRED_OR_INVALID', 2, ''], + ['RESET_TOKEN_EXPIRED_OR_INVALID', 1e7, ''], + ['', 0, ''], + ['NO_RESET_TOKEN', 0, ''], // already reset + ]; } /** - * @dataProvider data_activate_new_password - */ - public function test_activate_new_password($expected, $user_id, $act_key) + * @dataProvider data_reset_user_password + */ + public function test_reset_user_password($expected, $user_id, $token) { $this->add_lang('ucp'); $this->get_user_data('reset-password-test-user'); - $user_id = (!$user_id) ? $this->user_data['user_id'] : $user_id; - $act_key = (!$act_key) ? $this->user_data['user_actkey'] : $act_key; + $user_id = !$user_id ? $this->user_data['user_id'] : $user_id; + $token = !$token ? $this->user_data['reset_token'] : $token; + + $crawler = self::request('GET', "app.php/user/reset_password?u=$user_id&token=$token"); - $crawler = self::request('GET', "ucp.php?mode=activate&u=$user_id&k=$act_key&sid={$this->sid}"); - $this->assertContainsLang($expected, $crawler->text()); + if ($expected) + { + $this->assertContainsLang($expected, $crawler->text()); + } + else + { + $form = $crawler->filter('input[type=submit]')->form(); + $values = array_merge($form->getValues(), [ + 'new_password' => 'reset-password-test-user', + 'new_password_confirm' => 'reset-password-test-user', + ]); + $crawler = self::submit($form, $values); + $this->assertContainsLang('PASSWORD_RESET', $crawler->text()); + } } public function test_login() @@ -190,7 +217,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca protected function get_user_data($username) { $db = $this->get_db(); - $sql = 'SELECT user_id, username, user_type, user_email, user_newpasswd, user_lang, user_notify_type, user_actkey, user_inactive_reason + $sql = 'SELECT user_id, username, user_type, user_email, user_newpasswd, user_lang, user_notify_type, user_actkey, user_inactive_reason, reset_token, reset_token_expiration FROM ' . USERS_TABLE . " WHERE username = '" . $db->sql_escape($username) . "'"; $result = $db->sql_query($sql); diff --git a/tests/functions/convert_30_dbms_to_31_test.php b/tests/functions/convert_30_dbms_to_31_test.php index 456eb64461..05c42610bb 100644 --- a/tests/functions/convert_30_dbms_to_31_test.php +++ b/tests/functions/convert_30_dbms_to_31_test.php @@ -18,7 +18,6 @@ class phpbb_convert_30_dbms_to_31_test extends phpbb_test_case return array( array('mssql_odbc'), array('mssqlnative'), - array('mysql'), array('mysqli'), array('oracle'), array('postgres'), diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index f3adbefc1b..fec4709fbd 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -150,7 +150,6 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { - case 'phpbb\db\driver\mysql': case 'phpbb\db\driver\mysqli': $this->pdo->exec('SET NAMES utf8'); @@ -270,7 +269,6 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { - case 'phpbb\db\driver\mysql': case 'phpbb\db\driver\mysqli': $sql = 'SHOW TABLES'; break; @@ -336,14 +334,7 @@ class phpbb_database_test_connection_manager $sth = $this->pdo->query('SELECT VERSION() AS version'); $row = $sth->fetch(PDO::FETCH_ASSOC); - if (version_compare($row['version'], '4.1.3', '>=')) - { - $schema .= '_41'; - } - else - { - $schema .= '_40'; - } + $schema .= '_41'; } $filename = $directory . $schema . '_schema.sql'; @@ -424,11 +415,6 @@ class phpbb_database_test_connection_manager 'DELIM' => ';', 'PDO' => 'mysql', ), - 'phpbb\db\driver\mysql' => array( - 'SCHEMA' => 'mysql', - 'DELIM' => ';', - 'PDO' => 'mysql', - ), 'phpbb\db\driver\mssql' => array( 'SCHEMA' => 'mssql', 'DELIM' => 'GO', diff --git a/travis/setup-database.sh b/travis/setup-database.sh index cbd5e93e83..b581ddfccb 100755 --- a/travis/setup-database.sh +++ b/travis/setup-database.sh @@ -31,7 +31,7 @@ then mysql -e 'SET GLOBAL storage_engine=MyISAM;' fi -if [ "$DB" == "mysql" -o "$DB" == "mysqli" -o "$DB" == "mariadb" ] +if [ "$DB" == "mysqli" -o "$DB" == "mariadb" ] then mysql -e 'create database IF NOT EXISTS phpbb_tests;' fi |