diff options
Diffstat (limited to 'phpBB/phpbb')
140 files changed, 3482 insertions, 2610 deletions
diff --git a/phpBB/phpbb/auth/provider/apache.php b/phpBB/phpbb/auth/provider/apache.php index aa5bf64335..a713674657 100644 --- a/phpBB/phpbb/auth/provider/apache.php +++ b/phpBB/phpbb/auth/provider/apache.php @@ -13,34 +13,55 @@ namespace phpbb\auth\provider; +use phpbb\config\config; +use phpbb\db\driver\driver_interface; +use phpbb\language\language; +use phpbb\request\request_interface; +use phpbb\request\type_cast_helper; +use phpbb\user; + /** * Apache authentication provider for phpBB3 */ -class apache extends \phpbb\auth\provider\base +class apache extends base { - /** - * phpBB passwords manager - * - * @var \phpbb\passwords\manager - */ - protected $passwords_manager; + /** @var config phpBB config */ + protected $config; + + /** @var driver_interface Database object */ + protected $db; + + /** @var language Language object */ + protected $language; + + /** @var request_interface Request object */ + protected $request; + + /** @var user User object */ + protected $user; + + /** @var string Relative path to phpBB root */ + protected $phpbb_root_path; + + /** @var string PHP file extension */ + protected $php_ext; /** * Apache Authentication Constructor * - * @param \phpbb\db\driver\driver_interface $db Database object - * @param \phpbb\config\config $config Config object - * @param \phpbb\passwords\manager $passwords_manager Passwords Manager object - * @param \phpbb\request\request $request Request object - * @param \phpbb\user $user User object + * @param config $config Config object + * @param driver_interface $db Database object + * @param language $language Language object + * @param request_interface $request Request object + * @param user $user User object * @param string $phpbb_root_path Relative path to phpBB root * @param string $php_ext PHP file extension */ - public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request $request, \phpbb\user $user, $phpbb_root_path, $php_ext) + public function __construct(config $config, driver_interface $db, language $language, request_interface $request, user $user, $phpbb_root_path, $php_ext) { - $this->db = $db; $this->config = $config; - $this->passwords_manager = $passwords_manager; + $this->db = $db; + $this->language = $language; $this->request = $request; $this->user = $user; $this->phpbb_root_path = $phpbb_root_path; @@ -52,9 +73,9 @@ class apache extends \phpbb\auth\provider\base */ public function init() { - if (!$this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER) || $this->user->data['username'] !== htmlspecialchars_decode($this->request->server('PHP_AUTH_USER'))) + if (!$this->request->is_set('PHP_AUTH_USER', request_interface::SERVER) || $this->user->data['username'] !== htmlspecialchars_decode($this->request->server('PHP_AUTH_USER'))) { - return $this->user->lang['APACHE_SETUP_BEFORE_USE']; + return $this->language->lang('APACHE_SETUP_BEFORE_USE'); } return false; } @@ -83,7 +104,7 @@ class apache extends \phpbb\auth\provider\base ); } - if (!$this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER)) + if (!$this->request->is_set('PHP_AUTH_USER', request_interface::SERVER)) { return array( 'status' => LOGIN_ERROR_EXTERNAL_AUTH, @@ -137,7 +158,7 @@ class apache extends \phpbb\auth\provider\base return array( 'status' => LOGIN_SUCCESS_CREATE_PROFILE, 'error_msg' => false, - 'user_row' => $this->user_row($php_auth_user, $php_auth_pw), + 'user_row' => $this->user_row($php_auth_user), ); } @@ -154,7 +175,7 @@ class apache extends \phpbb\auth\provider\base */ public function autologin() { - if (!$this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER)) + if (!$this->request->is_set('PHP_AUTH_USER', request_interface::SERVER)) { return array(); } @@ -164,8 +185,8 @@ class apache extends \phpbb\auth\provider\base if (!empty($php_auth_user) && !empty($php_auth_pw)) { - set_var($php_auth_user, $php_auth_user, 'string', true); - set_var($php_auth_pw, $php_auth_pw, 'string', true); + $type_cast_helper = new type_cast_helper(); + $type_cast_helper->set_var($php_auth_user, $php_auth_user, 'string', true); $sql = 'SELECT * FROM ' . USERS_TABLE . " @@ -185,7 +206,7 @@ class apache extends \phpbb\auth\provider\base } // create the user if he does not exist yet - user_add($this->user_row($php_auth_user, $php_auth_pw)); + user_add($this->user_row($php_auth_user)); $sql = 'SELECT * FROM ' . USERS_TABLE . " @@ -208,11 +229,11 @@ class apache extends \phpbb\auth\provider\base * function in order to create a user * * @param string $username The username of the new user. - * @param string $password The password of the new user. + * * @return array Contains data that can be passed directly to * the user_add function. */ - private function user_row($username, $password) + private function user_row($username) { // first retrieve default group id $sql = 'SELECT group_id @@ -231,7 +252,7 @@ class apache extends \phpbb\auth\provider\base // generate user account data return array( 'username' => $username, - 'user_password' => $this->passwords_manager->hash($password), + 'user_password' => '', 'user_email' => '', 'group_id' => (int) $row['group_id'], 'user_type' => USER_NORMAL, @@ -246,7 +267,7 @@ class apache extends \phpbb\auth\provider\base public function validate_session($user) { // Check if PHP_AUTH_USER is set and handle this case - if ($this->request->is_set('PHP_AUTH_USER', \phpbb\request\request_interface::SERVER)) + if ($this->request->is_set('PHP_AUTH_USER', request_interface::SERVER)) { $php_auth_user = $this->request->server('PHP_AUTH_USER'); diff --git a/phpBB/phpbb/auth/provider/base.php b/phpBB/phpbb/auth/provider/base.php index dea27ccc25..30e0a0fe2d 100644 --- a/phpBB/phpbb/auth/provider/base.php +++ b/phpBB/phpbb/auth/provider/base.php @@ -16,7 +16,7 @@ namespace phpbb\auth\provider; /** * Base authentication provider class that all other providers should implement */ -abstract class base implements \phpbb\auth\provider\provider_interface +abstract class base implements provider_interface { /** * {@inheritdoc} diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php index 1adf85ee05..a70734fcbe 100644 --- a/phpBB/phpbb/auth/provider/db.php +++ b/phpBB/phpbb/auth/provider/db.php @@ -13,48 +13,69 @@ namespace phpbb\auth\provider; +use phpbb\captcha\factory; +use phpbb\config\config; +use phpbb\db\driver\driver_interface; +use phpbb\passwords\manager; +use phpbb\request\request_interface; +use phpbb\user; + /** * Database authentication provider for phpBB3 * This is for authentication via the integrated user table */ -class db extends \phpbb\auth\provider\base +class db extends base { + /** @var factory CAPTCHA factory */ + protected $captcha_factory; + + /** @var config phpBB config */ + protected $config; + + /** @var driver_interface DBAL driver instance */ + protected $db; + + /** @var request_interface Request object */ + protected $request; + + /** @var user User object */ + protected $user; + + /** @var string phpBB root path */ + protected $phpbb_root_path; + + /** @var string PHP file extension */ + protected $php_ext; + /** * phpBB passwords manager * - * @var \phpbb\passwords\manager + * @var manager */ protected $passwords_manager; /** - * DI container - * - * @var \Symfony\Component\DependencyInjection\ContainerInterface - */ - protected $phpbb_container; - - /** * Database Authentication Constructor * - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\config\config $config - * @param \phpbb\passwords\manager $passwords_manager - * @param \phpbb\request\request $request - * @param \phpbb\user $user - * @param \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container + * @param factory $captcha_factory + * @param config $config + * @param driver_interface $db + * @param manager $passwords_manager + * @param request_interface $request + * @param user $user * @param string $phpbb_root_path * @param string $php_ext */ - public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request $request, \phpbb\user $user, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, $phpbb_root_path, $php_ext) + public function __construct(factory $captcha_factory, config $config, driver_interface $db, manager $passwords_manager, request_interface $request, user $user, $phpbb_root_path, $php_ext) { - $this->db = $db; + $this->captcha_factory = $captcha_factory; $this->config = $config; + $this->db = $db; $this->passwords_manager = $passwords_manager; $this->request = $request; $this->user = $user; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; - $this->phpbb_container = $phpbb_container; } /** @@ -155,9 +176,7 @@ class db extends \phpbb\auth\provider\base // Every auth module is able to define what to do by itself... if ($show_captcha) { - /* @var $captcha_factory \phpbb\captcha\factory */ - $captcha_factory = $this->phpbb_container->get('captcha.factory'); - $captcha = $captcha_factory->get_instance($this->config['captcha_plugin']); + $captcha = $this->captcha_factory->get_instance($this->config['captcha_plugin']); $captcha->init(CONFIRM_LOGIN); $vc_response = $captcha->validate($row); if ($vc_response) diff --git a/phpBB/phpbb/auth/provider/ldap.php b/phpBB/phpbb/auth/provider/ldap.php index 0789a6234d..43699f7d6e 100644 --- a/phpBB/phpbb/auth/provider/ldap.php +++ b/phpBB/phpbb/auth/provider/ldap.php @@ -1,4 +1,5 @@ <?php + /** * * This file is part of the phpBB Forum Software package. @@ -13,32 +14,42 @@ namespace phpbb\auth\provider; +use phpbb\config\config; +use phpbb\db\driver\driver_interface; +use phpbb\language\language; +use phpbb\user; + /** * Database authentication provider for phpBB3 * This is for authentication via the integrated user table */ -class ldap extends \phpbb\auth\provider\base +class ldap extends base { - /** - * phpBB passwords manager - * - * @var \phpbb\passwords\manager - */ - protected $passwords_manager; + /** @var config phpBB config */ + protected $config; + + /** @var driver_interface DBAL driver interface */ + protected $db; + + /** @var language phpBB language class */ + protected $language; + + /** @var user phpBB user */ + protected $user; /** * LDAP Authentication Constructor * - * @param \phpbb\db\driver\driver_interface $db Database object - * @param \phpbb\config\config $config Config object - * @param \phpbb\passwords\manager $passwords_manager Passwords manager object - * @param \phpbb\user $user User object + * @param config $config Config object + * @param driver_interface $db DBAL driver interface + * @param language $language Language object + * @param user $user User object */ - public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\user $user) + public function __construct(config $config, driver_interface $db, language $language, user $user) { - $this->db = $db; $this->config = $config; - $this->passwords_manager = $passwords_manager; + $this->db = $db; + $this->language = $language; $this->user = $user; } @@ -49,7 +60,7 @@ class ldap extends \phpbb\auth\provider\base { if (!@extension_loaded('ldap')) { - return $this->user->lang['LDAP_NO_LDAP_EXTENSION']; + return $this->language->lang('LDAP_NO_LDAP_EXTENSION'); } $this->config['ldap_port'] = (int) $this->config['ldap_port']; @@ -64,7 +75,7 @@ class ldap extends \phpbb\auth\provider\base if (!$ldap) { - return $this->user->lang['LDAP_NO_SERVER_CONNECTION']; + return $this->language->lang('LDAP_NO_SERVER_CONNECTION'); } @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); @@ -74,7 +85,7 @@ class ldap extends \phpbb\auth\provider\base { if (!@ldap_bind($ldap, htmlspecialchars_decode($this->config['ldap_user']), htmlspecialchars_decode($this->config['ldap_password']))) { - return $this->user->lang['LDAP_INCORRECT_USER_PASSWORD']; + return $this->language->lang('LDAP_INCORRECT_USER_PASSWORD'); } } @@ -92,7 +103,7 @@ class ldap extends \phpbb\auth\provider\base if ($search === false) { - return $this->user->lang['LDAP_SEARCH_FAILED']; + return $this->language->lang('LDAP_SEARCH_FAILED'); } $result = @ldap_get_entries($ldap, $search); @@ -101,12 +112,12 @@ class ldap extends \phpbb\auth\provider\base if (!is_array($result) || count($result) < 2) { - return sprintf($this->user->lang['LDAP_NO_IDENTITY'], $this->user->data['username']); + return $this->language->lang('LDAP_NO_IDENTITY', $this->user->data['username']); } if (!empty($this->config['ldap_email']) && !isset($result[0][htmlspecialchars_decode($this->config['ldap_email'])])) { - return $this->user->lang['LDAP_NO_EMAIL']; + return $this->language->lang('LDAP_NO_EMAIL'); } return false; @@ -245,7 +256,7 @@ class ldap extends \phpbb\auth\provider\base // generate user account data $ldap_user_row = array( 'username' => $username, - 'user_password' => $this->passwords_manager->hash($password), + 'user_password' => '', 'user_email' => (!empty($this->config['ldap_email'])) ? utf8_htmlspecialchars($ldap_result[0][htmlspecialchars_decode($this->config['ldap_email'])][0]) : '', 'group_id' => (int) $row['group_id'], 'user_type' => USER_NORMAL, diff --git a/phpBB/phpbb/auth/provider/oauth/oauth.php b/phpBB/phpbb/auth/provider/oauth/oauth.php index e3f8394bba..29ffe6d591 100644 --- a/phpBB/phpbb/auth/provider/oauth/oauth.php +++ b/phpBB/phpbb/auth/provider/oauth/oauth.php @@ -1,169 +1,137 @@ <?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 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\auth\provider\oauth; +use OAuth\Common\Http\Exception\TokenResponseException; +use OAuth\ServiceFactory; use OAuth\Common\Consumer\Credentials; +use OAuth\Common\Service\ServiceInterface; +use OAuth\OAuth1\Service\AbstractService as OAuth1Service; +use OAuth\OAuth2\Service\AbstractService as OAuth2Service; +use phpbb\auth\provider\base; +use phpbb\auth\provider\db; +use phpbb\auth\provider\oauth\service\exception; +use phpbb\config\config; +use phpbb\db\driver\driver_interface; +use phpbb\di\service_collection; +use phpbb\event\dispatcher; +use phpbb\language\language; +use phpbb\request\request_interface; +use phpbb\user; /** -* OAuth authentication provider for phpBB3 -*/ -class oauth extends \phpbb\auth\provider\base + * OAuth authentication provider for phpBB3 + */ +class oauth extends base { - /** - * Database driver - * - * @var \phpbb\db\driver\driver_interface - */ - protected $db; - - /** - * phpBB config - * - * @var \phpbb\config\config - */ + /** @var config */ protected $config; - /** - * phpBB passwords manager - * - * @var \phpbb\passwords\manager - */ - protected $passwords_manager; - - /** - * phpBB request object - * - * @var \phpbb\request\request_interface - */ - protected $request; + /** @var driver_interface */ + protected $db; - /** - * phpBB user - * - * @var \phpbb\user - */ - protected $user; + /** @var db */ + protected $db_auth; - /** - * OAuth token table - * - * @var string - */ - protected $auth_provider_oauth_token_storage_table; + /** @var dispatcher */ + protected $dispatcher; - /** - * OAuth state table - * - * @var string - */ - protected $auth_provider_oauth_state_table; + /** @var language */ + protected $language; - /** - * OAuth account association table - * - * @var string - */ - protected $auth_provider_oauth_token_account_assoc; + /** @var request_interface */ + protected $request; - /** - * All OAuth service providers - * - * @var \phpbb\di\service_collection Contains \phpbb\auth\provider\oauth\service_interface - */ + /** @var service_collection */ protected $service_providers; - /** - * Users table - * - * @var string - */ - protected $users_table; + /** @var user */ + protected $user; - /** - * Cached current uri object - * - * @var \OAuth\Common\Http\Uri\UriInterface|null - */ - protected $current_uri; + /** @var string OAuth table: token storage */ + protected $oauth_token_table; - /** - * DI container - * - * @var \Symfony\Component\DependencyInjection\ContainerInterface - */ - protected $phpbb_container; + /** @var string OAuth table: state */ + protected $oauth_state_table; - /** - * phpBB event dispatcher - * - * @var \phpbb\event\dispatcher_interface - */ - protected $dispatcher; + /** @var string OAuth table: account association */ + protected $oauth_account_table; - /** - * phpBB root path - * - * @var string - */ - protected $phpbb_root_path; + /** @var string Users table */ + protected $users_table; - /** - * PHP file extension - * - * @var string - */ + /** @var string phpBB root path */ + protected $root_path; + + /** @var string php File extension */ protected $php_ext; /** - * OAuth Authentication Constructor - * - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\config\config $config - * @param \phpbb\passwords\manager $passwords_manager - * @param \phpbb\request\request_interface $request - * @param \phpbb\user $user - * @param string $auth_provider_oauth_token_storage_table - * @param string $auth_provider_oauth_state_table - * @param string $auth_provider_oauth_token_account_assoc - * @param \phpbb\di\service_collection $service_providers Contains \phpbb\auth\provider\oauth\service_interface - * @param string $users_table - * @param \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container - * @param \phpbb\event\dispatcher_interface $dispatcher phpBB event dispatcher - * @param string $phpbb_root_path - * @param string $php_ext - */ - public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request_interface $request, \phpbb\user $user, $auth_provider_oauth_token_storage_table, $auth_provider_oauth_state_table, $auth_provider_oauth_token_account_assoc, \phpbb\di\service_collection $service_providers, $users_table, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, \phpbb\event\dispatcher_interface $dispatcher, $phpbb_root_path, $php_ext) + * Constructor. + * + * @param config $config Config object + * @param driver_interface $db Database object + * @param db $db_auth DB auth provider + * @param dispatcher $dispatcher Event dispatcher object + * @param language $language Language object + * @param request_interface $request Request object + * @param service_collection $service_providers OAuth providers service collection + * @param user $user User object + * @param string $oauth_token_table OAuth table: token storage + * @param string $oauth_state_table OAuth table: state + * @param string $oauth_account_table OAuth table: account association + * @param string $users_table User table + * @param string $root_path phpBB root path + * @param string $php_ext php File extension + */ + public function __construct( + config $config, + driver_interface $db, + db $db_auth, + dispatcher $dispatcher, + language $language, + request_interface $request, + service_collection $service_providers, + user $user, + $oauth_token_table, + $oauth_state_table, + $oauth_account_table, + $users_table, + $root_path, + $php_ext + ) { - $this->db = $db; - $this->config = $config; - $this->passwords_manager = $passwords_manager; - $this->request = $request; - $this->user = $user; - $this->auth_provider_oauth_token_storage_table = $auth_provider_oauth_token_storage_table; - $this->auth_provider_oauth_state_table = $auth_provider_oauth_state_table; - $this->auth_provider_oauth_token_account_assoc = $auth_provider_oauth_token_account_assoc; - $this->service_providers = $service_providers; - $this->users_table = $users_table; - $this->phpbb_container = $phpbb_container; - $this->dispatcher = $dispatcher; - $this->phpbb_root_path = $phpbb_root_path; - $this->php_ext = $php_ext; + $this->config = $config; + $this->db = $db; + $this->db_auth = $db_auth; + $this->dispatcher = $dispatcher; + $this->language = $language; + $this->service_providers = $service_providers; + $this->request = $request; + $this->user = $user; + + $this->oauth_token_table = $oauth_token_table; + $this->oauth_state_table = $oauth_state_table; + $this->oauth_account_table = $oauth_account_table; + $this->users_table = $users_table; + $this->root_path = $root_path; + $this->php_ext = $php_ext; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function init() { // This does not test whether or not the key and secret provided are valid. @@ -173,61 +141,85 @@ class oauth extends \phpbb\auth\provider\base if (($credentials['key'] && !$credentials['secret']) || (!$credentials['key'] && $credentials['secret'])) { - return $this->user->lang['AUTH_PROVIDER_OAUTH_ERROR_ELEMENT_MISSING']; + return $this->language->lang('AUTH_PROVIDER_OAUTH_ERROR_ELEMENT_MISSING'); } } + return false; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function login($username, $password) { // Temporary workaround for only having one authentication provider available if (!$this->request->is_set('oauth_service')) { - $provider = new \phpbb\auth\provider\db($this->db, $this->config, $this->passwords_manager, $this->request, $this->user, $this->phpbb_container, $this->phpbb_root_path, $this->php_ext); - return $provider->login($username, $password); + return $this->db_auth->login($username, $password); } // Request the name of the OAuth service - $service_name_original = $this->request->variable('oauth_service', '', false); - $service_name = 'auth.provider.oauth.service.' . strtolower($service_name_original); - if ($service_name_original === '' || !array_key_exists($service_name, $this->service_providers)) + $provider = $this->request->variable('oauth_service', '', false); + $service_name = $this->get_service_name($provider); + + if ($provider === '' || !array_key_exists($service_name, $this->service_providers)) { - return array( + return [ 'status' => LOGIN_ERROR_EXTERNAL_AUTH, 'error_msg' => 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST', - 'user_row' => array('user_id' => ANONYMOUS), - ); + 'user_row' => ['user_id' => ANONYMOUS], + ]; } // Get the service credentials for the given service - $service_credentials = $this->service_providers[$service_name]->get_service_credentials(); + $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); + $query = 'mode=login&login=external&oauth_service=' . $provider; - $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table); - $query = 'mode=login&login=external&oauth_service=' . $service_name_original; - $service = $this->get_service($service_name_original, $storage, $service_credentials, $query, $this->service_providers[$service_name]->get_auth_scope()); + try + { + /** @var OAuth1Service|OAuth2Service $service */ + $service = $this->get_service($provider, $storage, $query); + } + catch (\Exception $e) + { + return [ + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => $e->getMessage(), + 'user_row' => ['user_id' => ANONYMOUS], + ]; + } - if (($service::OAUTH_VERSION === 2 && $this->request->is_set('code', \phpbb\request\request_interface::GET)) - || ($service::OAUTH_VERSION === 1 && $this->request->is_set('oauth_token', \phpbb\request\request_interface::GET))) + if ($this->is_set_code($service)) { $this->service_providers[$service_name]->set_external_service_provider($service); - $unique_id = $this->service_providers[$service_name]->perform_auth_login(); + + try + { + $unique_id = $this->service_providers[$service_name]->perform_auth_login(); + } + catch (exception $e) + { + return [ + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => $e->getMessage(), + 'user_row' => ['user_id' => ANONYMOUS], + ]; + } /** * Check to see if this provider is already associated with an account. * - * Enforcing a data type to make data contains strings and not integers, + * Enforcing a data type to make sure it are strings and not integers, * so values are quoted in the SQL WHERE statement. */ - $data = array( - 'provider' => (string) $service_name_original, + $data = [ + 'provider' => (string) utf8_strtolower($provider), 'oauth_provider_id' => (string) $unique_id - ); + ]; - $sql = 'SELECT user_id FROM ' . $this->auth_provider_oauth_token_account_assoc . ' + $sql = 'SELECT user_id + FROM ' . $this->oauth_account_table . ' WHERE ' . $this->db->sql_build_array('SELECT', $data); $result = $this->db->sql_query($sql); $row = $this->db->sql_fetchrow($result); @@ -235,204 +227,134 @@ class oauth extends \phpbb\auth\provider\base $redirect_data = array( 'auth_provider' => 'oauth', - 'login_link_oauth_service' => $service_name_original, + 'login_link_oauth_service' => $provider, ); /** - * Event is triggered before check if provider is already associated with an account - * - * @event core.oauth_login_after_check_if_provider_id_has_match - * @var array row User row - * @var array data Provider data - * @var array redirect_data Data to be appended to the redirect url - * @var \OAuth\Common\Service\ServiceInterface service OAuth service - * @since 3.2.3-RC1 - * @changed 3.2.6-RC1 Added redirect_data - */ - $vars = array( + * Event is triggered before check if provider is already associated with an account + * + * @event core.oauth_login_after_check_if_provider_id_has_match + * @var array row User row + * @var array data Provider data + * @var array redirect_data Data to be appended to the redirect url + * @var ServiceInterface service OAuth service + * @since 3.2.3-RC1 + * @changed 3.2.6-RC1 Added redirect_data + */ + $vars = [ 'row', 'data', 'redirect_data', 'service', - ); + ]; extract($this->dispatcher->trigger_event('core.oauth_login_after_check_if_provider_id_has_match', compact($vars))); if (!$row) { // The user does not yet exist, ask to link or create profile - return array( + return [ 'status' => LOGIN_SUCCESS_LINK_PROFILE, 'error_msg' => 'LOGIN_OAUTH_ACCOUNT_NOT_LINKED', - 'user_row' => array(), + 'user_row' => [], 'redirect_data' => $redirect_data, - ); + ]; } // Retrieve the user's account $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_ip, user_type, user_login_attempts FROM ' . $this->users_table . ' - WHERE user_id = ' . (int) $row['user_id']; + WHERE user_id = ' . (int) $row['user_id']; $result = $this->db->sql_query($sql); $row = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); if (!$row) { - throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY'); + return [ + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => 'AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY', + 'user_row' => ['user_id' => ANONYMOUS], + ]; } /** * Check if the user is banned. - * The fourth parameter, return, has to be true, - * otherwise the OAuth login is still called and - * an uncaught exception is thrown as there is no - * token stored in the database. + * The fourth parameter (return) has to be true, otherwise the OAuth login is still called and + * an uncaught exception is thrown as there is no token stored in the database. */ $ban = $this->user->check_ban($row['user_id'], $row['user_ip'], $row['user_email'], true); + if (!empty($ban)) { $till_date = !empty($ban['ban_end']) ? $this->user->format_date($ban['ban_end']) : ''; $message = !empty($ban['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM'; - $contact_link = phpbb_get_board_contact_link($this->config, $this->phpbb_root_path, $this->php_ext); - $message = $this->user->lang($message, $till_date, '<a href="' . $contact_link . '">', '</a>'); - $message .= !empty($ban['ban_give_reason']) ? '<br /><br />' . $this->user->lang('BOARD_BAN_REASON', $ban['ban_give_reason']) : ''; - $message .= !empty($ban['ban_triggered_by']) ? '<br /><br /><em>' . $this->user->lang('BAN_TRIGGERED_BY_' . strtoupper($ban['ban_triggered_by'])) . '</em>' : ''; + $contact_link = phpbb_get_board_contact_link($this->config, $this->root_path, $this->php_ext); + + $message = $this->language->lang($message, $till_date, '<a href="' . $contact_link . '">', '</a>'); + $message .= !empty($ban['ban_give_reason']) ? '<br /><br />' . $this->language->lang('BOARD_BAN_REASON', $ban['ban_give_reason']) : ''; + $message .= !empty($ban['ban_triggered_by']) ? '<br /><br /><em>' . $this->language->lang('BAN_TRIGGERED_BY_' . utf8_strtoupper($ban['ban_triggered_by'])) . '</em>' : ''; - return array( + return [ 'status' => LOGIN_BREAK, 'error_msg' => $message, 'user_row' => $row, - ); + ]; } // Update token storage to store the user_id $storage->set_user_id($row['user_id']); /** - * Event is triggered after user is successfully logged in via OAuth. - * - * @event core.auth_oauth_login_after - * @var array row User row - * @since 3.1.11-RC1 - */ - $vars = array( + * Event is triggered after user is successfully logged in via OAuth. + * + * @event core.auth_oauth_login_after + * @var array row User row + * @since 3.1.11-RC1 + */ + $vars = [ 'row', - ); + ]; extract($this->dispatcher->trigger_event('core.auth_oauth_login_after', compact($vars))); // The user is now authenticated and can be logged in - return array( + return [ 'status' => LOGIN_SUCCESS, 'error_msg' => false, 'user_row' => $row, - ); + ]; } else { - if ($service::OAUTH_VERSION === 1) - { - $token = $service->requestRequestToken(); - $url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken())); - } - else - { - $url = $service->getAuthorizationUri(); - } - header('Location: ' . $url); - } - } - - /** - * Returns the cached current_uri object or creates and caches it if it is - * not already created. In each case the query string is updated based on - * the $query parameter. - * - * @param string $service_name The name of the service - * @param string $query The query string of the current_uri - * used in redirects - * @return \OAuth\Common\Http\Uri\UriInterface - */ - protected function get_current_uri($service_name, $query) - { - if ($this->current_uri) - { - $this->current_uri->setQuery($query); - return $this->current_uri; - } - - $uri_factory = new \OAuth\Common\Http\Uri\UriFactory(); - $super_globals = $this->request->get_super_global(\phpbb\request\request_interface::SERVER); - if (!empty($super_globals['HTTP_X_FORWARDED_PROTO']) && $super_globals['HTTP_X_FORWARDED_PROTO'] === 'https') - { - $super_globals['HTTPS'] = 'on'; - $super_globals['SERVER_PORT'] = 443; - } - $current_uri = $uri_factory->createFromSuperGlobalArray($super_globals); - $current_uri->setQuery($query); - - $this->current_uri = $current_uri; - return $current_uri; - } - - /** - * Returns a new service object - * - * @param string $service_name The name of the service - * @param \phpbb\auth\provider\oauth\token_storage $storage - * @param array $service_credentials {@see \phpbb\auth\provider\oauth\oauth::get_service_credentials} - * @param string $query The query string of the - * current_uri used in redirection - * @param array $scopes The scope of the request against - * the api. - * @return \OAuth\Common\Service\ServiceInterface - * @throws \Exception - */ - protected function get_service($service_name, \phpbb\auth\provider\oauth\token_storage $storage, array $service_credentials, $query, array $scopes = array()) - { - $current_uri = $this->get_current_uri($service_name, $query); - - // Setup the credentials for the requests - $credentials = new Credentials( - $service_credentials['key'], - $service_credentials['secret'], - $current_uri->getAbsoluteUri() - ); - - $service_factory = new \OAuth\ServiceFactory(); - $service = $service_factory->createService($service_name, $credentials, $storage, $scopes); - - if (!$service) - { - throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_SERVICE_NOT_CREATED'); + return $this->set_redirect($service); } - - return $service; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function get_login_data() { - $login_data = array( + $login_data = [ 'TEMPLATE_FILE' => 'login_body_oauth.html', 'BLOCK_VAR_NAME' => 'oauth', - 'BLOCK_VARS' => array(), - ); + 'BLOCK_VARS' => [], + ]; foreach ($this->service_providers as $service_name => $service_provider) { // Only include data if the credentials are set $credentials = $service_provider->get_service_credentials(); + if ($credentials['key'] && $credentials['secret']) { - $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); - $redirect_url = generate_board_url() . '/ucp.' . $this->php_ext . '?mode=login&login=external&oauth_service=' . $actual_name; - $login_data['BLOCK_VARS'][$service_name] = array( + $provider = $this->get_provider($service_name); + $redirect_url = generate_board_url() . '/ucp.' . $this->php_ext . '?mode=login&login=external&oauth_service=' . $provider; + + $login_data['BLOCK_VARS'][$service_name] = [ 'REDIRECT_URL' => redirect($redirect_url, true), - 'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)], - ); + 'SERVICE_NAME' => $this->get_provider_title($provider), + ]; } } @@ -440,51 +362,55 @@ class oauth extends \phpbb\auth\provider\base } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function acp() { - $ret = array(); + $ret = []; foreach ($this->service_providers as $service_name => $service_provider) { - $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); - $ret[] = 'auth_oauth_' . $actual_name . '_key'; - $ret[] = 'auth_oauth_' . $actual_name . '_secret'; + $provider = $this->get_provider($service_name); + + $provider = utf8_strtolower($provider); + + $ret[] = 'auth_oauth_' . $provider . '_key'; + $ret[] = 'auth_oauth_' . $provider . '_secret'; } return $ret; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function get_acp_template($new_config) { - $ret = array( + $ret = [ 'BLOCK_VAR_NAME' => 'oauth_services', - 'BLOCK_VARS' => array(), + 'BLOCK_VARS' => [], 'TEMPLATE_FILE' => 'auth_provider_oauth.html', - 'TEMPLATE_VARS' => array(), - ); + 'TEMPLATE_VARS' => [], + ]; foreach ($this->service_providers as $service_name => $service_provider) { - $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); - $ret['BLOCK_VARS'][$actual_name] = array( - 'ACTUAL_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)], - 'KEY' => $new_config['auth_oauth_' . $actual_name . '_key'], - 'NAME' => $actual_name, - 'SECRET' => $new_config['auth_oauth_' . $actual_name . '_secret'], - ); + $provider = $this->get_provider($service_name); + + $ret['BLOCK_VARS'][$provider] = [ + 'NAME' => $provider, + 'ACTUAL_NAME' => $this->get_provider_title($provider), + 'KEY' => $new_config['auth_oauth_' . utf8_strtolower($provider) . '_key'], + 'SECRET' => $new_config['auth_oauth_' . utf8_strtolower($provider) . '_secret'], + ]; } return $ret; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function login_link_has_necessary_data($login_link_data) { if (empty($login_link_data)) @@ -502,16 +428,13 @@ class oauth extends \phpbb\auth\provider\base } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function link_account(array $link_data) { // Check for a valid link method (auth_link or login_link) if (!array_key_exists('link_method', $link_data) || - !in_array($link_data['link_method'], array( - 'auth_link', - 'login_link', - ))) + !in_array($link_data['link_method'], ['auth_link', 'login_link'])) { return 'LOGIN_LINK_MISSING_DATA'; } @@ -527,7 +450,8 @@ class oauth extends \phpbb\auth\provider\base } } - $service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']); + $service_name = $this->get_service_name($link_data['oauth_service']); + if (!array_key_exists($service_name, $this->service_providers)) { return 'LOGIN_ERROR_OAUTH_SERVICE_DOES_NOT_EXIST'; @@ -539,21 +463,109 @@ class oauth extends \phpbb\auth\provider\base return $this->link_account_auth_link($link_data, $service_name); case 'login_link': return $this->link_account_login_link($link_data, $service_name); + default: + return 'LOGIN_LINK_MISSING_DATA'; + } + } + + /** + * {@inheritdoc} + */ + public function logout($data, $new_session) + { + // Clear all tokens belonging to the user + $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); + $storage->clearAllTokens(); + + return; + } + + /** + * {@inheritdoc} + */ + public function get_auth_link_data($user_id = 0) + { + $user_ids = []; + $block_vars = []; + + $sql = 'SELECT oauth_provider_id, provider + FROM ' . $this->oauth_account_table . ' + WHERE user_id = ' . ($user_id > 0 ? (int) $user_id : (int) $this->user->data['user_id']); + $result = $this->db->sql_query($sql); + while ($row = $this->db->sql_fetchrow($result)) + { + $user_ids[$row['provider']] = $row['oauth_provider_id']; + } + $this->db->sql_freeresult($result); + + foreach ($this->service_providers as $service_name => $service_provider) + { + // Only include data if the credentials are set + $credentials = $service_provider->get_service_credentials(); + + if ($credentials['key'] && $credentials['secret']) + { + $provider = $this->get_provider($service_name); + + $block_vars[$service_name] = [ + 'SERVICE_NAME' => $this->get_provider_title($provider), + 'UNIQUE_ID' => isset($user_ids[$provider]) ? $user_ids[$provider] : null, + 'HIDDEN_FIELDS' => [ + 'link' => !isset($user_ids[$provider]), + 'oauth_service' => $provider, + ], + ]; + } + } + + return [ + 'BLOCK_VAR_NAME' => 'oauth', + 'BLOCK_VARS' => $block_vars, + + 'TEMPLATE_FILE' => 'ucp_auth_link_oauth.html', + ]; + } + + /** + * {@inheritdoc} + */ + public function unlink_account(array $link_data) + { + if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service']) + { + return 'LOGIN_LINK_MISSING_DATA'; } + + // Remove user specified in $link_data if possible + $user_id = isset($link_data['user_id']) ? $link_data['user_id'] : $this->user->data['user_id']; + + // Remove the link + $sql = 'DELETE FROM ' . $this->oauth_account_table . " + WHERE provider = '" . $this->db->sql_escape($link_data['oauth_service']) . "' + AND user_id = " . (int) $user_id; + $this->db->sql_query($sql); + + $service_name = $this->get_service_name($link_data['oauth_service']); + + // Clear all tokens belonging to the user on this service + $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); + $storage->clearToken($service_name); + + return false; } /** - * Performs the account linking for login_link - * - * @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account} - * @param string $service_name The name of the service being used in - * linking. - * @return string|null Returns a language constant (string) if an error is - * encountered, or null on success. - */ + * Performs the account linking for login_link. + * + * @param array $link_data The same variable given to + * {@see \phpbb\auth\provider\provider_interface::link_account} + * @param string $service_name The name of the service being used in linking. + * @return string|false Returns a language key (string) if an error is encountered, + * or false on success. + */ protected function link_account_login_link(array $link_data, $service_name) { - $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table); + $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); // Check for an access token, they should have one if (!$storage->has_access_token_by_session($service_name)) @@ -561,87 +573,109 @@ class oauth extends \phpbb\auth\provider\base return 'LOGIN_LINK_ERROR_OAUTH_NO_ACCESS_TOKEN'; } - // Prepare the query string - $query = 'mode=login_link&login_link_oauth_service=' . strtolower($link_data['oauth_service']); - // Prepare for an authentication request - $service_credentials = $this->service_providers[$service_name]->get_service_credentials(); - $scopes = $this->service_providers[$service_name]->get_auth_scope(); - $service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes); + $query = 'mode=login_link&login_link_oauth_service=' . $link_data['oauth_service']; + + try + { + $service = $this->get_service($link_data['oauth_service'], $storage, $query); + } + catch (\Exception $e) + { + return $e->getMessage(); + } + $this->service_providers[$service_name]->set_external_service_provider($service); - // The user has already authenticated successfully, request to authenticate again - $unique_id = $this->service_providers[$service_name]->perform_token_auth(); + try + { + // The user has already authenticated successfully, request to authenticate again + $unique_id = $this->service_providers[$service_name]->perform_token_auth(); + } + catch (exception $e) + { + return $e->getMessage(); + } // Insert into table, they will be able to log in after this - $data = array( + $data = [ 'user_id' => $link_data['user_id'], - 'provider' => strtolower($link_data['oauth_service']), + 'provider' => utf8_strtolower($link_data['oauth_service']), 'oauth_provider_id' => $unique_id, - ); + ]; $this->link_account_perform_link($data); + // Update token storage to store the user_id $storage->set_user_id($link_data['user_id']); + + return false; } /** - * Performs the account linking for auth_link - * - * @param array $link_data The same variable given to {@see \phpbb\auth\provider\provider_interface::link_account} - * @param string $service_name The name of the service being used in - * linking. - * @return string|null Returns a language constant (string) if an error is - * encountered, or null on success. - */ + * Performs the account linking for auth_link. + * + * @param array $link_data The same variable given to + * {@see \phpbb\auth\provider\provider_interface::link_account} + * @param string $service_name The name of the service being used in linking. + * @return string|false Returns a language constant (string) if an error is encountered, + * or false on success. + */ protected function link_account_auth_link(array $link_data, $service_name) { - $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table); - $query = 'i=ucp_auth_link&mode=auth_link&link=1&oauth_service=' . strtolower($link_data['oauth_service']); - $service_credentials = $this->service_providers[$service_name]->get_service_credentials(); - $scopes = $this->service_providers[$service_name]->get_auth_scope(); - $service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes); + $storage = new token_storage($this->db, $this->user, $this->oauth_token_table, $this->oauth_state_table); + $query = 'i=ucp_auth_link&mode=auth_link&link=1&oauth_service=' . $link_data['oauth_service']; - if (($service::OAUTH_VERSION === 2 && $this->request->is_set('code', \phpbb\request\request_interface::GET)) - || ($service::OAUTH_VERSION === 1 && $this->request->is_set('oauth_token', \phpbb\request\request_interface::GET))) + try + { + /** @var OAuth1Service|OAuth2Service $service */ + $service = $this->get_service($link_data['oauth_service'], $storage, $query); + } + catch (\Exception $e) + { + return $e->getMessage(); + } + + if ($this->is_set_code($service)) { $this->service_providers[$service_name]->set_external_service_provider($service); - $unique_id = $this->service_providers[$service_name]->perform_auth_login(); + + try + { + $unique_id = $this->service_providers[$service_name]->perform_auth_login(); + } + catch (exception $e) + { + return $e->getMessage(); + } // Insert into table, they will be able to log in after this - $data = array( + $data = [ 'user_id' => $this->user->data['user_id'], - 'provider' => strtolower($link_data['oauth_service']), + 'provider' => utf8_strtolower($link_data['oauth_service']), 'oauth_provider_id' => $unique_id, - ); + ]; $this->link_account_perform_link($data); + + return false; } else { - if ($service::OAUTH_VERSION === 1) - { - $token = $service->requestRequestToken(); - $url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken())); - } - else - { - $url = $service->getAuthorizationUri(); - } - header('Location: ' . $url); + return $this->set_redirect($service); } } /** - * Performs the query that inserts an account link - * - * @param array $data This array is passed to db->sql_build_array - */ + * Performs the query that inserts an account link + * + * @param array $data This array is passed to db->sql_build_array + */ protected function link_account_perform_link(array $data) { // Check if the external account is already associated with other user $sql = 'SELECT user_id - FROM ' . $this->auth_provider_oauth_token_account_assoc . " + FROM ' . $this->oauth_account_table . " WHERE provider = '" . $this->db->sql_escape($data['provider']) . "' AND oauth_provider_id = '" . $this->db->sql_escape($data['oauth_provider_id']) . "'"; $result = $this->db->sql_query($sql); @@ -654,114 +688,172 @@ class oauth extends \phpbb\auth\provider\base } // Link account - $sql = 'INSERT INTO ' . $this->auth_provider_oauth_token_account_assoc . ' - ' . $this->db->sql_build_array('INSERT', $data); + $sql = 'INSERT INTO ' . $this->oauth_account_table . ' ' . $this->db->sql_build_array('INSERT', $data); $this->db->sql_query($sql); /** * Event is triggered after user links account. * * @event core.auth_oauth_link_after - * @var array data User row + * @var array data User row * @since 3.1.11-RC1 */ - $vars = array( + $vars = [ 'data', - ); + ]; extract($this->dispatcher->trigger_event('core.auth_oauth_link_after', compact($vars))); } /** - * {@inheritdoc} - */ - public function logout($data, $new_session) + * Returns a new service object. + * + * @param string $provider The name of the provider + * @param token_storage $storage Token storage object + * @param string $query The query string used for the redirect uri + * @return ServiceInterface + * @throws exception When OAuth service was not created + */ + protected function get_service($provider, token_storage $storage, $query) { - // Clear all tokens belonging to the user - $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table); - $storage->clearAllTokens(); + $service_name = $this->get_service_name($provider); - return; - } + /** @see \phpbb\auth\provider\oauth\service\service_interface::get_service_credentials */ + $service_credentials = $this->service_providers[$service_name]->get_service_credentials(); - /** - * {@inheritdoc} - */ - public function get_auth_link_data($user_id = 0) - { - $block_vars = array(); + /** @see \phpbb\auth\provider\oauth\service\service_interface::get_auth_scope */ + $scopes = $this->service_providers[$service_name]->get_auth_scope(); - // Get all external accounts tied to the current user - $data = array( - 'user_id' => ($user_id <= 0) ? (int) $this->user->data['user_id'] : (int) $user_id, + $callback = generate_board_url() . "/ucp.{$this->php_ext}?{$query}"; + + // Setup the credentials for the requests + $credentials = new Credentials( + $service_credentials['key'], + $service_credentials['secret'], + $callback ); - $sql = 'SELECT oauth_provider_id, provider FROM ' . $this->auth_provider_oauth_token_account_assoc . ' - WHERE ' . $this->db->sql_build_array('SELECT', $data); - $result = $this->db->sql_query($sql); - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); - $oauth_user_ids = array(); + $service_factory = new ServiceFactory; - if ($rows !== false && count($rows)) + // Allow providers to register a custom class or override the provider name + if ($class = $this->service_providers[$service_name]->get_external_service_class()) { - foreach ($rows as $row) + if (class_exists($class)) + { + try + { + $service_factory->registerService($provider, $class); + } + catch (\OAuth\Common\Exception\Exception $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); + } + } + else { - $oauth_user_ids[$row['provider']] = $row['oauth_provider_id']; + $provider = $class; } } - unset($rows); - foreach ($this->service_providers as $service_name => $service_provider) + $service = $service_factory->createService($provider, $credentials, $storage, $scopes); + + if (!$service) { - // Only include data if the credentials are set - $credentials = $service_provider->get_service_credentials(); - if ($credentials['key'] && $credentials['secret']) - { - $actual_name = str_replace('auth.provider.oauth.service.', '', $service_name); - - $block_vars[$service_name] = array( - 'HIDDEN_FIELDS' => array( - 'link' => (!isset($oauth_user_ids[$actual_name])), - 'oauth_service' => $actual_name, - ), - - 'SERVICE_ID' => $actual_name, - 'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)], - 'UNIQUE_ID' => (isset($oauth_user_ids[$actual_name])) ? $oauth_user_ids[$actual_name] : null, - ); - } + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_SERVICE_NOT_CREATED'); } - return array( - 'BLOCK_VAR_NAME' => 'oauth', - 'BLOCK_VARS' => $block_vars, + return $service; + } - 'TEMPLATE_FILE' => 'ucp_auth_link_oauth.html', - ); + /** + * Returns the service name for an OAuth provider name. + * + * @param string $provider The OAuth provider name + * @return string The service name + */ + protected function get_service_name($provider) + { + if (strpos($provider, 'auth.provider.oauth.service.') !== 0) + { + $provider = 'auth.provider.oauth.service.' . utf8_strtolower($provider); + } + + return $provider; } /** - * {@inheritdoc} - */ - public function unlink_account(array $link_data) + * Returns the OAuth provider name from a service name. + * + * @param string $service_name The service name + * @return string The OAuth provider name + */ + protected function get_provider($service_name) { - if (!array_key_exists('oauth_service', $link_data) || !$link_data['oauth_service']) + return str_replace('auth.provider.oauth.service.', '', $service_name); + } + + /** + * Returns the localized title for the OAuth provider. + * + * @param string $provider The OAuth provider name + * @return string The OAuth provider title + */ + protected function get_provider_title($provider) + { + return $this->language->lang('AUTH_PROVIDER_OAUTH_SERVICE_' . utf8_strtoupper($provider)); + } + + /** + * Returns whether or not the authorization code is set. + * + * @param OAuth1Service|OAuth2Service $service The external OAuth service + * @return bool Whether or not the authorization code is set in the URL + * for the respective OAuth service's version + */ + protected function is_set_code($service) + { + switch ($service::OAUTH_VERSION) { - return 'LOGIN_LINK_MISSING_DATA'; + case 1: + return $this->request->is_set('oauth_token', request_interface::GET); + + case 2: + return $this->request->is_set('code', request_interface::GET); + + default: + return false; } + } - // Remove user specified in $link_data if possible - $user_id = isset($link_data['user_id']) ? $link_data['user_id'] : $this->user->data['user_id']; + /** + * Sets a redirect to the authorization uri. + * + * @param OAuth1Service|OAuth2Service $service The external OAuth service + * @return array|false Array if an error occurred, + * false on success + */ + protected function set_redirect($service) + { + $parameters = []; - // Remove the link - $sql = 'DELETE FROM ' . $this->auth_provider_oauth_token_account_assoc . " - WHERE provider = '" . $this->db->sql_escape($link_data['oauth_service']) . "' - AND user_id = " . (int) $user_id; - $this->db->sql_query($sql); + if ($service::OAUTH_VERSION === 1) + { + try + { + $token = $service->requestRequestToken(); + $parameters = ['oauth_token' => $token->getRequestToken()]; + } + catch (TokenResponseException $e) + { + return [ + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => $e->getMessage(), + 'user_row' => ['user_id' => ANONYMOUS], + ]; + } + } - // Clear all tokens belonging to the user on this service - $service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']); - $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table); - $storage->clearToken($service_name); + redirect($service->getAuthorizationUri($parameters), false, true); + + return false; } } diff --git a/phpBB/phpbb/auth/provider/oauth/service/base.php b/phpBB/phpbb/auth/provider/oauth/service/base.php index 6adf64aa30..5ab426a0aa 100644 --- a/phpBB/phpbb/auth/provider/oauth/service/base.php +++ b/phpBB/phpbb/auth/provider/oauth/service/base.php @@ -1,49 +1,57 @@ <?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 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\auth\provider\oauth\service; /** -* Base OAuth abstract class that all OAuth services should implement -*/ -abstract class base implements \phpbb\auth\provider\oauth\service\service_interface + * Base OAuth abstract class that all OAuth services should implement + */ +abstract class base implements service_interface { /** - * External OAuth service provider - * - * @var \OAuth\Common\Service\ServiceInterface - */ + * External OAuth service provider + * + * @var \OAuth\Common\Service\ServiceInterface + */ protected $service_provider; /** - * {@inheritdoc} - */ - public function get_external_service_provider() + * {@inheritdoc} + */ + public function get_auth_scope() { - return $this->service_provider; + return []; } /** - * {@inheritdoc} - */ - public function get_auth_scope() + * {@inheritdoc} + */ + public function get_external_service_class() + { + return ''; + } + + /** + * {@inheritdoc} + */ + public function get_external_service_provider() { - return array(); + return $this->service_provider; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function set_external_service_provider(\OAuth\Common\Service\ServiceInterface $service_provider) { $this->service_provider = $service_provider; diff --git a/phpBB/phpbb/auth/provider/oauth/service/bitly.php b/phpBB/phpbb/auth/provider/oauth/service/bitly.php index 25e731a02c..ca131b2019 100644 --- a/phpBB/phpbb/auth/provider/oauth/service/bitly.php +++ b/phpBB/phpbb/auth/provider/oauth/service/bitly.php @@ -1,94 +1,107 @@ <?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 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\auth\provider\oauth\service; /** -* Bitly OAuth service -*/ -class bitly extends \phpbb\auth\provider\oauth\service\base + * Bitly OAuth service + */ +class bitly extends base { - /** - * phpBB config - * - * @var \phpbb\config\config - */ + /** @var \phpbb\config\config */ protected $config; - /** - * phpBB request - * - * @var \phpbb\request\request_interface - */ + /** @var \phpbb\request\request_interface */ protected $request; /** - * Constructor - * - * @param \phpbb\config\config $config - * @param \phpbb\request\request_interface $request - */ + * Constructor. + * + * @param \phpbb\config\config $config Config object + * @param \phpbb\request\request_interface $request Request object + */ public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request) { - $this->config = $config; - $this->request = $request; + $this->config = $config; + $this->request = $request; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function get_service_credentials() { - return array( + return [ 'key' => $this->config['auth_oauth_bitly_key'], 'secret' => $this->config['auth_oauth_bitly_secret'], - ); + ]; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function perform_auth_login() { if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Bitly)) { - throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); } - // This was a callback request from bitly, get the token - $this->service_provider->requestAccessToken($this->request->variable('code', '')); + try + { + // This was a callback request, get the token + $this->service_provider->requestAccessToken($this->request->variable('code', '')); + } + catch (\OAuth\Common\Http\Exception\TokenResponseException $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } - // Send a request with it - $result = json_decode($this->service_provider->request('user/info'), true); + try + { + // Send a request with it + $result = (array) json_decode($this->service_provider->request('user/info'), true); + } + catch (\OAuth\Common\Exception\Exception $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } // Return the unique identifier returned from bitly return $result['data']['login']; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function perform_token_auth() { if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Bitly)) { - throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); } - // Send a request with it - $result = json_decode($this->service_provider->request('user/info'), true); + try + { + // Send a request with it + $result = (array) json_decode($this->service_provider->request('user/info'), true); + } + catch (\OAuth\Common\Exception\Exception $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } - // Return the unique identifier returned from bitly + // Return the unique identifier return $result['data']['login']; } } diff --git a/phpBB/phpbb/auth/provider/oauth/service/facebook.php b/phpBB/phpbb/auth/provider/oauth/service/facebook.php index bb98835e07..f7dbe307eb 100644 --- a/phpBB/phpbb/auth/provider/oauth/service/facebook.php +++ b/phpBB/phpbb/auth/provider/oauth/service/facebook.php @@ -1,63 +1,55 @@ <?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 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\auth\provider\oauth\service; /** -* Facebook OAuth service -*/ + * Facebook OAuth service + */ class facebook extends base { - /** - * phpBB config - * - * @var \phpbb\config\config - */ + /** @var \phpbb\config\config */ protected $config; - /** - * phpBB request - * - * @var \phpbb\request\request_interface - */ + /** @var \phpbb\request\request_interface */ protected $request; /** - * Constructor - * - * @param \phpbb\config\config $config - * @param \phpbb\request\request_interface $request - */ + * Constructor. + * + * @param \phpbb\config\config $config Config object + * @param \phpbb\request\request_interface $request Request object + */ public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request) { - $this->config = $config; - $this->request = $request; + $this->config = $config; + $this->request = $request; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function get_service_credentials() { - return array( + return [ 'key' => $this->config['auth_oauth_facebook_key'], 'secret' => $this->config['auth_oauth_facebook_secret'], - ); + ]; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function perform_auth_login() { if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Facebook)) @@ -65,19 +57,33 @@ class facebook extends base throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); } - // This was a callback request, get the token - $this->service_provider->requestAccessToken($this->request->variable('code', '')); + try + { + // This was a callback request, get the token + $this->service_provider->requestAccessToken($this->request->variable('code', '')); + } + catch (\OAuth\Common\Http\Exception\TokenResponseException $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } - // Send a request with it - $result = json_decode($this->service_provider->request('/me'), true); + try + { + // Send a request with it + $result = (array) json_decode($this->service_provider->request('/me'), true); + } + catch (\OAuth\Common\Exception\Exception $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } // Return the unique identifier return $result['id']; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function perform_token_auth() { if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Facebook)) @@ -85,8 +91,15 @@ class facebook extends base throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); } - // Send a request with it - $result = json_decode($this->service_provider->request('/me'), true); + try + { + // Send a request with it + $result = (array) json_decode($this->service_provider->request('/me'), true); + } + catch (\OAuth\Common\Exception\Exception $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } // Return the unique identifier return $result['id']; diff --git a/phpBB/phpbb/auth/provider/oauth/service/google.php b/phpBB/phpbb/auth/provider/oauth/service/google.php index cb9f83a94f..6e671ab13e 100644 --- a/phpBB/phpbb/auth/provider/oauth/service/google.php +++ b/phpBB/phpbb/auth/provider/oauth/service/google.php @@ -1,74 +1,66 @@ <?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 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\auth\provider\oauth\service; /** -* Google OAuth service -*/ + * Google OAuth service + */ class google extends base { - /** - * phpBB config - * - * @var \phpbb\config\config - */ + /** @var \phpbb\config\config */ protected $config; - /** - * phpBB request - * - * @var \phpbb\request\request_interface - */ + /** @var \phpbb\request\request_interface */ protected $request; /** - * Constructor - * - * @param \phpbb\config\config $config - * @param \phpbb\request\request_interface $request - */ + * Constructor. + * + * @param \phpbb\config\config $config Config object + * @param \phpbb\request\request_interface $request Request object + */ public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request) { - $this->config = $config; - $this->request = $request; + $this->config = $config; + $this->request = $request; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function get_auth_scope() { - return array( + return [ 'userinfo_email', 'userinfo_profile', - ); + ]; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function get_service_credentials() { - return array( + return [ 'key' => $this->config['auth_oauth_google_key'], 'secret' => $this->config['auth_oauth_google_secret'], - ); + ]; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function perform_auth_login() { if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Google)) @@ -76,19 +68,33 @@ class google extends base throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); } - // This was a callback request, get the token - $this->service_provider->requestAccessToken($this->request->variable('code', '')); + try + { + // This was a callback request, get the token + $this->service_provider->requestAccessToken($this->request->variable('code', '')); + } + catch (\OAuth\Common\Http\Exception\TokenResponseException $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } - // Send a request with it - $result = json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true); + try + { + // Send a request with it + $result = (array) json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true); + } + catch (\OAuth\Common\Exception\Exception $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } // Return the unique identifier return $result['id']; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function perform_token_auth() { if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Google)) @@ -96,8 +102,15 @@ class google extends base throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); } - // Send a request with it - $result = json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true); + try + { + // Send a request with it + $result = (array) json_decode($this->service_provider->request('https://www.googleapis.com/oauth2/v1/userinfo'), true); + } + catch (\OAuth\Common\Exception\Exception $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } // Return the unique identifier return $result['id']; diff --git a/phpBB/phpbb/auth/provider/oauth/service/service_interface.php b/phpBB/phpbb/auth/provider/oauth/service/service_interface.php index e84eb247b6..239e661989 100644 --- a/phpBB/phpbb/auth/provider/oauth/service/service_interface.php +++ b/phpBB/phpbb/auth/provider/oauth/service/service_interface.php @@ -1,73 +1,85 @@ <?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 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\auth\provider\oauth\service; /** -* OAuth service interface -*/ + * OAuth service interface + */ interface service_interface { /** - * Returns an array of the scopes necessary for auth - * - * @return array An array of the required scopes - */ + * Returns an array of the scopes necessary for auth + * + * @return array An array of the required scopes + */ public function get_auth_scope(); /** - * Returns the external library service provider once it has been set - * - * @param \OAuth\Common\Service\ServiceInterface|null - */ - public function get_external_service_provider(); - - /** - * Returns an array containing the service credentials belonging to requested - * service. - * - * @return array An array containing the 'key' and the 'secret' of the - * service in the form: - * array( - * 'key' => string - * 'secret' => string - * ) - */ + * Returns an array containing the service credentials belonging to requested + * service. + * + * @return array An array containing the 'key' and the 'secret' of the + * service in the form: + * array( + * 'key' => string + * 'secret' => string + * ) + */ public function get_service_credentials(); /** - * Returns the results of the authentication in json format - * - * @throws \phpbb\auth\provider\oauth\service\exception - * @return string The unique identifier returned by the service provider - * that is used to authenticate the user with phpBB. - */ + * Returns the results of the authentication in json format + * + * @throws \phpbb\auth\provider\oauth\service\exception + * @return string The unique identifier returned by the service provider + * that is used to authenticate the user with phpBB. + */ public function perform_auth_login(); /** - * Returns the results of the authentication in json format - * Use this function when the user already has an access token - * - * @throws \phpbb\auth\provider\oauth\service\exception - * @return string The unique identifier returned by the service provider - * that is used to authenticate the user with phpBB. - */ + * Returns the results of the authentication in json format + * Use this function when the user already has an access token + * + * @throws \phpbb\auth\provider\oauth\service\exception + * @return string The unique identifier returned by the service provider + * that is used to authenticate the user with phpBB. + */ public function perform_token_auth(); /** - * Sets the external library service provider - * - * @param \OAuth\Common\Service\ServiceInterface $service_provider - */ + * Returns the class of external library service provider that has to be used. + * + * @return string If the string is a class, it will register the provided string as a class, + * which later will be generated as the OAuth external service provider. + * If the string is not a class, it will use this string, + * trying to generate a service for the version 2 and 1 respectively: + * \OAuth\OAuth2\Service\<string> + * If the string is empty, it will default to OAuth's standard service classes, + * trying to generate a service for the version 2 and 1 respectively: + * \OAuth\OAuth2\Service\Facebook + */ + public function get_external_service_class(); + + /** + * Returns the external library service provider once it has been set + */ + public function get_external_service_provider(); + + /** + * Sets the external library service provider + * + * @param \OAuth\Common\Service\ServiceInterface $service_provider + */ public function set_external_service_provider(\OAuth\Common\Service\ServiceInterface $service_provider); } diff --git a/phpBB/phpbb/auth/provider/oauth/service/twitter.php b/phpBB/phpbb/auth/provider/oauth/service/twitter.php index 06beac51e2..35cbc9e4f7 100644 --- a/phpBB/phpbb/auth/provider/oauth/service/twitter.php +++ b/phpBB/phpbb/auth/provider/oauth/service/twitter.php @@ -1,102 +1,111 @@ <?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 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\auth\provider\oauth\service; /** -* Twitter OAuth service -*/ -class twitter extends \phpbb\auth\provider\oauth\service\base + * Twitter OAuth service + */ +class twitter extends base { - /** - * phpBB config - * - * @var \phpbb\config\config - */ + /** @var \phpbb\config\config */ protected $config; - /** - * phpBB request - * - * @var \phpbb\request\request_interface - */ + /** @var \phpbb\request\request_interface */ protected $request; /** - * Constructor - * - * @param \phpbb\config\config $config - * @param \phpbb\request\request_interface $request - */ + * Constructor. + * + * @param \phpbb\config\config $config Config object + * @param \phpbb\request\request_interface $request Request object + */ public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request) { - $this->config = $config; - $this->request = $request; + $this->config = $config; + $this->request = $request; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function get_service_credentials() { - return array( + return [ 'key' => $this->config['auth_oauth_twitter_key'], 'secret' => $this->config['auth_oauth_twitter_secret'], - ); + ]; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function perform_auth_login() { if (!($this->service_provider instanceof \OAuth\OAuth1\Service\Twitter)) { - throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); } $storage = $this->service_provider->getStorage(); - $token = $storage->retrieveAccessToken('Twitter'); - $tokensecret = $token->getRequestTokenSecret(); - // This was a callback request from twitter, get the token - $this->service_provider->requestAccessToken( - $this->request->variable('oauth_token', ''), - $this->request->variable('oauth_verifier', ''), - $tokensecret - ); + try + { + /** @var \OAuth\OAuth1\Token\TokenInterface $token */ + $token = $storage->retrieveAccessToken('Twitter'); + } + catch (\OAuth\Common\Storage\Exception\TokenNotFoundException $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } + + $secret = $token->getRequestTokenSecret(); + + try + { + // This was a callback request, get the token + $this->service_provider->requestAccessToken( + $this->request->variable('oauth_token', ''), + $this->request->variable('oauth_verifier', ''), + $secret + ); + } + catch (\OAuth\Common\Http\Exception\TokenResponseException $e) + { + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_REQUEST'); + } // Send a request with it - $result = json_decode($this->service_provider->request('account/verify_credentials.json'), true); + $result = (array) json_decode($this->service_provider->request('account/verify_credentials.json'), true); - // Return the unique identifier returned from twitter + // Return the unique identifier return $result['id']; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function perform_token_auth() { if (!($this->service_provider instanceof \OAuth\OAuth1\Service\Twitter)) { - throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); + throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE'); } // Send a request with it - $result = json_decode($this->service_provider->request('account/verify_credentials.json'), true); + $result = (array) json_decode($this->service_provider->request('account/verify_credentials.json'), true); - // Return the unique identifier returned from twitter + // Return the unique identifier return $result['id']; } } diff --git a/phpBB/phpbb/auth/provider/oauth/token_storage.php b/phpBB/phpbb/auth/provider/oauth/token_storage.php index b0c2fd0d62..c0f585d7bb 100644 --- a/phpBB/phpbb/auth/provider/oauth/token_storage.php +++ b/phpBB/phpbb/auth/provider/oauth/token_storage.php @@ -1,15 +1,15 @@ <?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 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\auth\provider\oauth; @@ -20,67 +20,48 @@ use OAuth\Common\Storage\Exception\TokenNotFoundException; use OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException; /** -* OAuth storage wrapper for phpbb's cache -*/ + * OAuth storage wrapper for phpBB's cache + */ class token_storage implements TokenStorageInterface { - /** - * Cache driver. - * - * @var \phpbb\db\driver\driver_interface - */ + /** @var \phpbb\db\driver\driver_interface */ protected $db; - /** - * phpBB user - * - * @var \phpbb\user - */ + /** @var \phpbb\user */ protected $user; - /** - * OAuth token table - * - * @var string - */ + /** @var string OAuth table: token storage */ protected $oauth_token_table; - /** - * OAuth state table - * - * @var string - */ + /** @var string OAuth table: state */ protected $oauth_state_table; - /** - * @var object|TokenInterface - */ + /** @var TokenInterface OAuth token */ protected $cachedToken; - /** - * @var string - */ + /** @var string OAuth state */ protected $cachedState; /** - * Creates token storage for phpBB. - * - * @param \phpbb\db\driver\driver_interface $db - * @param \phpbb\user $user - * @param string $oauth_token_table - * @param string $oauth_state_table - */ + * Constructor. + * + * @param \phpbb\db\driver\driver_interface $db Database object + * @param \phpbb\user $user User object + * @param string $oauth_token_table OAuth table: token storage + * @param string $oauth_state_table OAuth table: state + */ public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $oauth_token_table, $oauth_state_table) { - $this->db = $db; - $this->user = $user; + $this->db = $db; + $this->user = $user; + $this->oauth_token_table = $oauth_token_table; $this->oauth_state_table = $oauth_state_table; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function retrieveAccessToken($service) { $service = $this->get_service_name_for_db($service); @@ -90,10 +71,10 @@ class token_storage implements TokenStorageInterface return $this->cachedToken; } - $data = array( + $data = [ 'user_id' => (int) $this->user->data['user_id'], 'provider' => $service, - ); + ]; if ((int) $this->user->data['user_id'] === ANONYMOUS) { @@ -104,33 +85,38 @@ class token_storage implements TokenStorageInterface } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function storeAccessToken($service, TokenInterface $token) { $service = $this->get_service_name_for_db($service); $this->cachedToken = $token; - $data = array( + $data = [ 'oauth_token' => $this->json_encode_token($token), - ); + ]; $sql = 'UPDATE ' . $this->oauth_token_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $data) . ' - WHERE user_id = ' . (int) $this->user->data['user_id'] . ' - ' . ((int) $this->user->data['user_id'] === ANONYMOUS ? "AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'" : '') . " - AND provider = '" . $this->db->sql_escape($service) . "'"; + SET ' . $this->db->sql_build_array('UPDATE', $data) . ' + WHERE user_id = ' . (int) $this->user->data['user_id'] . " + AND provider = '" . $this->db->sql_escape($service) . "'"; + + if ((int) $this->user->data['user_id'] === ANONYMOUS) + { + $sql .= " AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'"; + } + $this->db->sql_query($sql); if (!$this->db->sql_affectedrows()) { - $data = array( + $data = [ 'user_id' => (int) $this->user->data['user_id'], 'provider' => $service, 'oauth_token' => $this->json_encode_token($token), 'session_id' => $this->user->data['session_id'], - ); + ]; $sql = 'INSERT INTO ' . $this->oauth_token_table . $this->db->sql_build_array('INSERT', $data); @@ -141,8 +127,8 @@ class token_storage implements TokenStorageInterface } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function hasAccessToken($service) { $service = $this->get_service_name_for_db($service); @@ -152,22 +138,22 @@ class token_storage implements TokenStorageInterface return true; } - $data = array( + $data = [ 'user_id' => (int) $this->user->data['user_id'], 'provider' => $service, - ); + ]; if ((int) $this->user->data['user_id'] === ANONYMOUS) { $data['session_id'] = $this->user->data['session_id']; } - return $this->_has_acess_token($data); + return $this->has_access_token($data); } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function clearToken($service) { $service = $this->get_service_name_for_db($service); @@ -189,13 +175,13 @@ class token_storage implements TokenStorageInterface } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function clearAllTokens() { $this->cachedToken = null; - $sql = 'DELETE FROM ' . $this->oauth_token_table . ' + $sql = 'DELETE FROM ' . $this->oauth_token_table . ' WHERE user_id = ' . (int) $this->user->data['user_id']; if ((int) $this->user->data['user_id'] === ANONYMOUS) @@ -209,31 +195,30 @@ class token_storage implements TokenStorageInterface } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function storeAuthorizationState($service, $state) { $service = $this->get_service_name_for_db($service); $this->cachedState = $state; - $data = array( + $data = [ 'user_id' => (int) $this->user->data['user_id'], 'provider' => $service, 'oauth_state' => $state, 'session_id' => $this->user->data['session_id'], - ); + ]; - $sql = 'INSERT INTO ' . $this->oauth_state_table . ' - ' . $this->db->sql_build_array('INSERT', $data); + $sql = 'INSERT INTO ' . $this->oauth_state_table . ' ' . $this->db->sql_build_array('INSERT', $data); $this->db->sql_query($sql); return $this; } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function hasAuthorizationState($service) { $service = $this->get_service_name_for_db($service); @@ -243,10 +228,10 @@ class token_storage implements TokenStorageInterface return true; } - $data = array( + $data = [ 'user_id' => (int) $this->user->data['user_id'], 'provider' => $service, - ); + ]; if ((int) $this->user->data['user_id'] === ANONYMOUS) { @@ -257,8 +242,8 @@ class token_storage implements TokenStorageInterface } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function retrieveAuthorizationState($service) { $service = $this->get_service_name_for_db($service); @@ -268,10 +253,10 @@ class token_storage implements TokenStorageInterface return $this->cachedState; } - $data = array( + $data = [ 'user_id' => (int) $this->user->data['user_id'], 'provider' => $service, - ); + ]; if ((int) $this->user->data['user_id'] === ANONYMOUS) { @@ -282,8 +267,8 @@ class token_storage implements TokenStorageInterface } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function clearAuthorizationState($service) { $service = $this->get_service_name_for_db($service); @@ -305,8 +290,8 @@ class token_storage implements TokenStorageInterface } /** - * {@inheritdoc} - */ + * {@inheritdoc} + */ public function clearAllAuthorizationStates() { $this->cachedState = null; @@ -325,10 +310,11 @@ class token_storage implements TokenStorageInterface } /** - * Updates the user_id field in the database assosciated with the token - * - * @param int $user_id - */ + * Updates the user_id field in the database associated with the token. + * + * @param int $user_id The user identifier + * @return void + */ public function set_user_id($user_id) { if (!$this->cachedToken) @@ -336,21 +322,24 @@ class token_storage implements TokenStorageInterface return; } + $data = [ + 'user_id' => (int) $user_id, + ]; + $sql = 'UPDATE ' . $this->oauth_token_table . ' - SET ' . $this->db->sql_build_array('UPDATE', array( - 'user_id' => (int) $user_id - )) . ' - WHERE user_id = ' . (int) $this->user->data['user_id'] . " - AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'"; + SET ' . $this->db->sql_build_array('UPDATE', $data) . ' + WHERE user_id = ' . (int) $this->user->data['user_id'] . " + AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'"; $this->db->sql_query($sql); } /** - * Checks to see if an access token exists solely by the session_id of the user - * - * @param string $service The name of the OAuth service - * @return bool true if they have token, false if they don't - */ + * Checks to see if an access token exists solely by the session_id of the user. + * + * @param string $service The OAuth service name + * @return bool true if the user's access token exists, + * false if the user's access token does not exist + */ public function has_access_token_by_session($service) { $service = $this->get_service_name_for_db($service); @@ -360,20 +349,21 @@ class token_storage implements TokenStorageInterface return true; } - $data = array( + $data = [ 'session_id' => $this->user->data['session_id'], 'provider' => $service, - ); + ]; - return $this->_has_acess_token($data); + return $this->has_access_token($data); } /** - * Checks to see if a state exists solely by the session_id of the user - * - * @param string $service The name of the OAuth service - * @return bool true if they have state, false if they don't - */ + * Checks to see if a state exists solely by the session_id of the user. + * + * @param string $service The OAuth service name + * @return bool true if the user's state exists, + * false if the user's state does not exist + */ public function has_state_by_session($service) { $service = $this->get_service_name_for_db($service); @@ -383,25 +373,34 @@ class token_storage implements TokenStorageInterface return true; } - $data = array( + $data = [ 'session_id' => $this->user->data['session_id'], 'provider' => $service, - ); + ]; return (bool) $this->get_state_row($data); } /** - * A helper function that performs the query for has access token functions - * - * @param array $data - * @return bool - */ - protected function _has_acess_token($data) + * A helper function that performs the query for has access token functions. + * + * @param array $data The SQL WHERE data + * @return bool true if the user's access token exists, + * false if the user's access token does not exist + */ + protected function has_access_token($data) { return (bool) $this->get_access_token_row($data); } + /** + * A helper function that performs the query for retrieving access token functions by session. + * Also checks if the token is a valid token. + * + * @param string $service The OAuth service provider name + * @return TokenInterface + * @throws TokenNotFoundException + */ public function retrieve_access_token_by_session($service) { $service = $this->get_service_name_for_db($service); @@ -411,14 +410,21 @@ class token_storage implements TokenStorageInterface return $this->cachedToken; } - $data = array( + $data = [ 'session_id' => $this->user->data['session_id'], - 'provider' => $service, - ); + 'provider' => $service, + ]; return $this->_retrieve_access_token($data); } + /** + * A helper function that performs the query for retrieving state functions by session. + * + * @param string $service The OAuth service provider name + * @return string The OAuth state + * @throws AuthorizationStateNotFoundException + */ public function retrieve_state_by_session($service) { $service = $this->get_service_name_for_db($service); @@ -428,22 +434,22 @@ class token_storage implements TokenStorageInterface return $this->cachedState; } - $data = array( + $data = [ 'session_id' => $this->user->data['session_id'], - 'provider' => $service, - ); + 'provider' => $service, + ]; return $this->_retrieve_state($data); } /** - * A helper function that performs the query for retrieve access token functions - * Also checks if the token is a valid token - * - * @param array $data - * @return mixed - * @throws \OAuth\Common\Storage\Exception\TokenNotFoundException - */ + * A helper function that performs the query for retrieve access token functions. + * Also checks if the token is a valid token. + * + * @param array $data The SQL WHERE data + * @return TokenInterface + * @throws TokenNotFoundException + */ protected function _retrieve_access_token($data) { $row = $this->get_access_token_row($data); @@ -459,19 +465,21 @@ class token_storage implements TokenStorageInterface if (!($token instanceof TokenInterface)) { $this->clearToken($data['provider']); + throw new TokenNotFoundException('AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED'); } $this->cachedToken = $token; + return $token; } /** - * A helper function that performs the query for retrieve state functions + * A helper function that performs the query for retrieve state functions. * - * @param array $data - * @return mixed - * @throws \OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException + * @param array $data The SQL WHERE data + * @return string The OAuth state + * @throws AuthorizationStateNotFoundException */ protected function _retrieve_state($data) { @@ -483,18 +491,21 @@ class token_storage implements TokenStorageInterface } $this->cachedState = $row['oauth_state']; + return $this->cachedState; } /** - * A helper function that performs the query for retrieving an access token - * - * @param array $data - * @return mixed - */ + * A helper function that performs the query for retrieving an access token. + * + * @param array $data The SQL WHERE data + * @return array|false array with the OAuth token row, + * false if the token does not exist + */ protected function get_access_token_row($data) { - $sql = 'SELECT oauth_token FROM ' . $this->oauth_token_table . ' + $sql = 'SELECT oauth_token + FROM ' . $this->oauth_token_table . ' WHERE ' . $this->db->sql_build_array('SELECT', $data); $result = $this->db->sql_query($sql); $row = $this->db->sql_fetchrow($result); @@ -504,14 +515,16 @@ class token_storage implements TokenStorageInterface } /** - * A helper function that performs the query for retrieving a state + * A helper function that performs the query for retrieving a state. * - * @param array $data - * @return mixed + * @param array $data The SQL WHERE data + * @return array|false array with the OAuth state row, + * false if the state does not exist */ protected function get_state_row($data) { - $sql = 'SELECT oauth_state FROM ' . $this->oauth_state_table . ' + $sql = 'SELECT oauth_state + FROM ' . $this->oauth_state_table . ' WHERE ' . $this->db->sql_build_array('SELECT', $data); $result = $this->db->sql_query($sql); $row = $this->db->sql_fetchrow($result); @@ -520,16 +533,22 @@ class token_storage implements TokenStorageInterface return $row; } + /** + * A helper function that JSON encodes a TokenInterface's data. + * + * @param TokenInterface $token + * @return string The json encoded TokenInterface's data + */ public function json_encode_token(TokenInterface $token) { - $members = array( + $members = [ 'accessToken' => $token->getAccessToken(), 'endOfLife' => $token->getEndOfLife(), 'extraParams' => $token->getExtraParams(), 'refreshToken' => $token->getRefreshToken(), 'token_class' => get_class($token), - ); + ]; // Handle additional data needed for OAuth1 tokens if ($token instanceof StdOAuth1Token) @@ -542,6 +561,13 @@ class token_storage implements TokenStorageInterface return json_encode($members); } + /** + * A helper function that JSON decodes a data string and creates a TokenInterface. + * + * @param string $json The json encoded TokenInterface's data + * @return TokenInterface + * @throws TokenNotFoundException + */ public function json_decode_token($json) { $token_data = json_decode($json, true); @@ -557,7 +583,10 @@ class token_storage implements TokenStorageInterface $endOfLife = $token_data['endOfLife']; $extra_params = $token_data['extraParams']; - // Create the token + /** + * Create the token + * @var TokenInterface $token + */ $token = new $token_class($access_token, $refresh_token, TokenInterface::EOL_NEVER_EXPIRES, $extra_params); $token->setEndOfLife($endOfLife); @@ -573,20 +602,19 @@ class token_storage implements TokenStorageInterface } /** - * Returns the name of the service as it must be stored in the database. - * - * @param string $service The name of the OAuth service - * @return string The name of the OAuth service as it needs to be stored - * in the database. - */ - protected function get_service_name_for_db($service) + * Returns the service name as it must be stored in the database. + * + * @param string $provider The OAuth provider name + * @return string The OAuth service name + */ + protected function get_service_name_for_db($provider) { // Enforce the naming convention for oauth services - if (strpos($service, 'auth.provider.oauth.service.') !== 0) + if (strpos($provider, 'auth.provider.oauth.service.') !== 0) { - $service = 'auth.provider.oauth.service.' . strtolower($service); + $provider = 'auth.provider.oauth.service.' . strtolower($provider); } - return $service; + return $provider; } } diff --git a/phpBB/phpbb/auth/provider/provider_interface.php b/phpBB/phpbb/auth/provider/provider_interface.php index 463324ff46..21c73a33c5 100644 --- a/phpBB/phpbb/auth/provider/provider_interface.php +++ b/phpBB/phpbb/auth/provider/provider_interface.php @@ -53,7 +53,7 @@ interface provider_interface * Autologin function * * @return array|null containing the user row, empty if no auto login - * should take place, or null if not impletmented. + * should take place, or null if not implemented. */ public function autologin(); @@ -68,7 +68,7 @@ interface provider_interface /** * This function updates the template with variables related to the acp - * options with whatever configuraton values are passed to it as an array. + * options with whatever configuration values are passed to it as an array. * It then returns the name of the acp file related to this authentication * provider. * diff --git a/phpBB/phpbb/avatar/driver/upload.php b/phpBB/phpbb/avatar/driver/upload.php index a012bb15b6..a5b704b4ff 100644 --- a/phpBB/phpbb/avatar/driver/upload.php +++ b/phpBB/phpbb/avatar/driver/upload.php @@ -84,6 +84,7 @@ class upload extends \phpbb\avatar\driver\driver $template->assign_vars(array( 'S_UPLOAD_AVATAR_URL' => ($this->config['allow_avatar_remote_upload']) ? true : false, 'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'], + 'AVATAR_ALLOWED_EXTENSIONS' => implode(',', preg_replace('/^/', '.', $this->allowed_extensions)), )); return true; 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/cache/driver/eaccelerator.php b/phpBB/phpbb/cache/driver/eaccelerator.php deleted file mode 100644 index 740855144f..0000000000 --- a/phpBB/phpbb/cache/driver/eaccelerator.php +++ /dev/null @@ -1,107 +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 eAccelerator -* @todo Missing locks from destroy() talk with David -*/ -class eaccelerator extends \phpbb\cache\driver\memory -{ - var $extension = 'eaccelerator'; - var $function = 'eaccelerator_get'; - - var $serialize_header = '#phpbb-serialized#'; - - /** - * {@inheritDoc} - */ - function purge() - { - foreach (eaccelerator_list_keys() as $var) - { - // @todo Check why the substr() - // @todo Only unset vars matching $this->key_prefix - eaccelerator_rm(substr($var['name'], 1)); - } - - parent::purge(); - } - - /** - * {@inheritDoc} - */ - function tidy() - { - global $config; - - eaccelerator_gc(); - - $config->set('cache_last_gc', time(), false); - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - $result = eaccelerator_get($this->key_prefix . $var); - - if ($result === null) - { - return false; - } - - // Handle serialized objects - if (is_string($result) && strpos($result, $this->serialize_header . 'O:') === 0) - { - $result = unserialize(substr($result, strlen($this->serialize_header))); - } - - return $result; - } - - /** - * 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) - { - // Serialize objects and make them easy to detect - $data = (is_object($data)) ? $this->serialize_header . serialize($data) : $data; - - return eaccelerator_put($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 eaccelerator_rm($this->key_prefix . $var); - } -} diff --git a/phpBB/phpbb/cache/driver/memcache.php b/phpBB/phpbb/cache/driver/memcache.php deleted file mode 100644 index 57f138f574..0000000000 --- a/phpBB/phpbb/cache/driver/memcache.php +++ /dev/null @@ -1,122 +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; - -if (!defined('PHPBB_ACM_MEMCACHE_PORT')) -{ - define('PHPBB_ACM_MEMCACHE_PORT', 11211); -} - -if (!defined('PHPBB_ACM_MEMCACHE_COMPRESS')) -{ - define('PHPBB_ACM_MEMCACHE_COMPRESS', false); -} - -if (!defined('PHPBB_ACM_MEMCACHE_HOST')) -{ - define('PHPBB_ACM_MEMCACHE_HOST', 'localhost'); -} - -if (!defined('PHPBB_ACM_MEMCACHE')) -{ - //can define multiple servers with host1/port1,host2/port2 format - define('PHPBB_ACM_MEMCACHE', PHPBB_ACM_MEMCACHE_HOST . '/' . PHPBB_ACM_MEMCACHE_PORT); -} - -/** -* ACM for Memcached -*/ -class memcache extends \phpbb\cache\driver\memory -{ - var $extension = 'memcache'; - - var $memcache; - var $flags = 0; - - function __construct() - { - // Call the parent constructor - parent::__construct(); - - $this->memcache = new \Memcache; - foreach (explode(',', PHPBB_ACM_MEMCACHE) as $u) - { - preg_match('#(.*)/(\d+)#', $u, $parts); - $this->memcache->addServer(trim($parts[1]), (int) trim($parts[2])); - } - $this->flags = (PHPBB_ACM_MEMCACHE_COMPRESS) ? MEMCACHE_COMPRESSED : 0; - } - - /** - * {@inheritDoc} - */ - function unload() - { - parent::unload(); - - $this->memcache->close(); - } - - /** - * {@inheritDoc} - */ - function purge() - { - $this->memcache->flush(); - - parent::purge(); - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - return $this->memcache->get($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) - { - if (!$this->memcache->replace($this->key_prefix . $var, $data, $this->flags, $ttl)) - { - return $this->memcache->set($this->key_prefix . $var, $data, $this->flags, $ttl); - } - return true; - } - - /** - * Remove an item from the cache - * - * @access protected - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - function _delete($var) - { - return $this->memcache->delete($this->key_prefix . $var); - } -} diff --git a/phpBB/phpbb/cache/driver/memcached.php b/phpBB/phpbb/cache/driver/memcached.php index 7d66759ec2..fbb587a369 100644 --- a/phpBB/phpbb/cache/driver/memcached.php +++ b/phpBB/phpbb/cache/driver/memcached.php @@ -50,12 +50,16 @@ class memcached extends \phpbb\cache\driver\memory /** * Memcached constructor + * + * @param string $memcached_servers Memcached servers string (optional) */ - public function __construct() + public function __construct($memcached_servers = '') { // Call the parent constructor parent::__construct(); + $memcached_servers = $memcached_servers ?: PHPBB_ACM_MEMCACHED; + $this->memcached = new \Memcached(); $this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); // Memcached defaults to using compression, disable if we don't want @@ -65,10 +69,20 @@ class memcached extends \phpbb\cache\driver\memory $this->memcached->setOption(\Memcached::OPT_COMPRESSION, false); } - foreach (explode(',', PHPBB_ACM_MEMCACHED) as $u) + $server_list = []; + foreach (explode(',', $memcached_servers) as $u) + { + if (preg_match('#(.*)/(\d+)#', $u, $parts)) + { + $server_list[] = [trim($parts[1]), (int) trim($parts[2])]; + } + } + + $this->memcached->addServers($server_list); + + if (empty($server_list) || empty($this->memcached->getStats())) { - preg_match('#(.*)/(\d+)#', $u, $parts); - $this->memcached->addServer(trim($parts[1]), (int) trim($parts[2])); + trigger_error('Could not connect to memcached server(s).'); } } diff --git a/phpBB/phpbb/cache/driver/memory.php b/phpBB/phpbb/cache/driver/memory.php index eba9549877..956936bf6f 100644 --- a/phpBB/phpbb/cache/driver/memory.php +++ b/phpBB/phpbb/cache/driver/memory.php @@ -25,7 +25,7 @@ abstract class memory extends \phpbb\cache\driver\base */ function __construct() { - global $phpbb_root_path, $dbname, $table_prefix, $phpbb_container; + global $dbname, $table_prefix, $phpbb_container; $this->cache_dir = $phpbb_container->getParameter('core.cache_dir'); $this->key_prefix = substr(md5($dbname . $table_prefix), 0, 8) . '_'; diff --git a/phpBB/phpbb/cache/driver/xcache.php b/phpBB/phpbb/cache/driver/xcache.php deleted file mode 100644 index 0c845a6a8d..0000000000 --- a/phpBB/phpbb/cache/driver/xcache.php +++ /dev/null @@ -1,107 +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 XCache -* -* To use this module you need ini_get() enabled and the following INI settings configured as follows: -* - xcache.var_size > 0 -* - xcache.admin.enable_auth = off (or xcache.admin.user and xcache.admin.password set) -* -*/ -class xcache extends \phpbb\cache\driver\memory -{ - var $extension = 'XCache'; - - function __construct() - { - parent::__construct(); - - if (!function_exists('ini_get') || (int) ini_get('xcache.var_size') <= 0) - { - trigger_error('Increase xcache.var_size setting above 0 or enable ini_get() to use this ACM module.', E_USER_ERROR); - } - } - - /** - * {@inheritDoc} - */ - function purge() - { - // Run before for XCache, if admin functions are disabled it will terminate execution - parent::purge(); - - // If the admin authentication is enabled but not set up, this will cause a nasty error. - // Not much we can do about it though. - $n = xcache_count(XC_TYPE_VAR); - - for ($i = 0; $i < $n; $i++) - { - xcache_clear_cache(XC_TYPE_VAR, $i); - } - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - $result = xcache_get($this->key_prefix . $var); - - return ($result !== null) ? $result : false; - } - - /** - * 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 xcache_set($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 xcache_unset($this->key_prefix . $var); - } - - /** - * Check if a cache var exists - * - * @access protected - * @param string $var Cache key - * @return bool True if it exists, otherwise false - */ - function _isset($var) - { - return xcache_isset($this->key_prefix . $var); - } -} diff --git a/phpBB/phpbb/captcha/non_gd.php b/phpBB/phpbb/captcha/non_gd.php index 3818672f17..8105187ed9 100644 --- a/phpBB/phpbb/captcha/non_gd.php +++ b/phpBB/phpbb/captcha/non_gd.php @@ -78,7 +78,7 @@ class non_gd for ($j = 0; $j < $code_len; $j++) { - $image .= $this->randomise(substr($hold_chars[$code{$j}][$i - $offset_y - 1], 1), $char_widths[$j]); + $image .= $this->randomise(substr($hold_chars[$code[$j]][$i - $offset_y - 1], 1), $char_widths[$j]); } for ($j = $offset_x + $img_width; $j < $this->width; $j++) @@ -117,7 +117,7 @@ class non_gd $end = strlen($scanline) - ceil($width/2); for ($i = (int) floor($width / 2); $i < $end; $i++) { - $pixel = ord($scanline{$i}); + $pixel = ord($scanline[$i]); if ($pixel < 190) { @@ -129,7 +129,7 @@ class non_gd } else { - $new_line .= $scanline{$i}; + $new_line .= $scanline[$i]; } } diff --git a/phpBB/phpbb/class_loader.php b/phpBB/phpbb/class_loader.php index cfdcc2af0b..a4b69311ca 100644 --- a/phpBB/phpbb/class_loader.php +++ b/phpBB/phpbb/class_loader.php @@ -64,7 +64,7 @@ class class_loader /** * Provide the class loader with a cache to store paths. If set to null, the - * the class loader will resolve paths by checking for the existance of every + * the class loader will resolve paths by checking for the existence of every * directory in the class name every time. * * @param \phpbb\cache\driver\driver_interface $cache An implementation of the phpBB cache interface. diff --git a/phpBB/phpbb/config/config.php b/phpBB/phpbb/config/config.php index aaad333006..c619cae2fd 100644 --- a/phpBB/phpbb/config/config.php +++ b/phpBB/phpbb/config/config.php @@ -148,6 +148,25 @@ class config implements \ArrayAccess, \IteratorAggregate, \Countable } /** + * Checks configuration option's value only if the new_value matches the + * current configuration value and the configuration value does exist.Called + * only after set_atomic has been called. + * + * @param string $key The configuration option's name + * @param string $new_value New configuration value + * @throws \phpbb\exception\http_exception when config value is set and not equal to new_value. + * @return bool True if the value was changed, false otherwise. + */ + public function ensure_lock($key, $new_value) + { + if (isset($this->config[$key]) && $this->config[$key] == $new_value) + { + return true; + } + throw new \phpbb\exception\http_exception(500, 'Failure while aqcuiring locks.'); + } + + /** * Increments an integer configuration value. * * @param string $key The configuration option's name 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/cron/run.php b/phpBB/phpbb/console/command/cron/run.php index dea6493007..511c6bc01b 100644 --- a/phpBB/phpbb/console/command/cron/run.php +++ b/phpBB/phpbb/console/command/cron/run.php @@ -73,7 +73,7 @@ class run extends \phpbb\console\command\command * @param InputInterface $input The input stream used to get the argument and verboe option. * @param OutputInterface $output The output stream, used for printing verbose-mode and error information. * - * @return int 0 if all is ok, 1 if a lock error occured and 2 if no task matching the argument was found. + * @return int 0 if all is ok, 1 if a lock error occurred and 2 if no task matching the argument was found. */ protected function execute(InputInterface $input, OutputInterface $output) { @@ -145,9 +145,11 @@ class run extends \phpbb\console\command\command * and returns with status 2. * * @see execute - * @param string $task_name The name of the task that should be run. + * * @param InputInterface $input The input stream used to get the argument and verbose option. * @param OutputInterface $output The output stream, used for printing verbose-mode and error information. + * @param string $task_name The name of the task that should be run. + * * @return int 0 if all is well, 2 if no task matches $task_name. */ protected function run_one(InputInterface $input, OutputInterface $output, $task_name) diff --git a/phpBB/phpbb/console/command/extension/enable.php b/phpBB/phpbb/console/command/extension/enable.php index a6f5b10e86..504b5546b3 100644 --- a/phpBB/phpbb/console/command/extension/enable.php +++ b/phpBB/phpbb/console/command/extension/enable.php @@ -46,9 +46,11 @@ class enable extends command $extension = $this->manager->get_extension($name); - if (!$extension->is_enableable()) + if (($enableable = $extension->is_enableable()) !== true) { - $io->error($this->user->lang('CLI_EXTENSION_NOT_ENABLEABLE', $name)); + $message = !empty($enableable) ? $enableable : $this->user->lang('CLI_EXTENSION_NOT_ENABLEABLE', $name); + $message = is_array($message) ? implode(PHP_EOL, $message) : $message; + $io->error($message); return 1; } diff --git a/phpBB/phpbb/console/command/fixup/recalculate_email_hash.php b/phpBB/phpbb/console/command/fixup/recalculate_email_hash.php deleted file mode 100644 index 6f7096296d..0000000000 --- a/phpBB/phpbb/console/command/fixup/recalculate_email_hash.php +++ /dev/null @@ -1,76 +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\console\command\fixup; - -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Style\SymfonyStyle; - -class recalculate_email_hash extends \phpbb\console\command\command -{ - /** @var \phpbb\db\driver\driver_interface */ - protected $db; - - public function __construct(\phpbb\user $user, \phpbb\db\driver\driver_interface $db) - { - $this->db = $db; - - parent::__construct($user); - } - - protected function configure() - { - $this - ->setName('fixup:recalculate-email-hash') - ->setDescription($this->user->lang('CLI_DESCRIPTION_RECALCULATE_EMAIL_HASH')) - ; - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $io = new SymfonyStyle($input, $output); - - $sql = 'SELECT user_id, user_email, user_email_hash - FROM ' . USERS_TABLE . ' - WHERE user_type <> ' . USER_IGNORE . " - AND user_email <> ''"; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - $user_email_hash = phpbb_email_hash($row['user_email']); - if ($user_email_hash !== $row['user_email_hash']) - { - $sql_ary = array( - 'user_email_hash' => $user_email_hash, - ); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . (int) $row['user_id']; - $this->db->sql_query($sql); - - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG) - { - $io->table( - array('user_id', 'user_email', 'user_email_hash'), - array(array($row['user_id'], $row['user_email'], $user_email_hash)) - ); - } - } - } - $this->db->sql_freeresult($result); - - $io->success($this->user->lang('CLI_FIXUP_RECALCULATE_EMAIL_HASH_SUCCESS')); - } -} diff --git a/phpBB/phpbb/console/command/update/check.php b/phpBB/phpbb/console/command/update/check.php index 9ced651e8b..4cd7d2155c 100644 --- a/phpBB/phpbb/console/command/update/check.php +++ b/phpBB/phpbb/console/command/update/check.php @@ -77,7 +77,7 @@ class check extends \phpbb\console\command\command * * @param InputInterface $input Input stream, used to get the options. * @param OutputInterface $output Output stream, used to print messages. - * @return int 0 if the board is up to date, 1 if it is not and 2 if an error occured. + * @return int 0 if the board is up to date, 1 if it is not and 2 if an error occurred. * @throws \RuntimeException */ protected function execute(InputInterface $input, OutputInterface $output) @@ -223,6 +223,7 @@ class check extends \phpbb\console\command\command * Check if all the available extensions are up to date * * @param SymfonyStyle $io IO handler, for formatted and unified IO + * @param string $stability Stability specifier string * @param bool $recheck Disallow the use of the cache * @return int */ 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/content_visibility.php b/phpBB/phpbb/content_visibility.php index f023e0742c..fbc56f3db2 100644 --- a/phpBB/phpbb/content_visibility.php +++ b/phpBB/phpbb/content_visibility.php @@ -144,7 +144,14 @@ class content_visibility */ public function is_visible($mode, $forum_id, $data) { - $is_visible = $this->auth->acl_get('m_approve', $forum_id) || $data[$mode . '_visibility'] == ITEM_APPROVED; + $visibility = $data[$mode . '_visibility']; + $poster_key = ($mode === 'topic') ? 'topic_poster' : 'poster_id'; + $is_visible = ($visibility == ITEM_APPROVED) || + ($this->config['display_unapproved_posts'] && + ($this->user->data['user_id'] != ANONYMOUS) && + ($visibility == ITEM_UNAPPROVED || $visibility == ITEM_REAPPROVE) && + ($this->user->data['user_id'] == $data[$poster_key])) || + $this->auth->acl_get('m_approve', $forum_id); /** * Allow changing the result of calling is_visible @@ -216,9 +223,16 @@ class content_visibility } else { - $where_sql .= $table_alias . $mode . '_visibility = ' . ITEM_APPROVED; - } + $visibility_query = $table_alias . $mode . '_visibility = '; + $where_sql .= '(' . $visibility_query . ITEM_APPROVED . ')'; + if ($this->config['display_unapproved_posts'] && ($this->user->data['user_id'] != ANONYMOUS)) + { + $poster_key = ($mode === 'topic') ? 'topic_poster' : 'poster_id'; + $where_sql .= ' OR ((' . $visibility_query . ITEM_UNAPPROVED . ' OR ' . $visibility_query . ITEM_REAPPROVE .')'; + $where_sql .= ' AND ' . $table_alias . $poster_key . ' = ' . ((int) $this->user->data['user_id']) . ')'; + } + } return '(' . $where_sql . ')'; } @@ -684,7 +698,7 @@ class content_visibility * @param $time int Timestamp when the action is performed * @param $reason string Reason why the visibilty was changed. * @param $force_update_all bool Force to update all posts within the topic - * @return array Changed topic data, empty array if an error occured. + * @return array Changed topic data, empty array if an error occurred. */ public function set_topic_visibility($visibility, $topic_id, $forum_id, $user_id, $time, $reason, $force_update_all = false) { diff --git a/phpBB/phpbb/controller/helper.php b/phpBB/phpbb/controller/helper.php index 664b4f4e0f..58a4a492f8 100644 --- a/phpBB/phpbb/controller/helper.php +++ b/phpBB/phpbb/controller/helper.php @@ -121,7 +121,7 @@ class helper * @param int $code The error code (e.g. 404, 500, 503, etc.) * @return Response A Response instance * - * @deprecated 3.1.3 (To be removed: 3.3.0) Use exceptions instead. + * @deprecated 3.1.3 (To be removed: 4.0.0) Use exceptions instead. */ public function error($message, $code = 500) { diff --git a/phpBB/phpbb/cron/controller/cron.php b/phpBB/phpbb/cron/controller/cron.php new file mode 100644 index 0000000000..6f0e35e4cd --- /dev/null +++ b/phpBB/phpbb/cron/controller/cron.php @@ -0,0 +1,40 @@ +<?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\cron\controller; + +use Symfony\Component\HttpFoundation\Response; + +/** + * Controller for running cron jobs + */ +class cron +{ + /** + * Handles CRON requests + * + * @param string $cron_type + * + * @return Response + */ + public function handle($cron_type) + { + $response = new Response(); + $response->headers->set('Cache-Control', 'no-cache'); + $response->headers->set('Content-type', 'image/gif'); + $response->headers->set('Content-length', '43'); + $response->setContent(base64_decode('R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==')); + + return $response; + } +} diff --git a/phpBB/phpbb/cron/event/cron_runner_listener.php b/phpBB/phpbb/cron/event/cron_runner_listener.php new file mode 100644 index 0000000000..9e9ecf0d47 --- /dev/null +++ b/phpBB/phpbb/cron/event/cron_runner_listener.php @@ -0,0 +1,103 @@ +<?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\cron\event; + +use phpbb\cron\manager; +use phpbb\lock\db; +use phpbb\request\request_interface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\Event\PostResponseEvent; + +/** + * Event listener that executes cron tasks, after the response was served + */ +class cron_runner_listener implements EventSubscriberInterface +{ + /** + * @var \phpbb\lock\db + */ + private $cron_lock; + + /** + * @var \phpbb\cron\manager + */ + private $cron_manager; + + /** + * @var \phpbb\request\request_interface + */ + private $request; + + /** + * Constructor + * + * @param db $lock + * @param manager $manager + * @param request_interface $request + */ + public function __construct(db $lock, manager $manager, request_interface $request) + { + $this->cron_lock = $lock; + $this->cron_manager = $manager; + $this->request = $request; + } + + /** + * Runs the cron job after the response was sent + * + * @param PostResponseEvent $event The event + */ + public function on_kernel_terminate(PostResponseEvent $event) + { + $request = $event->getRequest(); + $controller_name = $request->get('_route'); + + if ($controller_name !== 'phpbb_cron_run') + { + return; + } + + $cron_type = $request->get('cron_type'); + + if ($this->cron_lock->acquire()) + { + $task = $this->cron_manager->find_task($cron_type); + if ($task) + { + if ($task->is_parametrized()) + { + $task->parse_parameters($this->request); + } + + if ($task->is_ready()) + { + $task->run(); + } + + $this->cron_lock->release(); + } + } + } + + /** + * {@inheritdoc} + */ + static public function getSubscribedEvents() + { + return array( + KernelEvents::TERMINATE => 'on_kernel_terminate', + ); + } +} diff --git a/phpBB/phpbb/cron/manager.php b/phpBB/phpbb/cron/manager.php index 9bd30a0a5b..59ee693074 100644 --- a/phpBB/phpbb/cron/manager.php +++ b/phpBB/phpbb/cron/manager.php @@ -13,6 +13,9 @@ namespace phpbb\cron; +use phpbb\cron\task\wrapper; +use phpbb\routing\helper; + /** * Cron manager class. * @@ -21,6 +24,11 @@ namespace phpbb\cron; class manager { /** + * @var helper + */ + protected $routing_helper; + + /** * Set of \phpbb\cron\task\wrapper objects. * Array holding all tasks that have been found. * @@ -28,18 +36,27 @@ class manager */ protected $tasks = array(); + /** + * @var string + */ protected $phpbb_root_path; + + /** + * @var string + */ protected $php_ext; /** * Constructor. Loads all available tasks. * * @param array|\Traversable $tasks Provides an iterable set of task names + * @param helper $routing_helper Routing helper * @param string $phpbb_root_path Relative path to phpBB root * @param string $php_ext PHP file extension */ - public function __construct($tasks, $phpbb_root_path, $php_ext) + public function __construct($tasks, helper $routing_helper, $phpbb_root_path, $php_ext) { + $this->routing_helper = $routing_helper; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; @@ -142,6 +159,6 @@ class manager */ public function wrap_task(\phpbb\cron\task\task $task) { - return new \phpbb\cron\task\wrapper($task, $this->phpbb_root_path, $this->php_ext); + return new wrapper($task, $this->routing_helper, $this->phpbb_root_path, $this->php_ext); } } diff --git a/phpBB/phpbb/cron/task/wrapper.php b/phpBB/phpbb/cron/task/wrapper.php index 8a4a8b1f0c..4dc3a7fb95 100644 --- a/phpBB/phpbb/cron/task/wrapper.php +++ b/phpBB/phpbb/cron/task/wrapper.php @@ -13,14 +13,32 @@ namespace phpbb\cron\task; +use phpbb\routing\helper; + /** * Cron task wrapper class. * Enhances cron tasks with convenience methods that work identically for all tasks. */ class wrapper { + /** + * @var helper + */ + protected $routing_helper; + + /** + * @var task + */ protected $task; + + /** + * @var string + */ protected $phpbb_root_path; + + /** + * @var string + */ protected $php_ext; /** @@ -28,13 +46,15 @@ class wrapper * * Wraps a task $task, which must implement cron_task interface. * - * @param \phpbb\cron\task\task $task The cron task to wrap. - * @param string $phpbb_root_path Relative path to phpBB root - * @param string $php_ext PHP file extension + * @param task $task The cron task to wrap. + * @param helper $routing_helper Routing helper for route generation + * @param string $phpbb_root_path Relative path to phpBB root + * @param string $php_ext PHP file extension */ - public function __construct(\phpbb\cron\task\task $task, $phpbb_root_path, $php_ext) + public function __construct(task $task, helper $routing_helper, $phpbb_root_path, $php_ext) { $this->task = $task; + $this->routing_helper = $routing_helper; $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; } @@ -49,7 +69,7 @@ class wrapper */ public function is_parametrized() { - return $this->task instanceof \phpbb\cron\task\parametrized; + return $this->task instanceof parametrized; } /** @@ -76,22 +96,13 @@ class wrapper */ public function get_url() { - $name = $this->get_name(); + $params['cron_type'] = $this->get_name(); if ($this->is_parametrized()) { - $params = $this->task->get_parameters(); - $extra = ''; - foreach ($params as $key => $value) - { - $extra .= '&' . $key . '=' . urlencode($value); - } + $params = array_merge($params, $this->task->get_parameters()); } - else - { - $extra = ''; - } - $url = append_sid($this->phpbb_root_path . 'cron.' . $this->php_ext, 'cron_type=' . $name . $extra); - return $url; + + return $this->routing_helper->route('phpbb_cron_run', $params); } /** diff --git a/phpBB/phpbb/db/driver/driver.php b/phpBB/phpbb/db/driver/driver.php index a36ce8c0d7..93f0a749e5 100644 --- a/phpBB/phpbb/db/driver/driver.php +++ b/phpBB/phpbb/db/driver/driver.php @@ -76,6 +76,16 @@ abstract class driver implements driver_interface const SUBQUERY_BUILD = 5; /** + * @var bool + */ + protected $debug_load_time = false; + + /** + * @var bool + */ + protected $debug_sql_explain = false; + + /** * Constructor */ function __construct() @@ -98,6 +108,22 @@ abstract class driver implements driver_interface /** * {@inheritdoc} */ + public function set_debug_load_time($value) + { + $this->debug_load_time = $value; + } + + /** + * {@inheritdoc} + */ + public function set_debug_sql_explain($value) + { + $this->debug_sql_explain = $value; + } + + /** + * {@inheritdoc} + */ public function get_sql_layer() { return $this->sql_layer; @@ -955,7 +981,7 @@ abstract class driver implements driver_interface // Show complete SQL error and path to administrators only // Additionally show complete error on installation or if extended debug mode is enabled // The DEBUG constant is for development only! - if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG')) + if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || $this->debug_sql_explain) { $message .= ($sql) ? '<br /><br />SQL<br /><br />' . htmlspecialchars($sql) : ''; } diff --git a/phpBB/phpbb/db/driver/driver_interface.php b/phpBB/phpbb/db/driver/driver_interface.php index 8b487c5d42..05ff5ef066 100644 --- a/phpBB/phpbb/db/driver/driver_interface.php +++ b/phpBB/phpbb/db/driver/driver_interface.php @@ -16,6 +16,20 @@ namespace phpbb\db\driver; interface driver_interface { /** + * Set value for load_time debug parameter + * + * @param bool $value + */ + public function set_debug_load_time($value); + + /** + * Set value for sql_explain debug parameter + * + * @param bool $value + */ + public function set_debug_sql_explain($value); + + /** * Gets the name of the sql layer. * * @return string diff --git a/phpBB/phpbb/db/driver/factory.php b/phpBB/phpbb/db/driver/factory.php index fb3a826254..bb6e7a2682 100644 --- a/phpBB/phpbb/db/driver/factory.php +++ b/phpBB/phpbb/db/driver/factory.php @@ -68,6 +68,22 @@ class factory implements driver_interface /** * {@inheritdoc} */ + public function set_debug_load_time($value) + { + $this->get_driver()->set_debug_load_time($value); + } + + /** + * {@inheritdoc} + */ + public function set_debug_sql_explain($value) + { + $this->get_driver()->set_debug_sql_explain($value); + } + + /** + * {@inheritdoc} + */ public function get_sql_layer() { return $this->get_driver()->get_sql_layer(); diff --git a/phpBB/phpbb/db/driver/mssql_odbc.php b/phpBB/phpbb/db/driver/mssql_odbc.php index 9d9ad603e0..06cdce7a15 100644 --- a/phpBB/phpbb/db/driver/mssql_odbc.php +++ b/phpBB/phpbb/db/driver/mssql_odbc.php @@ -151,12 +151,11 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base { global $cache; - // EXPLAIN only in extra debug mode - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('start', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->curtime = microtime(true); } @@ -172,11 +171,11 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base $this->sql_error($query); } - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('stop', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->sql_time += microtime(true) - $this->curtime; } @@ -196,7 +195,7 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG')) + else if ($this->debug_sql_explain) { $this->sql_report('fromcache', $query); } diff --git a/phpBB/phpbb/db/driver/mssqlnative.php b/phpBB/phpbb/db/driver/mssqlnative.php index a4dcac5966..30ef9d9bc4 100644 --- a/phpBB/phpbb/db/driver/mssqlnative.php +++ b/phpBB/phpbb/db/driver/mssqlnative.php @@ -123,12 +123,11 @@ class mssqlnative extends \phpbb\db\driver\mssql_base { global $cache; - // EXPLAIN only in extra debug mode - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('start', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->curtime = microtime(true); } @@ -146,11 +145,11 @@ class mssqlnative extends \phpbb\db\driver\mssql_base // reset options for next query $this->query_options = array(); - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('stop', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->sql_time += microtime(true) - $this->curtime; } @@ -170,7 +169,7 @@ class mssqlnative extends \phpbb\db\driver\mssql_base $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG')) + else if ($this->debug_sql_explain) { $this->sql_report('fromcache', $query); } diff --git a/phpBB/phpbb/db/driver/mysql.php b/phpBB/phpbb/db/driver/mysql.php deleted file mode 100644 index a94e88b331..0000000000 --- a/phpBB/phpbb/db/driver/mysql.php +++ /dev/null @@ -1,503 +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; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG')) - { - $this->sql_report('start', $query); - } - else if (defined('PHPBB_DISPLAY_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 (defined('DEBUG')) - { - $this->sql_report('stop', $query); - } - else if (defined('PHPBB_DISPLAY_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 (defined('DEBUG')) - { - $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 existance 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/driver/mysqli.php b/phpBB/phpbb/db/driver/mysqli.php index b429ad97aa..0c1c063262 100644 --- a/phpBB/phpbb/db/driver/mysqli.php +++ b/phpBB/phpbb/db/driver/mysqli.php @@ -176,12 +176,11 @@ class mysqli extends \phpbb\db\driver\mysql_base { global $cache; - // EXPLAIN only in extra debug mode - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('start', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->curtime = microtime(true); } @@ -196,11 +195,11 @@ class mysqli extends \phpbb\db\driver\mysql_base $this->sql_error($query); } - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('stop', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->sql_time += microtime(true) - $this->curtime; } @@ -215,7 +214,7 @@ class mysqli extends \phpbb\db\driver\mysql_base $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } } - else if (defined('DEBUG')) + else if ($this->debug_sql_explain) { $this->sql_report('fromcache', $query); } @@ -376,7 +375,7 @@ class mysqli extends \phpbb\db\driver\mysql_base { static $test_prof; - // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING + // current detection method, might just switch to see the existence of INFORMATION_SCHEMA.PROFILING if ($test_prof === null) { $test_prof = false; diff --git a/phpBB/phpbb/db/driver/oracle.php b/phpBB/phpbb/db/driver/oracle.php index 5fd14709f8..f2a0bb557a 100644 --- a/phpBB/phpbb/db/driver/oracle.php +++ b/phpBB/phpbb/db/driver/oracle.php @@ -246,12 +246,11 @@ class oracle extends \phpbb\db\driver\driver { global $cache; - // EXPLAIN only in extra debug mode - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('start', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->curtime = microtime(true); } @@ -428,11 +427,11 @@ class oracle extends \phpbb\db\driver\driver } } - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('stop', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->sql_time += microtime(true) - $this->curtime; } @@ -452,7 +451,7 @@ class oracle extends \phpbb\db\driver\driver $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG')) + else if ($this->debug_sql_explain) { $this->sql_report('fromcache', $query); } diff --git a/phpBB/phpbb/db/driver/postgres.php b/phpBB/phpbb/db/driver/postgres.php index 44476612c3..ed330bc540 100644 --- a/phpBB/phpbb/db/driver/postgres.php +++ b/phpBB/phpbb/db/driver/postgres.php @@ -173,12 +173,11 @@ class postgres extends \phpbb\db\driver\driver { global $cache; - // EXPLAIN only in extra debug mode - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('start', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->curtime = microtime(true); } @@ -194,11 +193,11 @@ class postgres extends \phpbb\db\driver\driver $this->sql_error($query); } - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('stop', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->sql_time += microtime(true) - $this->curtime; } @@ -218,7 +217,7 @@ class postgres extends \phpbb\db\driver\driver $this->open_queries[(int) $this->query_result] = $this->query_result; } } - else if (defined('DEBUG')) + else if ($this->debug_sql_explain) { $this->sql_report('fromcache', $query); } diff --git a/phpBB/phpbb/db/driver/sqlite3.php b/phpBB/phpbb/db/driver/sqlite3.php index 0508500c52..43906f1b58 100644 --- a/phpBB/phpbb/db/driver/sqlite3.php +++ b/phpBB/phpbb/db/driver/sqlite3.php @@ -118,12 +118,11 @@ class sqlite3 extends \phpbb\db\driver\driver { global $cache; - // EXPLAIN only in extra debug mode - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('start', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->curtime = microtime(true); } @@ -156,11 +155,11 @@ class sqlite3 extends \phpbb\db\driver\driver } } - if (defined('DEBUG')) + if ($this->debug_sql_explain) { $this->sql_report('stop', $query); } - else if (defined('PHPBB_DISPLAY_LOAD_TIME')) + else if ($this->debug_load_time) { $this->sql_time += microtime(true) - $this->curtime; } @@ -175,7 +174,7 @@ class sqlite3 extends \phpbb\db\driver\driver $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } } - else if (defined('DEBUG')) + else if ($this->debug_sql_explain) { $this->sql_report('fromcache', $query); } diff --git a/phpBB/phpbb/db/extractor/mysql_extractor.php b/phpBB/phpbb/db/extractor/mysql_extractor.php index 34e309c19e..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 @@ -300,7 +198,7 @@ class mysql_extractor extends base_extractor } /** - * Extracts database table structure (for MySQL verisons older than 3.23.20) + * Extracts database table structure (for MySQL versions older than 3.23.20) * * @param string $table_name name of the database table * @return null diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php index 10343438b3..247ccc7a76 100644 --- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php +++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_4_rc1.php @@ -117,7 +117,7 @@ class release_3_0_4_rc1 extends \phpbb\db\migration\migration } else { - // equivelant to "none", which is the "Display in user control panel" option + // equivalent to "none", which is the "Display in user control panel" option $sql_ary['field_show_profile'] = 1; } diff --git a/phpBB/phpbb/db/migration/data/v310/softdelete_p1.php b/phpBB/phpbb/db/migration/data/v310/softdelete_p1.php index b1e7486e24..877cdc2fa3 100644 --- a/phpBB/phpbb/db/migration/data/v310/softdelete_p1.php +++ b/phpBB/phpbb/db/migration/data/v310/softdelete_p1.php @@ -132,7 +132,7 @@ class softdelete_p1 extends \phpbb\db\migration\migration /* * Using sql_case here to avoid "BIGINT UNSIGNED value is out of range" errors. * As we update all topics in 2 queries, one broken topic would stop the conversion - * for all topics and the surpressed error will cause the admin to not even notice it. + * for all topics and the suppressed error will cause the admin to not even notice it. */ $sql = 'UPDATE ' . $this->table_prefix . 'topics SET topic_posts_approved = topic_replies + 1, diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/migration/data/v330/add_display_unapproved_posts_config.php index 4d1b91f7b4..b429270827 100644 --- a/phpBB/phpbb/db/tools.php +++ b/phpBB/phpbb/db/migration/data/v330/add_display_unapproved_posts_config.php @@ -11,11 +11,14 @@ * */ -namespace phpbb\db; +namespace phpbb\db\migration\data\v330; -/** - * @deprecated 3.2.0-dev (To be removed 3.3.0) use \phpbb\db\tools\tools instead - */ -class tools extends \phpbb\db\tools\tools +class add_display_unapproved_posts_config extends \phpbb\db\migration\migration { + public function update_data() + { + return [ + ['config.add', ['display_unapproved_posts', 1]], + ]; + } } diff --git a/phpBB/phpbb/db/migration/data/v330/dev.php b/phpBB/phpbb/db/migration/data/v330/dev.php new file mode 100644 index 0000000000..209f9fc7ec --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/dev.php @@ -0,0 +1,36 @@ +<?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 dev extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return version_compare($this->config['version'], '3.3.0-dev', '>='); + } + + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v32x\v327', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.3.0-dev')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v330/forums_legend_limit.php b/phpBB/phpbb/db/migration/data/v330/forums_legend_limit.php new file mode 100644 index 0000000000..c5a4beef38 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/forums_legend_limit.php @@ -0,0 +1,49 @@ +<?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 forums_legend_limit extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return $this->db_tools->sql_column_exists($this->table_prefix . 'forums', 'display_subforum_limit'); + } + + static public function depends_on() + { + return ['\phpbb\db\migration\data\v330\v330b1']; + } + + public function update_schema() + { + return [ + 'add_columns' => [ + $this->table_prefix . 'forums' => [ + 'display_subforum_limit' => ['BOOL', 0, 'after' => 'display_subforum_list'], + ], + ], + ]; + } + + public function revert_schema() + { + return [ + 'drop_columns' => [ + $this->table_prefix . 'forums' => [ + 'display_subforum_limit', + ], + ], + ]; + } +} diff --git a/phpBB/phpbb/db/migration/data/v330/jquery_update.php b/phpBB/phpbb/db/migration/data/v330/jquery_update.php new file mode 100644 index 0000000000..f1ac6cdd41 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/jquery_update.php @@ -0,0 +1,37 @@ +<?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 jquery_update extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return $this->config['load_jquery_url'] === '//ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js'; + } + + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v330\dev', + ); + } + + public function update_data() + { + return array( + array('config.update', array('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js')), + ); + } + +} diff --git a/phpBB/phpbb/db/migration/data/v330/remove_attachment_flash.php b/phpBB/phpbb/db/migration/data/v330/remove_attachment_flash.php new file mode 100644 index 0000000000..11dc43483b --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/remove_attachment_flash.php @@ -0,0 +1,84 @@ +<?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_attachment_flash extends \phpbb\db\migration\migration +{ + // Following constants were deprecated in 3.3 + // and moved from constants.php to compatibility_globals.php, + // thus define them as class constants + const ATTACHMENT_CATEGORY_FLASH = 5; + + protected $cat_id = array( + self::ATTACHMENT_CATEGORY_FLASH, + ); + + public function update_data() + { + return array( + array('custom', array(array($this, 'remove_flash_group'))), + ); + } + + public function remove_flash_group() + { + // select group ids of outdated media + $sql = 'SELECT group_id + FROM ' . EXTENSION_GROUPS_TABLE . ' + WHERE ' . $this->db->sql_in_set('cat_id', $this->cat_id); + $result = $this->db->sql_query($sql); + + $group_ids = array(); + while ($group_id = (int) $this->db->sql_fetchfield('group_id')) + { + $group_ids[] = $group_id; + } + $this->db->sql_freeresult($result); + + // nothing to do, admin has removed all the outdated media extension groups + if (empty($group_ids)) + { + return true; + } + + // get the group id of downloadable files + $sql = 'SELECT group_id + FROM ' . EXTENSION_GROUPS_TABLE . " + WHERE group_name = 'DOWNLOADABLE_FILES'"; + $result = $this->db->sql_query($sql); + $download_id = (int) $this->db->sql_fetchfield('group_id'); + $this->db->sql_freeresult($result); + + if (empty($download_id)) + { + $sql = 'UPDATE ' . EXTENSIONS_TABLE . ' + SET group_id = 0 + WHERE ' . $this->db->sql_in_set('group_id', $group_ids); + } + else + { + // move outdated media extensions to downloadable files + $sql = 'UPDATE ' . EXTENSIONS_TABLE . " + SET group_id = $download_id" . ' + WHERE ' . $this->db->sql_in_set('group_id', $group_ids); + } + + $this->db->sql_query($sql); + + // delete the now empty, outdated media extension groups + $sql = 'DELETE FROM ' . EXTENSION_GROUPS_TABLE . ' + WHERE ' . $this->db->sql_in_set('group_id', $group_ids); + $this->db->sql_query($sql); + } +} diff --git a/phpBB/phpbb/db/migration/data/v330/remove_email_hash.php b/phpBB/phpbb/db/migration/data/v330/remove_email_hash.php new file mode 100644 index 0000000000..8ac8f4ed72 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/remove_email_hash.php @@ -0,0 +1,62 @@ +<?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_email_hash extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return ['\phpbb\db\migration\data\v30x\release_3_0_0']; + } + + public function update_schema() + { + return [ + 'add_index' => [ + $this->table_prefix . 'users' => [ + 'user_email' => ['user_email'], + ], + ], + 'drop_keys' => [ + $this->table_prefix . 'users' => [ + 'user_email_hash', + ], + ], + 'drop_columns' => [ + $this->table_prefix . 'users' => ['user_email_hash'], + ], + ]; + } + + public function revert_schema() + { + return [ + 'add_columns' => [ + $this->table_prefix . 'users' => [ + 'user_email_hash' => ['BINT', 0], + ], + ], + 'add_index' => [ + $this->table_prefix . 'users' => [ + 'user_email_hash', + ], + ], + 'drop_keys' => [ + $this->table_prefix . 'users' => [ + 'user_email' => ['user_email'], + ], + ], + ]; + } +} 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/migration/data/v330/v330b1.php b/phpBB/phpbb/db/migration/data/v330/v330b1.php new file mode 100644 index 0000000000..3df44504fc --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/v330b1.php @@ -0,0 +1,41 @@ +<?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 v330b1 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return version_compare($this->config['version'], '3.3.0-b1', '>='); + } + + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v330\jquery_update', + '\phpbb\db\migration\data\v330\reset_password', + '\phpbb\db\migration\data\v330\remove_attachment_flash', + '\phpbb\db\migration\data\v330\remove_max_pass_chars', + '\phpbb\db\migration\data\v32x\v328', + '\phpbb\db\migration\data\v330\dev', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.3.0-b1')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v330/v330b2.php b/phpBB/phpbb/db/migration/data/v330/v330b2.php new file mode 100644 index 0000000000..1badc1387a --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/v330b2.php @@ -0,0 +1,38 @@ +<?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 v330b2 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return version_compare($this->config['version'], '3.3.0-b2', '>='); + } + + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v330\add_display_unapproved_posts_config', + '\phpbb\db\migration\data\v330\forums_legend_limit', + '\phpbb\db\migration\data\v330\remove_email_hash', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.3.0-b2')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v330/v330rc1.php b/phpBB/phpbb/db/migration/data/v330/v330rc1.php new file mode 100644 index 0000000000..52193750cc --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/v330rc1.php @@ -0,0 +1,36 @@ +<?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 v330rc1 extends \phpbb\db\migration\migration +{ + public function effectively_installed() + { + return version_compare($this->config['version'], '3.3.0-RC1', '>='); + } + + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v330\v330b2', + ); + } + + public function update_data() + { + return array( + array('config.update', array('version', '3.3.0-RC1')), + ); + } +} diff --git a/phpBB/phpbb/db/migration/tool/module.php b/phpBB/phpbb/db/migration/tool/module.php index e5133c8152..93c338437e 100644 --- a/phpBB/phpbb/db/migration/tool/module.php +++ b/phpBB/phpbb/db/migration/tool/module.php @@ -509,7 +509,7 @@ class module implements \phpbb\db\migration\tool\tool_interface * Get parent module id * * @param string|int $parent_id The parent module_id|module_langname - * @param int|string|array $data The module_id, module_langname for existance checking or module data array for adding + * @param int|string|array $data The module_id, module_langname for existence checking or module data array for adding * @param bool $throw_exception The flag indicating if exception should be thrown on error * @return mixed The int parent module_id, an array of int parent module_id values or false * @throws \phpbb\db\migration\exception diff --git a/phpBB/phpbb/db/migrator.php b/phpBB/phpbb/db/migrator.php index 2b0c66fc58..3a1ee758cf 100644 --- a/phpBB/phpbb/db/migrator.php +++ b/phpBB/phpbb/db/migrator.php @@ -784,7 +784,7 @@ class migrator { return array( $parameters[0], - array($last_result), + isset($parameters[1]) ? array_merge($parameters[1], array($last_result)) : array($last_result), ); } break; diff --git a/phpBB/phpbb/db/tools/mssql.php b/phpBB/phpbb/db/tools/mssql.php index cbedf9a5c4..29f816a869 100644 --- a/phpBB/phpbb/db/tools/mssql.php +++ b/phpBB/phpbb/db/tools/mssql.php @@ -194,7 +194,7 @@ class mssql extends tools $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set']; } - // create sequence DDL based off of the existance of auto incrementing columns + // create sequence DDL based off of the existence of auto incrementing columns if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment']) { $create_sequence = $column_name; diff --git a/phpBB/phpbb/db/tools/postgres.php b/phpBB/phpbb/db/tools/postgres.php index 077d6e06f9..276ac135be 100644 --- a/phpBB/phpbb/db/tools/postgres.php +++ b/phpBB/phpbb/db/tools/postgres.php @@ -141,7 +141,7 @@ class postgres extends tools $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set']; } - // create sequence DDL based off of the existance of auto incrementing columns + // create sequence DDL based off of the existence of auto incrementing columns if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment']) { $create_sequence = $column_name; diff --git a/phpBB/phpbb/db/tools/tools.php b/phpBB/phpbb/db/tools/tools.php index c3352a1f66..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; @@ -335,7 +287,7 @@ class tools implements tools_interface $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set']; } - // create sequence DDL based off of the existance of auto incrementing columns + // create sequence DDL based off of the existence of auto incrementing columns if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment']) { $create_sequence = $column_name; @@ -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/di/container_builder.php b/phpBB/phpbb/di/container_builder.php index 8c1ce8bde2..70ceb9b5e3 100644 --- a/phpBB/phpbb/di/container_builder.php +++ b/phpBB/phpbb/di/container_builder.php @@ -158,13 +158,18 @@ class container_builder } else { - $this->container_extensions = array(new extension\core($this->get_config_path())); + $this->container_extensions = [ + new extension\core($this->get_config_path()), + ]; if ($this->use_extensions) { $this->load_extensions(); } + // Add tables extension after all extensions + $this->container_extensions[] = new extension\tables(); + // Inject the config if ($this->config_php_file) { @@ -481,7 +486,7 @@ class container_builder $cached_container_dump = $dumper->dump(array( 'class' => 'phpbb_cache_container', - 'base_class' => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder', + 'base_class' => 'Symfony\\Component\\DependencyInjection\\Container', )); $cache->write($cached_container_dump, $this->container->getResources()); diff --git a/phpBB/phpbb/di/extension/container_configuration.php b/phpBB/phpbb/di/extension/container_configuration.php index 4585d6509e..57e7ef6ca6 100644 --- a/phpBB/phpbb/di/extension/container_configuration.php +++ b/phpBB/phpbb/di/extension/container_configuration.php @@ -31,10 +31,15 @@ class container_configuration implements ConfigurationInterface $rootNode ->children() ->booleanNode('require_dev_dependencies')->defaultValue(false)->end() + ->booleanNode('allow_install_dir')->defaultValue(false)->end() ->arrayNode('debug') ->addDefaultsIfNotSet() ->children() ->booleanNode('exceptions')->defaultValue(false)->end() + ->booleanNode('load_time')->defaultValue(false)->end() + ->booleanNode('sql_explain')->defaultValue(false)->end() + ->booleanNode('memory')->defaultValue(false)->end() + ->booleanNode('show_errors')->defaultValue(false)->end() ->end() ->end() ->arrayNode('twig') @@ -45,6 +50,12 @@ class container_configuration implements ConfigurationInterface ->booleanNode('enable_debug_extension')->defaultValue(false)->end() ->end() ->end() + ->arrayNode('session') + ->addDefaultsIfNotSet() + ->children() + ->booleanNode('log_errors')->defaultValue(false)->end() + ->end() + ->end() ->end() ; return $treeBuilder; diff --git a/phpBB/phpbb/di/extension/core.php b/phpBB/phpbb/di/extension/core.php index 67150f0103..0497c90e2a 100644 --- a/phpBB/phpbb/di/extension/core.php +++ b/phpBB/phpbb/di/extension/core.php @@ -71,6 +71,8 @@ class core extends Extension } } + $container->setParameter('allow_install_dir', $config['allow_install_dir']); + // Set the Twig options if defined in the environment $definition = $container->getDefinition('template.twig.environment'); $twig_environment_options = $definition->getArgument(static::TWIG_OPTIONS_POSITION); @@ -97,6 +99,12 @@ class core extends Extension { $container->setParameter('debug.' . $name, $value); } + + // Set the log options + foreach ($config['session'] as $name => $value) + { + $container->setParameter('session.' . $name, $value); + } } /** diff --git a/phpBB/phpbb/di/extension/tables.php b/phpBB/phpbb/di/extension/tables.php new file mode 100644 index 0000000000..40684b6038 --- /dev/null +++ b/phpBB/phpbb/di/extension/tables.php @@ -0,0 +1,59 @@ +<?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\di\extension; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpKernel\DependencyInjection\Extension; + +/** + * Container tables extension + */ +class tables extends Extension +{ + /** + * {@inheritDoc} + */ + public function load(array $configs, ContainerBuilder $container) + { + // Tables is a reserved parameter and will be overwritten at all times + $tables = []; + + // Add access via 'tables' parameter to acquire array with all tables + $parameterBag = $container->getParameterBag(); + $parameters = $parameterBag->all(); + foreach ($parameters as $parameter_name => $parameter_value) + { + if (!preg_match('/tables\.(.+)/', $parameter_name, $matches)) + { + continue; + } + + $tables[$matches[1]] = $parameter_value; + } + + $container->setParameter('tables', $tables); + } + + /** + * Returns the recommended alias to use in XML. + * + * This alias is also the mandatory prefix to use when using YAML. + * + * @return string The alias + */ + public function getAlias() + { + return 'tables'; + } +} diff --git a/phpBB/phpbb/di/service_collection.php b/phpBB/phpbb/di/service_collection.php index 8e9175e204..6298670c42 100644 --- a/phpBB/phpbb/di/service_collection.php +++ b/phpBB/phpbb/di/service_collection.php @@ -49,21 +49,6 @@ class service_collection extends \ArrayObject return new service_collection_iterator($this); } - // Because of a PHP issue we have to redefine offsetExists - // (even with a call to the parent): - // https://bugs.php.net/bug.php?id=66834 - // https://bugs.php.net/bug.php?id=67067 - // But it triggers a sniffer issue that we have to skip - // @codingStandardsIgnoreStart - /** - * {@inheritdoc} - */ - public function offsetExists($index) - { - return parent::offsetExists($index); - } - // @codingStandardsIgnoreEnd - /** * {@inheritdoc} */ @@ -76,11 +61,11 @@ class service_collection extends \ArrayObject * Add a service to the collection * * @param string $name The service name - * @return null + * @return void */ public function add($name) { - $this->offsetSet($name, null); + $this->offsetSet($name, false); } /** @@ -103,4 +88,35 @@ class service_collection extends \ArrayObject { return $this->service_classes; } + + /** + * Returns the service associated to a class + * + * @return mixed + * @throw \RuntimeException if the + */ + public function get_by_class($class) + { + $service_id = null; + + foreach ($this->service_classes as $id => $service_class) + { + if ($service_class === $class) + { + if ($service_id !== null) + { + throw new \RuntimeException('More than one service definitions found for class "'.$class.'" in collection.'); + } + + $service_id = $id; + } + } + + if ($service_id === null) + { + throw new \RuntimeException('No service found for class "'.$class.'" in collection.'); + } + + return $this->offsetGet($service_id); + } } diff --git a/phpBB/phpbb/extension/extension_interface.php b/phpBB/phpbb/extension/extension_interface.php index 6a6b6adb8f..46072d420c 100644 --- a/phpBB/phpbb/extension/extension_interface.php +++ b/phpBB/phpbb/extension/extension_interface.php @@ -22,7 +22,8 @@ interface extension_interface /** * Indicate whether or not the extension can be enabled. * - * @return bool + * @return bool|array True if extension is enableable, array of reasons + * if not, false for generic reason. */ public function is_enableable(); diff --git a/phpBB/phpbb/extension/manager.php b/phpBB/phpbb/extension/manager.php index 4b4109bd85..1ce8425fff 100644 --- a/phpBB/phpbb/extension/manager.php +++ b/phpBB/phpbb/extension/manager.php @@ -161,6 +161,47 @@ class manager } /** + * Update the database entry for an extension + * + * @param string $name Extension name to update + * @param array $data Data to update in the database + * @param string $action Action to perform, by default 'update', may be also 'insert' or 'delete' + */ + protected function update_state($name, $data, $action = 'update') + { + switch ($action) + { + case 'insert': + $this->extensions[$name] = $data; + $this->extensions[$name]['ext_path'] = $this->get_extension_path($name); + ksort($this->extensions); + $sql = 'INSERT INTO ' . $this->extension_table . ' ' . $this->db->sql_build_array('INSERT', $data); + $this->db->sql_query($sql); + break; + + case 'update': + $this->extensions[$name] = array_merge($this->extensions[$name], $data); + $sql = 'UPDATE ' . $this->extension_table . ' + SET ' . $this->db->sql_build_array('UPDATE', $data) . " + WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; + $this->db->sql_query($sql); + break; + + case 'delete': + unset($this->extensions[$name]); + $sql = 'DELETE FROM ' . $this->extension_table . " + WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; + $this->db->sql_query($sql); + break; + } + + if ($this->cache) + { + $this->cache->purge(); + } + } + + /** * Runs a step of the extension enabling process. * * Allows the exentension to enable in a long running script that works @@ -197,35 +238,7 @@ class manager 'ext_state' => serialize($state), ); - $this->extensions[$name] = $extension_data; - $this->extensions[$name]['ext_path'] = $this->get_extension_path($extension_data['ext_name']); - ksort($this->extensions); - - $sql = 'SELECT COUNT(ext_name) as row_count - FROM ' . $this->extension_table . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $result = $this->db->sql_query($sql); - $count = $this->db->sql_fetchfield('row_count'); - $this->db->sql_freeresult($result); - - if ($count) - { - $sql = 'UPDATE ' . $this->extension_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - } - else - { - $sql = 'INSERT INTO ' . $this->extension_table . ' - ' . $this->db->sql_build_array('INSERT', $extension_data); - $this->db->sql_query($sql); - } - - if ($this->cache) - { - $this->cache->purge(); - } + $this->update_state($name, $extension_data, $this->is_configured($name) ? 'update' : 'insert'); if ($active) { @@ -272,46 +285,15 @@ class manager $extension = $this->get_extension($name); $state = $extension->disable_step($old_state); - - // continue until the state is false - if ($state !== false) - { - $extension_data = array( - 'ext_state' => serialize($state), - ); - $this->extensions[$name]['ext_state'] = serialize($state); - - $sql = 'UPDATE ' . $this->extension_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - - if ($this->cache) - { - $this->cache->purge(); - } - - return true; - } + $active = ($state !== false); $extension_data = array( - 'ext_active' => false, - 'ext_state' => serialize(false), + 'ext_active' => $active, + 'ext_state' => serialize($state), ); - $this->extensions[$name]['ext_active'] = false; - $this->extensions[$name]['ext_state'] = serialize(false); + $this->update_state($name, $extension_data); - $sql = 'UPDATE ' . $this->extension_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - - if ($this->cache) - { - $this->cache->purge(); - } - - return false; + return $active; } /** @@ -357,40 +339,16 @@ class manager $extension = $this->get_extension($name); $state = $extension->purge_step($old_state); + $purged = ($state === false); - // continue until the state is false - if ($state !== false) - { - $extension_data = array( - 'ext_state' => serialize($state), - ); - $this->extensions[$name]['ext_state'] = serialize($state); - - $sql = 'UPDATE ' . $this->extension_table . ' - SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); - - if ($this->cache) - { - $this->cache->purge(); - } - - return true; - } - - unset($this->extensions[$name]); - - $sql = 'DELETE FROM ' . $this->extension_table . " - WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; - $this->db->sql_query($sql); + $extension_data = array( + 'ext_state' => serialize($state), + ); - if ($this->cache) - { - $this->cache->purge(); - } + $this->update_state($name, $extension_data, $purged ? 'delete' : 'update'); - return false; + // continue until the state is false + return !$purged; } /** diff --git a/phpBB/phpbb/feed/controller/feed.php b/phpBB/phpbb/feed/controller/feed.php index c0d7bc72ec..7826d19042 100644 --- a/phpBB/phpbb/feed/controller/feed.php +++ b/phpBB/phpbb/feed/controller/feed.php @@ -308,14 +308,13 @@ class feed * Event to modify the feed row * * @event core.feed_modify_feed_row - * @var int forum_id Forum ID - * @var string mode Feeds mode (forums|topics|topics_new|topics_active|news) + * @var feed_interface feed Feed instance * @var array row Array with feed data - * @var int topic_id Topic ID * * @since 3.1.10-RC1 + * @changed 3.3.0 Replace forum_id, mode, topic_id with feed instance */ - $vars = array('forum_id', 'mode', 'row', 'topic_id'); + $vars = array('feed', 'row'); extract($this->phpbb_dispatcher->trigger_event('core.feed_modify_feed_row', compact($vars))); // BBCode options to correctly disable urls, smilies, bbcode... diff --git a/phpBB/phpbb/feed/topics_active.php b/phpBB/phpbb/feed/topics_active.php index ea9ee97b9d..ee7fe177f5 100644 --- a/phpBB/phpbb/feed/topics_active.php +++ b/phpBB/phpbb/feed/topics_active.php @@ -17,7 +17,7 @@ namespace phpbb\feed; * Active Topics feed * * This will give you the last {$this->num_items} topics - * with replies made withing the last {$this->sort_days} days + * with replies made within the last {$this->sort_days} days * including the last post. */ class topics_active extends topic_base diff --git a/phpBB/phpbb/files/filespec.php b/phpBB/phpbb/files/filespec.php index 6847bca4cb..1e6771a3a4 100644 --- a/phpBB/phpbb/files/filespec.php +++ b/phpBB/phpbb/files/filespec.php @@ -420,7 +420,7 @@ class filespec return false; } - $upload_mode = ($this->php_ini->getBool('open_basedir') || $this->php_ini->getBool('safe_mode')) ? 'move' : 'copy'; + $upload_mode = ($this->php_ini->getBool('open_basedir')) ? 'move' : 'copy'; $upload_mode = ($this->local) ? 'local' : $upload_mode; $this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname); diff --git a/phpBB/phpbb/filesystem.php b/phpBB/phpbb/filesystem.php index af56d78845..6ac9459331 100644 --- a/phpBB/phpbb/filesystem.php +++ b/phpBB/phpbb/filesystem.php @@ -14,7 +14,7 @@ namespace phpbb; /** - * @deprecated 3.2.0-dev (To be removed 3.3.0) use \phpbb\filesystem\filesystem instead + * @deprecated 3.2.0-dev (To be removed 4.0.0) use \phpbb\filesystem\filesystem instead */ class filesystem extends \phpbb\filesystem\filesystem { diff --git a/phpBB/phpbb/filesystem/filesystem.php b/phpBB/phpbb/filesystem/filesystem.php index c5be284d8c..9acead0876 100644 --- a/phpBB/phpbb/filesystem/filesystem.php +++ b/phpBB/phpbb/filesystem/filesystem.php @@ -67,7 +67,7 @@ class filesystem implements filesystem_interface $error = trim($e->getMessage()); $file = substr($error, strrpos($error, ' ')); - throw new filesystem_exception('CANNOT_CHANGE_FILE_GROUP', $file, array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_CHANGE_FILE_GROUP', $file, array(), $e); } } @@ -124,14 +124,14 @@ class filesystem implements filesystem_interface { if (true !== @chmod($file, $dir_perm)) { - throw new filesystem_exception('CANNOT_CHANGE_FILE_PERMISSIONS', $file, array()); + throw new filesystem_exception('FILESYSTEM_CANNOT_CHANGE_FILE_PERMISSIONS', $file, array()); } } else if (is_file($file)) { if (true !== @chmod($file, $file_perm)) { - throw new filesystem_exception('CANNOT_CHANGE_FILE_PERMISSIONS', $file, array()); + throw new filesystem_exception('FILESYSTEM_CANNOT_CHANGE_FILE_PERMISSIONS', $file, array()); } } } @@ -153,7 +153,7 @@ class filesystem implements filesystem_interface $error = trim($e->getMessage()); $file = substr($error, strrpos($error, ' ')); - throw new filesystem_exception('CANNOT_CHANGE_FILE_GROUP', $file, array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_CHANGE_FILE_GROUP', $file, array(), $e); } } @@ -195,7 +195,7 @@ class filesystem implements filesystem_interface } catch (\Symfony\Component\Filesystem\Exception\IOException $e) { - throw new filesystem_exception('CANNOT_COPY_FILES', '', array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_COPY_FILES', '', array(), $e); } } @@ -210,7 +210,7 @@ class filesystem implements filesystem_interface } catch (\Symfony\Component\Filesystem\Exception\IOException $e) { - throw new filesystem_exception('CANNOT_DUMP_FILE', $filename, array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_DUMP_FILE', $filename, array(), $e); } } @@ -322,7 +322,7 @@ class filesystem implements filesystem_interface $msg = $e->getMessage(); $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"')); - throw new filesystem_exception('CANNOT_MIRROR_DIRECTORY', $filename, array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_MIRROR_DIRECTORY', $filename, array(), $e); } } @@ -340,7 +340,7 @@ class filesystem implements filesystem_interface $msg = $e->getMessage(); $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"')); - throw new filesystem_exception('CANNOT_CREATE_DIRECTORY', $filename, array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_CREATE_DIRECTORY', $filename, array(), $e); } } @@ -525,7 +525,7 @@ class filesystem implements filesystem_interface $error = trim($e->getMessage()); $file = substr($error, strrpos($error, ' ')); - throw new filesystem_exception('CANNOT_DELETE_FILES', $file, array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_DELETE_FILES', $file, array(), $e); } } @@ -543,7 +543,7 @@ class filesystem implements filesystem_interface $msg = $e->getMessage(); $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"')); - throw new filesystem_exception('CANNOT_RENAME_FILE', $filename, array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_RENAME_FILE', $filename, array(), $e); } } @@ -558,7 +558,7 @@ class filesystem implements filesystem_interface } catch (\Symfony\Component\Filesystem\Exception\IOException $e) { - throw new filesystem_exception('CANNOT_CREATE_SYMLINK', $origin_dir, array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_CREATE_SYMLINK', $origin_dir, array(), $e); } } @@ -578,7 +578,7 @@ class filesystem implements filesystem_interface $error = trim($e->getMessage()); $file = substr($error, strrpos($error, ' ')); - throw new filesystem_exception('CANNOT_TOUCH_FILES', $file, array(), $e); + throw new filesystem_exception('FILESYSTEM_CANNOT_TOUCH_FILES', $file, array(), $e); } } diff --git a/phpBB/phpbb/filesystem/filesystem_interface.php b/phpBB/phpbb/filesystem/filesystem_interface.php index 1093be2499..39ae0c3954 100644 --- a/phpBB/phpbb/filesystem/filesystem_interface.php +++ b/phpBB/phpbb/filesystem/filesystem_interface.php @@ -204,7 +204,7 @@ interface filesystem_interface * This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions. * The function determines owner and group from common.php file and sets the same to the provided file. * The function uses bit fields to build the permissions. - * The function sets the appropiate execute bit on directories. + * The function sets the appropriate execute bit on directories. * * Supported constants representing bit fields are: * diff --git a/phpBB/phpbb/finder.php b/phpBB/phpbb/finder.php index 1f1d931880..0a2b67a034 100644 --- a/phpBB/phpbb/finder.php +++ b/phpBB/phpbb/finder.php @@ -80,7 +80,7 @@ class finder /** * Set the array of extensions * - * @param array $extensions A list of extensions that should be searched aswell + * @param array $extensions A list of extensions that should be searched as well * @param bool $replace_list Should the list be emptied before adding the extensions * @return \phpbb\finder This object for chaining calls */ @@ -237,7 +237,7 @@ class finder } /** - * Removes occurances of /./ and makes sure path ends without trailing slash + * Removes occurrences of /./ and makes sure path ends without trailing slash * * @param string $directory A directory pattern * @return string A cleaned up directory pattern diff --git a/phpBB/phpbb/help/controller/bbcode.php b/phpBB/phpbb/help/controller/bbcode.php index e16f99023d..560b0c02ce 100644 --- a/phpBB/phpbb/help/controller/bbcode.php +++ b/phpBB/phpbb/help/controller/bbcode.php @@ -25,6 +25,11 @@ class bbcode extends controller { $this->language->add_lang('help/bbcode'); + $this->template->assign_block_vars('navlinks', array( + 'BREADCRUMB_NAME' => $this->language->lang('BBCODE_GUIDE'), + 'U_BREADCRUMB' => $this->helper->route('phpbb_help_bbcode_controller'), + )); + $this->manager->add_block( 'HELP_BBCODE_BLOCK_INTRO', false, diff --git a/phpBB/phpbb/help/controller/faq.php b/phpBB/phpbb/help/controller/faq.php index 5e45cfe667..0f63be5b56 100644 --- a/phpBB/phpbb/help/controller/faq.php +++ b/phpBB/phpbb/help/controller/faq.php @@ -25,6 +25,11 @@ class faq extends controller { $this->language->add_lang('help/faq'); + $this->template->assign_block_vars('navlinks', array( + 'BREADCRUMB_NAME' => $this->language->lang('FAQ_EXPLAIN'), + 'U_BREADCRUMB' => $this->helper->route('phpbb_help_faq_controller'), + )); + $this->manager->add_block( 'HELP_FAQ_BLOCK_LOGIN', false, diff --git a/phpBB/phpbb/install/controller/helper.php b/phpBB/phpbb/install/controller/helper.php index ff7e691224..f61c7de41f 100644 --- a/phpBB/phpbb/install/controller/helper.php +++ b/phpBB/phpbb/install/controller/helper.php @@ -267,7 +267,7 @@ class helper 'L_SKIP' => $this->language->lang('SKIP'), 'PAGE_TITLE' => $this->language->lang($page_title), 'T_IMAGE_PATH' => $this->path_helper->get_web_root_path() . $path . 'images', - 'T_JQUERY_LINK' => $this->path_helper->get_web_root_path() . $path . '../assets/javascript/jquery.min.js', + 'T_JQUERY_LINK' => $this->path_helper->get_web_root_path() . $path . '../assets/javascript/jquery-3.4.1.min.js', 'T_TEMPLATE_PATH' => $this->path_helper->get_web_root_path() . $path . 'style', 'T_ASSETS_PATH' => $this->path_helper->get_web_root_path() . $path . '../assets', diff --git a/phpBB/phpbb/install/helper/container_factory.php b/phpBB/phpbb/install/helper/container_factory.php index 9e372fecde..655760270a 100644 --- a/phpBB/phpbb/install/helper/container_factory.php +++ b/phpBB/phpbb/install/helper/container_factory.php @@ -181,7 +181,7 @@ class container_factory $this->request->disable_super_globals(); } - // Get compatibilty globals and constants + // Get compatibility globals and constants $this->update_helper->include_file('includes/compatibility_globals.' . $this->php_ext); register_compatibility_globals(); 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/helper/iohandler/iohandler_interface.php b/phpBB/phpbb/install/helper/iohandler/iohandler_interface.php index 440748901c..3df9a91936 100644 --- a/phpBB/phpbb/install/helper/iohandler/iohandler_interface.php +++ b/phpBB/phpbb/install/helper/iohandler/iohandler_interface.php @@ -31,7 +31,7 @@ interface iohandler_interface * @param string $name Name of the input variable to obtain * @param mixed $default A default value that is returned if the variable was not set. * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters + * @param bool $multibyte If $default is a string this parameter has to be true if the variable may contain any UTF-8 characters * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks * * @return mixed Value of the input variable diff --git a/phpBB/phpbb/install/installer_configuration.php b/phpBB/phpbb/install/installer_configuration.php index 805140338c..dfafc40b4b 100644 --- a/phpBB/phpbb/install/installer_configuration.php +++ b/phpBB/phpbb/install/installer_configuration.php @@ -48,9 +48,9 @@ class installer_configuration implements ConfigurationInterface ->cannotBeEmpty() ->end() ->scalarNode('description') - ->defaultValue('My amazing new phpBB board') - ->cannotBeEmpty() - ->end() + ->defaultValue('My amazing new phpBB board') + ->cannotBeEmpty() + ->end() ->end() ->end() ->arrayNode('database') @@ -128,12 +128,11 @@ class installer_configuration implements ConfigurationInterface ->integerNode('server_port') ->defaultValue(80) ->min(1) - ->cannotBeEmpty() ->end() ->scalarNode('script_path') ->defaultValue('/') ->cannotBeEmpty() - ->end() + ->end() ->end() ->end() ->arrayNode('extensions') diff --git a/phpBB/phpbb/install/module/install_database/task/add_config_settings.php b/phpBB/phpbb/install/module/install_database/task/add_config_settings.php index ba439609ff..91d7884aa4 100644 --- a/phpBB/phpbb/install/module/install_database/task/add_config_settings.php +++ b/phpBB/phpbb/install/module/install_database/task/add_config_settings.php @@ -245,7 +245,6 @@ class add_config_settings extends \phpbb\install\task_base user_lang = '" . $this->db->sql_escape($this->install_config->get('user_language', 'en')) . "', user_email='" . $this->db->sql_escape($this->install_config->get('board_email')) . "', user_dateformat='" . $this->db->sql_escape($this->language->lang('default_dateformat')) . "', - user_email_hash = " . $this->db->sql_escape(phpbb_email_hash($this->install_config->get('board_email'))) . ", username_clean = '" . $this->db->sql_escape(utf8_clean_string($this->install_config->get('admin_name'))) . "' WHERE username = 'Admin'", 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/install/module/install_filesystem/task/create_config_file.php b/phpBB/phpbb/install/module/install_filesystem/task/create_config_file.php index 5bc425b929..900d5b94bc 100644 --- a/phpBB/phpbb/install/module/install_filesystem/task/create_config_file.php +++ b/phpBB/phpbb/install/module/install_filesystem/task/create_config_file.php @@ -165,7 +165,7 @@ class create_config_file extends \phpbb\install\task_base protected function get_config_data($debug = false, $debug_container = false, $environment = null) { $config_content = "<?php\n"; - $config_content .= "// phpBB 3.2.x auto-generated configuration file\n// Do not change anything in this file!\n"; + $config_content .= "// phpBB 3.3.x auto-generated configuration file\n// Do not change anything in this file!\n"; $dbms = $this->install_config->get('dbms'); $db_driver = $this->db_helper->get_available_dbms($dbms); @@ -191,7 +191,6 @@ class create_config_file extends \phpbb\install\task_base } $config_content .= "\n@define('PHPBB_INSTALLED', true);\n"; - $config_content .= "// @define('PHPBB_DISPLAY_LOAD_TIME', true);\n"; if ($environment) { diff --git a/phpBB/phpbb/install/module/requirements/task/check_server_environment.php b/phpBB/phpbb/install/module/requirements/task/check_server_environment.php index 29f9777747..4607ce9ec2 100644 --- a/phpBB/phpbb/install/module/requirements/task/check_server_environment.php +++ b/phpBB/phpbb/install/module/requirements/task/check_server_environment.php @@ -98,7 +98,7 @@ class check_server_environment extends \phpbb\install\task_base { $php_version = PHP_VERSION; - if (version_compare($php_version, '5.4') < 0) + if (version_compare($php_version, '7.1') < 0) { $this->response_helper->add_error_message('PHP_VERSION_REQD', 'PHP_VERSION_REQD_EXPLAIN'); diff --git a/phpBB/phpbb/install/module_base.php b/phpBB/phpbb/install/module_base.php index 93c10bd656..4464a89716 100644 --- a/phpBB/phpbb/install/module_base.php +++ b/phpBB/phpbb/install/module_base.php @@ -131,7 +131,7 @@ abstract class module_base implements module_interface $name, )); - $this->install_config->increment_current_task_progress($this->task_step_count[$name]); + $this->install_config->increment_current_task_progress($this->task_step_count[$name] ?? false); } else { diff --git a/phpBB/phpbb/language/language_file_loader.php b/phpBB/phpbb/language/language_file_loader.php index b6816afd16..2910dd3c4a 100644 --- a/phpBB/phpbb/language/language_file_loader.php +++ b/phpBB/phpbb/language/language_file_loader.php @@ -151,6 +151,7 @@ class language_file_loader * * @param string $path Path to language directory * @param string $filename Filename to load language strings from + * @param array $locales Array containing language fallback options * * @return string Relative path to language file * diff --git a/phpBB/phpbb/lock/db.php b/phpBB/phpbb/lock/db.php index 85ba9a7aa3..eea919f8f7 100644 --- a/phpBB/phpbb/lock/db.php +++ b/phpBB/phpbb/lock/db.php @@ -110,6 +110,13 @@ class db // process we failed to acquire the lock. $this->locked = $this->config->set_atomic($this->config_name, $lock_value, $this->unique_id, false); + if ($this->locked == true) + { + if ($this->config->ensure_lock($this->config_name, $this->unique_id)) + { + return true; + } + } return $this->locked; } diff --git a/phpBB/phpbb/lock/flock.php b/phpBB/phpbb/lock/flock.php index df88e1490a..af051afb56 100644 --- a/phpBB/phpbb/lock/flock.php +++ b/phpBB/phpbb/lock/flock.php @@ -101,7 +101,10 @@ class flock if ($this->lock_fp) { - @flock($this->lock_fp, LOCK_EX); + if (!@flock($this->lock_fp, LOCK_EX)) + { + throw new \phpbb\exception\http_exception(500, 'Failure while aqcuiring locks.'); + } } return (bool) $this->lock_fp; diff --git a/phpBB/phpbb/mimetype/guesser.php b/phpBB/phpbb/mimetype/guesser.php index 8baa77089b..f8cbffe8f5 100644 --- a/phpBB/phpbb/mimetype/guesser.php +++ b/phpBB/phpbb/mimetype/guesser.php @@ -76,7 +76,7 @@ class guesser * should be used first and vice versa. usort() orders the array values * from low to high depending on what the comparison function returns * to it. Return value should be smaller than 0 if value a is smaller - * than value b. This has been reversed in the comparision function in + * than value b. This has been reversed in the comparison function in * order to sort the guessers from high to low. * Method has been set to public in order to allow proper testing. * diff --git a/phpBB/phpbb/notification/type/approve_post.php b/phpBB/phpbb/notification/type/approve_post.php index e4b111e4da..139b5fabb9 100644 --- a/phpBB/phpbb/notification/type/approve_post.php +++ b/phpBB/phpbb/notification/type/approve_post.php @@ -78,10 +78,7 @@ class approve_post extends \phpbb\notification\type\post 'ignore_users' => array(), ), $options); - $users = array(); - $users[$post['poster_id']] = $this->notification_manager->get_default_methods(); - - return $this->get_authorised_recipients(array_keys($users), $post['forum_id'], array_merge($options, array( + return $this->get_authorised_recipients(array($post['poster_id']), $post['forum_id'], array_merge($options, array( 'item_type' => static::$notification_option['id'], ))); } @@ -94,7 +91,7 @@ class approve_post extends \phpbb\notification\type\post * * @param array $post Post data from submit_post * @param array $notify_users Notify users list - * Formated from find_users_for_notification() + * Formatted from find_users_for_notification() * @return array Whatever you want to send to create_insert_array(). */ public function pre_create_insert_array($post, $notify_users) diff --git a/phpBB/phpbb/notification/type/approve_topic.php b/phpBB/phpbb/notification/type/approve_topic.php index f8a3fdec6f..0c343646ee 100644 --- a/phpBB/phpbb/notification/type/approve_topic.php +++ b/phpBB/phpbb/notification/type/approve_topic.php @@ -78,10 +78,7 @@ class approve_topic extends \phpbb\notification\type\topic 'ignore_users' => array(), ), $options); - $users = array(); - $users[$post['poster_id']] = $this->notification_manager->get_default_methods(); - - return $this->get_authorised_recipients(array_keys($users), $post['forum_id'], array_merge($options, array( + return $this->get_authorised_recipients(array($post['poster_id']), $post['forum_id'], array_merge($options, array( 'item_type' => static::$notification_option['id'], ))); } @@ -94,7 +91,7 @@ class approve_topic extends \phpbb\notification\type\topic * * @param array $post Post data from submit_post * @param array $notify_users Notify users list - * Formated from find_users_for_notification() + * Formatted from find_users_for_notification() * @return array Whatever you want to send to create_insert_array(). */ public function pre_create_insert_array($post, $notify_users) diff --git a/phpBB/phpbb/notification/type/base.php b/phpBB/phpbb/notification/type/base.php index 77ed7f2b09..e4600add11 100644 --- a/phpBB/phpbb/notification/type/base.php +++ b/phpBB/phpbb/notification/type/base.php @@ -336,7 +336,7 @@ abstract class base implements \phpbb\notification\type\type_interface } /** - * Get the reference of the notifcation (fall back) + * Get the reference of the notification (fall back) * * @return string */ @@ -356,7 +356,7 @@ abstract class base implements \phpbb\notification\type\type_interface } /** - * Get the reason for the notifcation (fall back) + * Get the reason for the notification (fall back) * * @return string */ diff --git a/phpBB/phpbb/notification/type/post.php b/phpBB/phpbb/notification/type/post.php index 254f4c07b3..f0e938d3ce 100644 --- a/phpBB/phpbb/notification/type/post.php +++ b/phpBB/phpbb/notification/type/post.php @@ -352,7 +352,7 @@ class post extends \phpbb\notification\type\base * * @param array $post Post data from submit_post * @param array $notify_users Notify users list - * Formated from find_users_for_notification() + * Formatted from find_users_for_notification() * @return array Whatever you want to send to create_insert_array(). */ public function pre_create_insert_array($post, $notify_users) diff --git a/phpBB/phpbb/notification/type/topic.php b/phpBB/phpbb/notification/type/topic.php index 5c42afa8c8..2535cdaed6 100644 --- a/phpBB/phpbb/notification/type/topic.php +++ b/phpBB/phpbb/notification/type/topic.php @@ -256,7 +256,7 @@ class topic extends \phpbb\notification\type\base * * @param array $post Post data from submit_post * @param array $notify_users Notify users list - * Formated from find_users_for_notification() + * Formatted from find_users_for_notification() * @return array Whatever you want to send to create_insert_array(). */ public function pre_create_insert_array($post, $notify_users) diff --git a/phpBB/phpbb/notification/type/type_interface.php b/phpBB/phpbb/notification/type/type_interface.php index f9f832bdda..ed77335ce5 100644 --- a/phpBB/phpbb/notification/type/type_interface.php +++ b/phpBB/phpbb/notification/type/type_interface.php @@ -170,7 +170,7 @@ interface type_interface * * @param array $type_data The type specific data * @param array $notify_users Notify users list - * Formated from find_users_for_notification() + * Formatted from find_users_for_notification() * @return array Whatever you want to send to create_insert_array(). */ public function pre_create_insert_array($type_data, $notify_users); diff --git a/phpBB/phpbb/passwords/driver/argon2i.php b/phpBB/phpbb/passwords/driver/argon2i.php new file mode 100644 index 0000000000..bf4d6ec33a --- /dev/null +++ b/phpBB/phpbb/passwords/driver/argon2i.php @@ -0,0 +1,86 @@ +<?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\passwords\driver; + +class argon2i extends base_native +{ + /** @var int Maximum memory (in bytes) that may be used to compute the Argon2 hash */ + protected $memory_cost; + + /** @var int Number of threads to use for computing the Argon2 hash */ + protected $threads; + + /** @var int Maximum amount of time it may take to compute the Argon2 hash */ + protected $time_cost; + + /** + * Constructor of passwords driver object + * + * @param \phpbb\config\config $config phpBB config + * @param \phpbb\passwords\driver\helper $helper Password driver helper + * @param int $memory_cost Maximum memory (optional) + * @param int $threads Number of threads to use (optional) + * @param int $time_cost Maximum amount of time (optional) + */ + public function __construct(\phpbb\config\config $config, helper $helper, $memory_cost = 1024, $threads = 2, $time_cost = 2) + { + parent::__construct($config, $helper); + + // Workaround to prevent "Use of undefined constant" warning on some unsupported PHP installations + if (!defined('PASSWORD_ARGON2I')) + { + define('PASSWORD_ARGON2_DEFAULT_MEMORY_COST', 1024); + define('PASSWORD_ARGON2_DEFAULT_TIME_COST', 2); + define('PASSWORD_ARGON2_DEFAULT_THREADS', 1); + } + + /** + * For Sodium implementation of argon2 algorithm (since PHP 7.4), set special value of 1 for "threads" cost factor + * See https://wiki.php.net/rfc/sodium.argon.hash and PHPBB3-16266 + * Don't allow cost factors to be below default settings where possible + */ + $this->memory_cost = max($memory_cost, PASSWORD_ARGON2_DEFAULT_MEMORY_COST); + $this->time_cost = max($time_cost, PASSWORD_ARGON2_DEFAULT_TIME_COST); + $this->threads = (defined('PASSWORD_ARGON2_PROVIDER') && PASSWORD_ARGON2_PROVIDER == 'sodium') ? + PASSWORD_ARGON2_DEFAULT_THREADS : max($threads, PASSWORD_ARGON2_DEFAULT_THREADS); + } + + /** + * {@inheritdoc} + */ + public function get_algo_name() + { + return 'PASSWORD_ARGON2I'; + } + + /** + * {@inheritdoc} + */ + public function get_options() + { + return [ + 'memory_cost' => $this->memory_cost, + 'time_cost' => $this->time_cost, + 'threads' => $this->threads + ]; + } + + /** + * {@inheritdoc} + */ + public function get_prefix() + { + return '$argon2i$'; + } +} diff --git a/phpBB/phpbb/passwords/driver/argon2id.php b/phpBB/phpbb/passwords/driver/argon2id.php new file mode 100644 index 0000000000..9e4b08bbb9 --- /dev/null +++ b/phpBB/phpbb/passwords/driver/argon2id.php @@ -0,0 +1,33 @@ +<?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\passwords\driver; + +class argon2id extends argon2i +{ + /** + * {@inheritdoc} + */ + public function get_algo_name() + { + return 'PASSWORD_ARGON2ID'; + } + + /** + * {@inheritdoc} + */ + public function get_prefix() + { + return '$argon2id$'; + } +} diff --git a/phpBB/phpbb/passwords/driver/base_native.php b/phpBB/phpbb/passwords/driver/base_native.php new file mode 100644 index 0000000000..87498327f9 --- /dev/null +++ b/phpBB/phpbb/passwords/driver/base_native.php @@ -0,0 +1,75 @@ +<?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\passwords\driver; + +abstract class base_native extends base +{ + /** + * Return the constant name for this driver's algorithm + * + * @link https://www.php.net/manual/en/password.constants.php + * + * @return string + */ + abstract public function get_algo_name(); + + /** + * Return the options set for this driver instance + * + * @return array + */ + abstract public function get_options(); + + /** + * {@inheritdoc} + */ + public function check($password, $hash, $user_row = []) + { + return password_verify($password, $hash); + } + + /** + * Return the value for this driver's algorithm + * + * @return integer + */ + public function get_algo_value() + { + return constant($this->get_algo_name()); + } + + /** + * {@inheritdoc} + */ + public function hash($password) + { + return password_hash($password, $this->get_algo_value(), $this->get_options()); + } + + /** + * {@inheritdoc} + */ + public function is_supported() + { + return defined($this->get_algo_name()) && function_exists('password_hash') && function_exists('password_needs_rehash') && function_exists('password_verify'); + } + + /** + * {@inheritdoc} + */ + public function needs_rehash($hash) + { + return password_needs_rehash($hash, $this->get_algo_value(), $this->get_options()); + } +} diff --git a/phpBB/phpbb/passwords/manager.php b/phpBB/phpbb/passwords/manager.php index fad76a9fe5..54e6dce4be 100644 --- a/phpBB/phpbb/passwords/manager.php +++ b/phpBB/phpbb/passwords/manager.php @@ -250,7 +250,7 @@ class manager /** * Check supplied password against hash and set convert_flag if password - * needs to be converted to different format (preferrably newer one) + * needs to be converted to different format (preferably newer one) * * @param string $password Password that should be checked * @param string $hash Stored hash diff --git a/phpBB/phpbb/plupload/plupload.php b/phpBB/phpbb/plupload/plupload.php index 5a5b8a1874..80d7e914db 100644 --- a/phpBB/phpbb/plupload/plupload.php +++ b/phpBB/phpbb/plupload/plupload.php @@ -325,6 +325,8 @@ class plupload * by PHP and actually exists, if not, it generates an error * * @param string $form_name The name of the file in the form data + * @param int $chunk Chunk number + * @param string $file_path File path * * @return null */ diff --git a/phpBB/phpbb/report/report_handler.php b/phpBB/phpbb/report/report_handler.php index 854318c559..97acc1763e 100644 --- a/phpBB/phpbb/report/report_handler.php +++ b/phpBB/phpbb/report/report_handler.php @@ -51,7 +51,7 @@ abstract class report_handler implements report_handler_interface protected $report_data; /** - * Construtor + * Constructor * * @param \phpbb\db\driver\driver_interface $db * @param \phpbb\event\dispatcher_interface $dispatcher diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php index a0267d1370..4d7bc9ea48 100644 --- a/phpBB/phpbb/request/request.php +++ b/phpBB/phpbb/request/request.php @@ -179,7 +179,7 @@ class request implements \phpbb\request\request_interface * then specifying array("var", 1) as the name will return "a". * @param mixed $default A default value that is returned if the variable was not set. * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters + * @param bool $multibyte If $default is a string this parameter has to be true if the variable may contain any UTF-8 characters * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global * Specifies which super global should be used @@ -203,7 +203,7 @@ class request implements \phpbb\request\request_interface * then specifying array("var", 1) as the name will return "a". * @param mixed $default A default value that is returned if the variable was not set. * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters + * @param bool $multibyte If $default is a string this parameter has to be true if the variable may contain any UTF-8 characters * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global * Specifies which super global should be used @@ -268,7 +268,7 @@ class request implements \phpbb\request\request_interface * whatever). * * @param string|array $var_name See \phpbb\request\request_interface::variable - * @param mixed $Default See \phpbb\request\request_interface::variable + * @param mixed $default See \phpbb\request\request_interface::variable * * @return mixed The server variable value. */ @@ -395,7 +395,7 @@ class request implements \phpbb\request\request_interface * then specifying array("var", 1) as the name will return "a". * @param mixed $default A default value that is returned if the variable was not set. * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters + * @param bool $multibyte If $default is a string this parameter has to be true if the variable may contain any UTF-8 characters * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global * Specifies which super global should be used diff --git a/phpBB/phpbb/request/request_interface.php b/phpBB/phpbb/request/request_interface.php index 3bfa8bb424..a1fbf0ae45 100644 --- a/phpBB/phpbb/request/request_interface.php +++ b/phpBB/phpbb/request/request_interface.php @@ -54,7 +54,7 @@ interface request_interface * then specifying array("var", 1) as the name will return "a". * @param mixed $default A default value that is returned if the variable was not set. * This function will always return a value of the same type as the default. - * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters + * @param bool $multibyte If $default is a string this parameter has to be true if the variable may contain any UTF-8 characters * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global * Specifies which super global should be used @@ -104,7 +104,7 @@ interface request_interface * * @return mixed The header value. */ - public function header($var_name, $default = ''); + public function header($header_name, $default = ''); /** * Checks whether a certain variable was sent via POST. diff --git a/phpBB/phpbb/request/type_cast_helper.php b/phpBB/phpbb/request/type_cast_helper.php index 912494998d..39d5908fd3 100644 --- a/phpBB/phpbb/request/type_cast_helper.php +++ b/phpBB/phpbb/request/type_cast_helper.php @@ -106,7 +106,8 @@ class type_cast_helper implements \phpbb\request\type_cast_helper_interface return; } - list($default_key, $default_value) = each($default); + $default_key = key($default); + $default_value = current($default); $key_type = gettype($default_key); $_var = $var; diff --git a/phpBB/phpbb/search/fulltext_mysql.php b/phpBB/phpbb/search/fulltext_mysql.php index 1105d0892f..42ac6eaba2 100644 --- a/phpBB/phpbb/search/fulltext_mysql.php +++ b/phpBB/phpbb/search/fulltext_mysql.php @@ -83,7 +83,7 @@ class fulltext_mysql extends \phpbb\search\base * @param string $phpEx PHP file extension * @param \phpbb\auth\auth $auth Auth object * @param \phpbb\config\config $config Config object - * @param \phpbb\db\driver\driver_interface Database object + * @param \phpbb\db\driver\driver_interface $db Database object * @param \phpbb\user $user User object * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object */ @@ -150,11 +150,11 @@ class fulltext_mysql extends \phpbb\search\base /** * Checks for correct MySQL version and stores min/max word length in the config * - * @return string|bool Language key of the error/incompatiblity occurred + * @return string|bool Language key of the error/incompatibility occurred */ 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 c83de75eed..23460d3381 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -109,6 +109,12 @@ class fulltext_native extends \phpbb\search\base * Initialises the fulltext_native search backend with min/max word length * * @param boolean|string &$error is passed by reference and should either be set to false on success or an error message on failure + * @param string $phpbb_root_path phpBB root path + * @param string $phpEx PHP file extension + * @param \phpbb\auth\auth $auth Auth object + * @param \phpbb\config\config $config Config object + * @param \phpbb\db\driver\driver_interface $db Database object + * @param \phpbb\user $user User object * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object */ public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher) @@ -351,7 +357,7 @@ class fulltext_native extends \phpbb\search\base $this->db->sql_freeresult($result); } - // Handle +, - without preceeding whitespace character + // Handle +, - without preceding whitespace character $match = array('#(\S)\+#', '#(\S)-#'); $replace = array('$1 +', '$1 +'); @@ -782,6 +788,8 @@ class fulltext_native extends \phpbb\search\base $must_not_contain_ids = $this->must_not_contain_ids; $must_contain_ids = $this->must_contain_ids; + $sql_sort_table = $sql_sort_join = $sql_match = $sql_match_where = $sql_sort = ''; + /** * Allow changing the query used for counting for posts using fulltext_native * @@ -889,7 +897,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 +1191,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_postgres.php b/phpBB/phpbb/search/fulltext_postgres.php index 2f387e791e..6241f21fcf 100644 --- a/phpBB/phpbb/search/fulltext_postgres.php +++ b/phpBB/phpbb/search/fulltext_postgres.php @@ -173,7 +173,7 @@ class fulltext_postgres extends \phpbb\search\base /** * Checks for correct PostgreSQL version and stores min/max word length in the config * - * @return string|bool Language key of the error/incompatiblity occurred + * @return string|bool Language key of the error/incompatibility occurred */ public function init() { diff --git a/phpBB/phpbb/search/fulltext_sphinx.php b/phpBB/phpbb/search/fulltext_sphinx.php index 227fbd3fd6..d2e12fd7c0 100644 --- a/phpBB/phpbb/search/fulltext_sphinx.php +++ b/phpBB/phpbb/search/fulltext_sphinx.php @@ -18,7 +18,7 @@ define('SPHINX_CONNECT_RETRIES', 3); define('SPHINX_CONNECT_WAIT_TIME', 300); /** -* Fulltext search based on the sphinx search deamon +* Fulltext search based on the sphinx search daemon */ class fulltext_sphinx { @@ -210,11 +210,11 @@ class fulltext_sphinx /** * Checks permissions and paths, if everything is correct it generates the config file * - * @return string|bool Language key of the error/incompatiblity encountered, or false if successful + * @return string|bool Language key of the error/incompatibility encountered, or false if successful */ 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/session.php b/phpBB/phpbb/session.php index cc5a1b8f8f..6851bc8188 100644 --- a/phpBB/phpbb/session.php +++ b/phpBB/phpbb/session.php @@ -250,8 +250,7 @@ class session $ips = explode(' ', $this->forwarded_for); foreach ($ips as $ip) { - // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly - if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) + if (!filter_var($ip, FILTER_VALIDATE_IP)) { // contains invalid data, don't use the forwarded for header $this->forwarded_for = ''; @@ -311,49 +310,17 @@ class session foreach ($ips as $ip) { - if (function_exists('phpbb_ip_normalise')) - { - // Normalise IP address - $ip = phpbb_ip_normalise($ip); - - if (empty($ip)) - { - // IP address is invalid. - break; - } - - // IP address is valid. - $this->ip = $ip; - - // Skip legacy code. - continue; - } - - if (preg_match(get_preg_expression('ipv4'), $ip)) - { - $this->ip = $ip; - } - else if (preg_match(get_preg_expression('ipv6'), $ip)) - { - // Quick check for IPv4-mapped address in IPv6 - if (stripos($ip, '::ffff:') === 0) - { - $ipv4 = substr($ip, 7); + // Normalise IP address + $ip = phpbb_ip_normalise($ip); - if (preg_match(get_preg_expression('ipv4'), $ipv4)) - { - $ip = $ipv4; - } - } - - $this->ip = $ip; - } - else + if ($ip === false) { - // We want to use the last valid address in the chain - // Leave foreach loop when address is invalid + // IP address is invalid. break; } + + // IP address is valid. + $this->ip = $ip; } $this->load = false; @@ -478,8 +445,8 @@ class session } else { - // Added logging temporarly to help debug bugs... - if (defined('DEBUG') && $this->data['user_id'] != ANONYMOUS) + // Added logging temporarily to help debug bugs... + if ($phpbb_container->getParameter('session.log_errors') && $this->data['user_id'] != ANONYMOUS) { if ($referer_valid) { @@ -987,72 +954,96 @@ class session { global $db, $config, $phpbb_container, $phpbb_dispatcher; - $batch_size = 10; - if (!$this->time_now) { $this->time_now = time(); } - // Firstly, delete guest sessions - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . ANONYMOUS . ' - AND session_time < ' . (int) ($this->time_now - $config['session_length']); - $db->sql_query($sql); + /** + * Get expired sessions for registered users, only most recent for each user + * Inner SELECT gets most recent expired sessions for unique session_user_id + * Outer SELECT gets data for them + */ + $sql_select = 'SELECT s1.session_page, s1.session_user_id, s1.session_time AS recent_time + FROM ' . SESSIONS_TABLE . ' AS s1 + INNER JOIN ( + SELECT session_user_id, MAX(session_time) AS recent_time + FROM ' . SESSIONS_TABLE . ' + WHERE session_time < ' . ($this->time_now - (int) $config['session_length']) . ' + AND session_user_id <> ' . ANONYMOUS . ' + GROUP BY session_user_id + ) AS s2 + ON s1.session_user_id = s2.session_user_id + AND s1.session_time = s2.recent_time'; + + switch ($db->get_sql_layer()) + { + case 'sqlite3': + if (phpbb_version_compare($db->sql_server_info(true), '3.8.3', '>=')) + { + // For SQLite versions 3.8.3+ which support Common Table Expressions (CTE) + $sql = "WITH s3 (session_page, session_user_id, session_time) AS ($sql_select) + UPDATE " . USERS_TABLE . ' + SET (user_lastpage, user_lastvisit) = (SELECT session_page, session_time FROM s3 WHERE session_user_id = user_id) + WHERE EXISTS (SELECT session_user_id FROM s3 WHERE session_user_id = user_id)'; + $db->sql_query($sql); - // Get expired sessions, only most recent for each user - $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time - FROM ' . SESSIONS_TABLE . ' - WHERE session_time < ' . ($this->time_now - $config['session_length']) . ' - GROUP BY session_user_id, session_page'; - $result = $db->sql_query_limit($sql, $batch_size); + break; + } - $del_user_id = array(); - $del_sessions = 0; + // No break, for SQLite versions prior to 3.8.3 and Oracle + case 'oracle': + $result = $db->sql_query($sql_select); + while ($row = $db->sql_fetchrow($result)) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' + WHERE user_id = " . (int) $row['session_user_id']; + $db->sql_query($sql); + } + $db->sql_freeresult($result); + break; - while ($row = $db->sql_fetchrow($result)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' - WHERE user_id = " . (int) $row['session_user_id']; - $db->sql_query($sql); + case 'mysqli': + $sql = 'UPDATE ' . USERS_TABLE . " u, + ($sql_select) s3 + SET u.user_lastvisit = s3.recent_time, u.user_lastpage = s3.session_page + WHERE u.user_id = s3.session_user_id"; + $db->sql_query($sql); + break; - $del_user_id[] = (int) $row['session_user_id']; - $del_sessions++; + default: + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_lastvisit = s3.recent_time, user_lastpage = s3.session_page + FROM ($sql_select) s3 + WHERE user_id = s3.session_user_id"; + $db->sql_query($sql); + break; } - $db->sql_freeresult($result); - if (count($del_user_id)) + // Delete all expired sessions + $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' + WHERE session_time < ' . ($this->time_now - (int) $config['session_length']); + $db->sql_query($sql); + + // Update gc timer + $config->set('session_last_gc', $this->time_now, false); + + if ($config['max_autologin_time']) { - // Delete expired sessions - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . ' - AND session_time < ' . ($this->time_now - $config['session_length']); + $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' + WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time'])); $db->sql_query($sql); } - if ($del_sessions < $batch_size) - { - // Less than 10 users, update gc timer ... else we want gc - // called again to delete other sessions - $config->set('session_last_gc', $this->time_now, false); - - if ($config['max_autologin_time']) - { - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time'])); - $db->sql_query($sql); - } - - // only called from CRON; should be a safe workaround until the infrastructure gets going - /* @var $captcha_factory \phpbb\captcha\factory */ - $captcha_factory = $phpbb_container->get('captcha.factory'); - $captcha_factory->garbage_collect($config['captcha_plugin']); + // only called from CRON; should be a safe workaround until the infrastructure gets going + /* @var \phpbb\captcha\factory $captcha_factory */ + $captcha_factory = $phpbb_container->get('captcha.factory'); + $captcha_factory->garbage_collect($config['captcha_plugin']); - $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']); - $db->sql_query($sql); - } + $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' + WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']); + $db->sql_query($sql); /** * Event to trigger extension on session_gc @@ -1362,7 +1353,7 @@ class session * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups) * * @author satmd (from the php manual) - * @param string $mode register/post - spamcop for example is ommitted for posting + * @param string $mode register/post - spamcop for example is omitted for posting * @param string|false $ip the IPv4 address to check * * @return false if ip is not blacklisted, else an array([checked server], [lookup]) @@ -1400,7 +1391,7 @@ class session foreach ($dnsbl_check as $dnsbl => $lookup) { - if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true) + if (checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true) { $info = array($dnsbl, $lookup . $ip); } @@ -1421,7 +1412,7 @@ class session /** * Check if URI is blacklisted - * This should be called only where absolutly necessary, for example on the submitted website field + * This should be called only where absolutely necessary, for example on the submitted website field * This function is not in use at the moment and is only included for testing purposes, it may not work at all! * This means it is untested at the moment and therefore commented out * @@ -1444,7 +1435,7 @@ class session { // One problem here... the return parameter for the "windows" method is different from what // we expect... this may render this check useless... - if (phpbb_checkdnsrr($uri . '.multi.uribl.com.', 'A') === true) + if (checkdnsrr($uri . '.multi.uribl.com.', 'A') === true) { return true; } diff --git a/phpBB/phpbb/template/asset.php b/phpBB/phpbb/template/asset.php index cb00f16549..d6b46234f0 100644 --- a/phpBB/phpbb/template/asset.php +++ b/phpBB/phpbb/template/asset.php @@ -45,13 +45,6 @@ class asset */ public function set_url($url) { - if (version_compare(PHP_VERSION, '5.4.7') < 0 && substr($url, 0, 2) === '//') - { - // Workaround for PHP 5.4.6 and older bug #62844 - add fake scheme and then remove it - $this->components = parse_url('http:' . $url); - $this->components['scheme'] = ''; - return; - } $this->components = parse_url($url); } diff --git a/phpBB/phpbb/template/context.php b/phpBB/phpbb/template/context.php index 202e29ce00..f059c327c1 100644 --- a/phpBB/phpbb/template/context.php +++ b/phpBB/phpbb/template/context.php @@ -87,7 +87,7 @@ class context } /** - * Retreive a single scalar value from a single key. + * Retrieve a single scalar value from a single key. * * @param string $varname Variable name * @return mixed Variable value, or null if not set @@ -149,7 +149,7 @@ class context { // If the key name is lowercase and the data is an array, // it could be a template loop. So we set the S_NUM_ROWS there - // aswell. + // as well. if ($sub_block_name === strtolower($sub_block_name) && is_array($sub_block)) { $this->set_num_rows($sub_block); diff --git a/phpBB/phpbb/template/template.php b/phpBB/phpbb/template/template.php index df83d5bc43..6634c28d02 100644 --- a/phpBB/phpbb/template/template.php +++ b/phpBB/phpbb/template/template.php @@ -136,7 +136,7 @@ interface template public function retrieve_vars(array $vararray); /** - * Retreive a single scalar value from a single key. + * Retrieve a single scalar value from a single key. * * @param string $varname Variable name * @return mixed Variable value, or null if not set diff --git a/phpBB/phpbb/template/twig/extension.php b/phpBB/phpbb/template/twig/extension.php index f6f8e03ca2..1131a7f3aa 100644 --- a/phpBB/phpbb/template/twig/extension.php +++ b/phpBB/phpbb/template/twig/extension.php @@ -18,6 +18,9 @@ class extension extends \Twig_Extension /** @var \phpbb\template\context */ protected $context; + /** @var \phpbb\template\twig\environment */ + protected $environment; + /** @var \phpbb\language\language */ protected $language; @@ -25,12 +28,13 @@ class extension extends \Twig_Extension * Constructor * * @param \phpbb\template\context $context + * @param \phpbb\template\twig\environment $environment * @param \phpbb\language\language $language - * @return \phpbb\template\twig\extension */ - public function __construct(\phpbb\template\context $context, $language) + public function __construct(\phpbb\template\context $context, \phpbb\template\twig\environment $environment, $language) { $this->context = $context; + $this->environment = $environment; $this->language = $language; } @@ -56,9 +60,9 @@ class extension extends \Twig_Extension new \phpbb\template\twig\tokenparser\includeparser, new \phpbb\template\twig\tokenparser\includejs, new \phpbb\template\twig\tokenparser\includecss, - new \phpbb\template\twig\tokenparser\event, - new \phpbb\template\twig\tokenparser\includephp, - new \phpbb\template\twig\tokenparser\php, + new \phpbb\template\twig\tokenparser\event($this->environment), + new \phpbb\template\twig\tokenparser\includephp($this->environment), + new \phpbb\template\twig\tokenparser\php($this->environment), ); } @@ -85,6 +89,8 @@ class extension extends \Twig_Extension { return array( new \Twig_SimpleFunction('lang', array($this, 'lang')), + new \Twig_SimpleFunction('lang_defined', array($this, 'lang_defined')), + new \Twig_SimpleFunction('get_class', 'get_class'), ); } @@ -136,7 +142,7 @@ class extension extends \Twig_Extension * * @return mixed The sliced variable */ - function loop_subset(\Twig_Environment $env, $item, $start, $end = null, $preserveKeys = false) + public function loop_subset(\Twig_Environment $env, $item, $start, $end = null, $preserveKeys = false) { // We do almost the same thing as Twig's slice (array_slice), except when $end is positive if ($end >= 1) @@ -165,7 +171,7 @@ class extension extends \Twig_Extension * * @return string */ - function lang() + public function lang() { $args = func_get_args(); $key = $args[0]; @@ -182,4 +188,14 @@ class extension extends \Twig_Extension return call_user_func_array(array($this->language, 'lang'), $args); } + + /** + * Check if a language variable exists + * + * @return bool + */ + public function lang_defined($key) + { + return call_user_func_array([$this->language, 'is_set'], [$key]); + } } diff --git a/phpBB/phpbb/template/twig/extension/avatar.php b/phpBB/phpbb/template/twig/extension/avatar.php new file mode 100644 index 0000000000..7a17fd4b42 --- /dev/null +++ b/phpBB/phpbb/template/twig/extension/avatar.php @@ -0,0 +1,80 @@ +<?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\template\twig\extension; + +class avatar extends \Twig_Extension +{ + /** + * Get the name of this extension + * + * @return string + */ + public function getName() + { + return 'avatar'; + } + + /** + * Returns a list of global functions to add to the existing list. + * + * @return array An array of global functions + */ + public function getFunctions() + { + return array( + new \Twig_SimpleFunction('avatar', array($this, 'get_avatar')), + ); + } + + /** + * Get avatar for placing into templates. + * + * How to use in a template: + * - {{ avatar('mode', row, alt, ignore_config, lazy) }} + * + * The mode and row (group_row or user_row) are required. + * The other fields (alt|ignore_config|lazy) are optional. + * + * @uses \phpbb_get_group_avatar() + * @uses \phpbb_get_user_avatar() + * + * @return string The avatar HTML for the specified mode + */ + public function get_avatar() + { + $args = func_get_args(); + + $mode = (string) $args[0]; + $row = (array) $args[1]; + $alt = isset($args[2]) ? (string) $args[2] : false; + $ignore_config = isset($args[3]) ? (bool) $args[3] : false; + $lazy = isset($args[4]) ? (bool) $args[4] : false; + + // To prevent having to redefine alt attribute ('USER_AVATAR'|'GROUP_AVATAR'), we check if an alternative has been provided + switch ($mode) + { + case 'group': + return $alt ? phpbb_get_group_avatar($row, $alt, $ignore_config, $lazy) : phpbb_get_group_avatar($row); + break; + + case 'user': + return $alt ? phpbb_get_user_avatar($row, $alt, $ignore_config, $lazy) : phpbb_get_user_avatar($row); + break; + + default: + return ''; + break; + } + } +} diff --git a/phpBB/phpbb/template/twig/extension/config.php b/phpBB/phpbb/template/twig/extension/config.php new file mode 100644 index 0000000000..cbf6e505c5 --- /dev/null +++ b/phpBB/phpbb/template/twig/extension/config.php @@ -0,0 +1,64 @@ +<?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\template\twig\extension; + +class config extends \Twig_Extension +{ + /** @var \phpbb\config\config */ + protected $config; + + /** + * Constructor. + * + * @param \phpbb\config\config $config Configuration object + */ + public function __construct(\phpbb\config\config $config) + { + $this->config = $config; + } + + /** + * Get the name of this extension + * + * @return string + */ + public function getName() + { + return 'config'; + } + + /** + * Returns a list of global functions to add to the existing list. + * + * @return array An array of global functions + */ + public function getFunctions() + { + return array( + new \Twig_SimpleFunction('config', array($this, 'get_config')), + ); + } + + /** + * Retrieves a configuration value for use in templates. + * + * @return string The configuration value + */ + public function get_config() + { + $args = func_get_args(); + + return $this->config->offsetGet($args[0]); + } +} diff --git a/phpBB/phpbb/template/twig/extension/username.php b/phpBB/phpbb/template/twig/extension/username.php new file mode 100644 index 0000000000..ef149693a0 --- /dev/null +++ b/phpBB/phpbb/template/twig/extension/username.php @@ -0,0 +1,84 @@ +<?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\template\twig\extension; + +class username extends \Twig_Extension +{ + /** + * Get the name of this extension + * + * @return string + */ + public function getName() + { + return 'username'; + } + + /** + * Returns a list of global functions to add to the existing list. + * + * @return array An array of global functions + */ + public function getFunctions() + { + return array( + new \Twig_SimpleFunction('username', array($this, 'get_username')), + ); + } + + /** + * Get username details for placing into templates. + * + * How to use in a template: + * - {{ username('mode', user_id, username, user_colour, guest_username, custom_profile_url) }} + * - {{ username('mode', user_row, guest_username, custom_profile_url) }} + * It's possible to provide the user identifier, name and colour separately, + * or provide the entire user row at once as an array. + * + * The mode, user_id and username are required (separately or through a user row). + * The other fields (user_colour|guest_username|custom_profile_url) are optional. + * + * @uses \get_username_string() + * + * @return string A string based on what is wanted depending on $mode + */ + public function get_username() + { + $args = func_get_args(); + + $mode = $args[0]; + $user = $args[1]; + + // If the entire user row is provided + if (is_array($user)) + { + $user_id = isset($user['user_id']) ? $user['user_id'] : ''; + $username = isset($user['username']) ? $user['username'] : ''; + $user_colour = isset($user['user_colour']) ? $user['user_colour'] : ''; + $guest_username = isset($args[2]) ? $args[2] : false; + $custom_profile_url = isset($args[3]) ? $args[3] : false; + } + else + { + // Options are provided separately + $user_id = $user; + $username = $args[2]; + $user_colour = isset($args[3]) ? $args[3] : ''; + $guest_username = isset($args[4]) ? $args[4] : false; + $custom_profile_url = isset($args[5]) ? $args[5] : false; + } + + return get_username_string($mode, $user_id, $username, $user_colour, $guest_username, $custom_profile_url); + } +} diff --git a/phpBB/phpbb/template/twig/lexer.php b/phpBB/phpbb/template/twig/lexer.php index d0bcfa615e..6615a46067 100644 --- a/phpBB/phpbb/template/twig/lexer.php +++ b/phpBB/phpbb/template/twig/lexer.php @@ -15,20 +15,10 @@ namespace phpbb\template\twig; class lexer extends \Twig_Lexer { - public function set_environment(\Twig_Environment $env) + public function tokenize(\Twig_Source $source) { - $this->env = $env; - } - - public function tokenize($code, $filename = null) - { - // Handle \Twig_Source format input - if ($code instanceof \Twig_Source) - { - $source = $code; - $code = $source->getCode(); - $filename = $source->getName(); - } + $code = $source->getCode(); + $filename = $source->getName(); // Our phpBB tags // Commented out tokens are handled separately from the main replace diff --git a/phpBB/phpbb/template/twig/loader.php b/phpBB/phpbb/template/twig/loader.php index c13e3ee298..0f193dbe59 100644 --- a/phpBB/phpbb/template/twig/loader.php +++ b/phpBB/phpbb/template/twig/loader.php @@ -35,7 +35,7 @@ class loader extends \Twig_Loader_Filesystem { $this->filesystem = $filesystem; - parent::__construct($paths, $this->filesystem->realpath(dirname(__FILE__))); + parent::__construct($paths, __DIR__); } /** @@ -116,7 +116,7 @@ class loader extends \Twig_Loader_Filesystem * Override for Twig_Loader_Filesystem::findTemplate to add support * for loading from safe directories. */ - protected function findTemplate($name) + protected function findTemplate($name, $throw = true) { $name = (string) $name; @@ -132,12 +132,12 @@ class loader extends \Twig_Loader_Filesystem // First, find the template name. The override above of validateName // causes the validateName process to be skipped for this call - $file = parent::findTemplate($name); + $file = parent::findTemplate($name, $throw); try { // Try validating the name (which may throw an exception) - parent::validateName($name); + $this->validateName($name); } catch (\Twig_Error_Loader $e) { diff --git a/phpBB/phpbb/template/twig/node/definenode.php b/phpBB/phpbb/template/twig/node/definenode.php index ddbd151d20..1c51596916 100644 --- a/phpBB/phpbb/template/twig/node/definenode.php +++ b/phpBB/phpbb/template/twig/node/definenode.php @@ -16,7 +16,7 @@ namespace phpbb\template\twig\node; class definenode extends \Twig_Node { - public function __construct($capture, \Twig_NodeInterface $name, \Twig_NodeInterface $value, $lineno, $tag = null) + public function __construct($capture, \Twig_Node $name, \Twig_Node $value, $lineno, $tag = null) { parent::__construct(array('name' => $name, 'value' => $value), array('capture' => $capture, 'safe' => false), $lineno, $tag); } diff --git a/phpBB/phpbb/template/twig/node/includeasset.php b/phpBB/phpbb/template/twig/node/includeasset.php index 12034b7820..69bfd58803 100644 --- a/phpBB/phpbb/template/twig/node/includeasset.php +++ b/phpBB/phpbb/template/twig/node/includeasset.php @@ -15,15 +15,11 @@ namespace phpbb\template\twig\node; abstract class includeasset extends \Twig_Node { - /** @var \Twig_Environment */ - protected $environment; - - public function __construct(\Twig_Node_Expression $expr, \phpbb\template\twig\environment $environment, $lineno, $tag = null) + public function __construct(\Twig_Node_Expression $expr, $lineno, $tag = null) { - $this->environment = $environment; - parent::__construct(array('expr' => $expr), array(), $lineno, $tag); } + /** * Compiles the node to PHP. * @@ -33,20 +29,18 @@ abstract class includeasset extends \Twig_Node { $compiler->addDebugInfo($this); - $config = $this->environment->get_phpbb_config(); - $compiler ->write("\$asset_file = ") ->subcompile($this->getNode('expr')) ->raw(";\n") - ->write("\$asset = new \phpbb\\template\\asset(\$asset_file, \$this->getEnvironment()->get_path_helper(), \$this->getEnvironment()->get_filesystem());\n") + ->write("\$asset = new \phpbb\\template\\asset(\$asset_file, \$this->env->get_path_helper(), \$this->env->get_filesystem());\n") ->write("if (substr(\$asset_file, 0, 2) !== './' && \$asset->is_relative()) {\n") ->indent() ->write("\$asset_path = \$asset->get_path();") - ->write("\$local_file = \$this->getEnvironment()->get_phpbb_root_path() . \$asset_path;\n") + ->write("\$local_file = \$this->env->get_phpbb_root_path() . \$asset_path;\n") ->write("if (!file_exists(\$local_file)) {\n") ->indent() - ->write("\$local_file = \$this->getEnvironment()->findTemplate(\$asset_path);\n") + ->write("\$local_file = \$this->env->findTemplate(\$asset_path);\n") ->write("\$asset->set_path(\$local_file, true);\n") ->outdent() ->write("}\n") @@ -55,10 +49,10 @@ abstract class includeasset extends \Twig_Node ->write("\n") ->write("if (\$asset->is_relative()) {\n") ->indent() - ->write("\$asset->add_assets_version('{$config['assets_version']}');\n") + ->write("\$asset->add_assets_version(\$this->env->get_phpbb_config()['assets_version']);\n") ->outdent() ->write("}\n") - ->write("\$this->getEnvironment()->get_assets_bag()->add_{$this->get_setters_name()}(\$asset);") + ->write("\$this->env->get_assets_bag()->add_{$this->get_setters_name()}(\$asset);") ; } diff --git a/phpBB/phpbb/template/twig/node/includephp.php b/phpBB/phpbb/template/twig/node/includephp.php index 76182c2f84..0cf95abe99 100644 --- a/phpBB/phpbb/template/twig/node/includephp.php +++ b/phpBB/phpbb/template/twig/node/includephp.php @@ -63,15 +63,15 @@ class includephp extends \Twig_Node // Absolute path specified ->write("require(\$location);\n") ->outdent() - ->write("} else if (file_exists(\$this->getEnvironment()->get_phpbb_root_path() . \$location)) {\n") + ->write("} else if (file_exists(\$this->env->get_phpbb_root_path() . \$location)) {\n") ->indent() // PHP file relative to phpbb_root_path - ->write("require(\$this->getEnvironment()->get_phpbb_root_path() . \$location);\n") + ->write("require(\$this->env->get_phpbb_root_path() . \$location);\n") ->outdent() ->write("} else {\n") ->indent() // Local path (behaves like INCLUDE) - ->write("require(\$this->getEnvironment()->getLoader()->getCacheKey(\$location));\n") + ->write("require(\$this->env->getLoader()->getCacheKey(\$location));\n") ->outdent() ->write("}\n") ; diff --git a/phpBB/phpbb/template/twig/tokenparser/defineparser.php b/phpBB/phpbb/template/twig/tokenparser/defineparser.php index b755836ccd..6285091e94 100644 --- a/phpBB/phpbb/template/twig/tokenparser/defineparser.php +++ b/phpBB/phpbb/template/twig/tokenparser/defineparser.php @@ -21,7 +21,7 @@ class defineparser extends \Twig_TokenParser * * @param \Twig_Token $token A Twig_Token instance * - * @return \Twig_NodeInterface A Twig_NodeInterface instance + * @return \Twig_Node A Twig_Node instance * @throws \Twig_Error_Syntax * @throws \phpbb\template\twig\node\definenode */ @@ -41,7 +41,7 @@ class defineparser extends \Twig_TokenParser { // This would happen if someone improperly formed their DEFINE syntax // e.g. <!-- DEFINE $VAR = foo --> - throw new \Twig_Error_Syntax('Invalid DEFINE', $token->getLine(), $this->parser->getFilename()); + throw new \Twig_Error_Syntax('Invalid DEFINE', $token->getLine(), $this->parser->getStream()->getSourceContext()->getPath()); } $stream->expect(\Twig_Token::BLOCK_END_TYPE); diff --git a/phpBB/phpbb/template/twig/tokenparser/event.php b/phpBB/phpbb/template/twig/tokenparser/event.php index f73ef4ae25..92ecff4a74 100644 --- a/phpBB/phpbb/template/twig/tokenparser/event.php +++ b/phpBB/phpbb/template/twig/tokenparser/event.php @@ -15,12 +15,25 @@ namespace phpbb\template\twig\tokenparser; class event extends \Twig_TokenParser { + /** @var \phpbb\template\twig\environment */ + protected $environment; + + /** + * Constructor + * + * @param \phpbb\template\twig\environment $environment + */ + public function __construct(\phpbb\template\twig\environment $environment) + { + $this->environment = $environment; + } + /** * Parses a token and returns a node. * * @param \Twig_Token $token A Twig_Token instance * - * @return \Twig_NodeInterface A Twig_NodeInterface instance + * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { @@ -29,7 +42,7 @@ class event extends \Twig_TokenParser $stream = $this->parser->getStream(); $stream->expect(\Twig_Token::BLOCK_END_TYPE); - return new \phpbb\template\twig\node\event($expr, $this->parser->getEnvironment(), $token->getLine(), $this->getTag()); + return new \phpbb\template\twig\node\event($expr, $this->environment, $token->getLine(), $this->getTag()); } /** diff --git a/phpBB/phpbb/template/twig/tokenparser/includecss.php b/phpBB/phpbb/template/twig/tokenparser/includecss.php index 1f30811754..f7e55a46fb 100644 --- a/phpBB/phpbb/template/twig/tokenparser/includecss.php +++ b/phpBB/phpbb/template/twig/tokenparser/includecss.php @@ -20,7 +20,7 @@ class includecss extends \Twig_TokenParser * * @param \Twig_Token $token A Twig_Token instance * - * @return \Twig_NodeInterface A Twig_NodeInterface instance + * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { @@ -29,7 +29,7 @@ class includecss extends \Twig_TokenParser $stream = $this->parser->getStream(); $stream->expect(\Twig_Token::BLOCK_END_TYPE); - return new \phpbb\template\twig\node\includecss($expr, $this->parser->getEnvironment(), $token->getLine(), $this->getTag()); + return new \phpbb\template\twig\node\includecss($expr, $token->getLine(), $this->getTag()); } /** diff --git a/phpBB/phpbb/template/twig/tokenparser/includejs.php b/phpBB/phpbb/template/twig/tokenparser/includejs.php index 4b67d2c468..598ea0a70d 100644 --- a/phpBB/phpbb/template/twig/tokenparser/includejs.php +++ b/phpBB/phpbb/template/twig/tokenparser/includejs.php @@ -20,7 +20,7 @@ class includejs extends \Twig_TokenParser * * @param \Twig_Token $token A Twig_Token instance * - * @return \Twig_NodeInterface A Twig_NodeInterface instance + * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { @@ -29,7 +29,7 @@ class includejs extends \Twig_TokenParser $stream = $this->parser->getStream(); $stream->expect(\Twig_Token::BLOCK_END_TYPE); - return new \phpbb\template\twig\node\includejs($expr, $this->parser->getEnvironment(), $token->getLine(), $this->getTag()); + return new \phpbb\template\twig\node\includejs($expr, $token->getLine(), $this->getTag()); } /** diff --git a/phpBB/phpbb/template/twig/tokenparser/includeparser.php b/phpBB/phpbb/template/twig/tokenparser/includeparser.php index aa7236aaa6..2fba4ac4c4 100644 --- a/phpBB/phpbb/template/twig/tokenparser/includeparser.php +++ b/phpBB/phpbb/template/twig/tokenparser/includeparser.php @@ -21,7 +21,7 @@ class includeparser extends \Twig_TokenParser_Include * * @param \Twig_Token $token A Twig_Token instance * - * @return \Twig_NodeInterface A Twig_NodeInterface instance + * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { diff --git a/phpBB/phpbb/template/twig/tokenparser/includephp.php b/phpBB/phpbb/template/twig/tokenparser/includephp.php index 3992636f8c..2fdf396452 100644 --- a/phpBB/phpbb/template/twig/tokenparser/includephp.php +++ b/phpBB/phpbb/template/twig/tokenparser/includephp.php @@ -16,12 +16,25 @@ namespace phpbb\template\twig\tokenparser; class includephp extends \Twig_TokenParser { + /** @var \phpbb\template\twig\environment */ + protected $environment; + + /** + * Constructor + * + * @param \phpbb\template\twig\environment $environment + */ + public function __construct(\phpbb\template\twig\environment $environment) + { + $this->environment = $environment; + } + /** * Parses a token and returns a node. * * @param \Twig_Token $token A Twig_Token instance * - * @return \Twig_NodeInterface A Twig_NodeInterface instance + * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { @@ -40,7 +53,7 @@ class includephp extends \Twig_TokenParser $stream->expect(\Twig_Token::BLOCK_END_TYPE); - return new \phpbb\template\twig\node\includephp($expr, $this->parser->getEnvironment(), $token->getLine(), $ignoreMissing, $this->getTag()); + return new \phpbb\template\twig\node\includephp($expr, $this->environment, $token->getLine(), $ignoreMissing, $this->getTag()); } /** diff --git a/phpBB/phpbb/template/twig/tokenparser/php.php b/phpBB/phpbb/template/twig/tokenparser/php.php index f11ce35896..3007912b47 100644 --- a/phpBB/phpbb/template/twig/tokenparser/php.php +++ b/phpBB/phpbb/template/twig/tokenparser/php.php @@ -15,12 +15,25 @@ namespace phpbb\template\twig\tokenparser; class php extends \Twig_TokenParser { + /** @var \phpbb\template\twig\environment */ + protected $environment; + + /** + * Constructor + * + * @param \phpbb\template\twig\environment $environment + */ + public function __construct(\phpbb\template\twig\environment $environment) + { + $this->environment = $environment; + } + /** * Parses a token and returns a node. * * @param \Twig_Token $token A Twig_Token instance * - * @return \Twig_NodeInterface A Twig_NodeInterface instance + * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { @@ -32,7 +45,7 @@ class php extends \Twig_TokenParser $stream->expect(\Twig_Token::BLOCK_END_TYPE); - return new \phpbb\template\twig\node\php($body, $this->parser->getEnvironment(), $token->getLine(), $this->getTag()); + return new \phpbb\template\twig\node\php($body, $this->environment, $token->getLine(), $this->getTag()); } public function decideEnd(\Twig_Token $token) diff --git a/phpBB/phpbb/textformatter/acp_utils_interface.php b/phpBB/phpbb/textformatter/acp_utils_interface.php new file mode 100644 index 0000000000..cdee56f19d --- /dev/null +++ b/phpBB/phpbb/textformatter/acp_utils_interface.php @@ -0,0 +1,54 @@ +<?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\textformatter; + +interface acp_utils_interface +{ + /** + * There is an issue with the definition + */ + const BBCODE_STATUS_INVALID_DEFINITION = 'invalid_definition'; + + /** + * There is an issue with the template + */ + const BBCODE_STATUS_INVALID_TEMPLATE = 'invalid_template'; + + /** + * The BBCode is valid and can be safely used by anyone + */ + const BBCODE_STATUS_SAFE = 'safe'; + + /** + * The BBCode is valid but may be unsafe to use + */ + const BBCODE_STATUS_UNSAFE = 'unsafe'; + + /** + * Analyse given BBCode definition for issues and safeness + * + * Required elements in the return array: + * - status: see BBCODE_STATUS_* constants + * + * Optional elements in the return array: + * - name: Name of the BBCode based on the definition. Required if status is "safe". + * - error_text: Textual description of the issue in plain text or as a L_* string. + * - error_html: Visual description of the issue in HTML. + * + * @param string $definition BBCode definition, e.g. [b]{TEXT}[/b] + * @param string $template BBCode template, e.g. <b>{TEXT}</b> + * @return array + */ + public function analyse_bbcode(string $definition, string $template): array; +} diff --git a/phpBB/phpbb/textformatter/s9e/acp_utils.php b/phpBB/phpbb/textformatter/s9e/acp_utils.php new file mode 100644 index 0000000000..c4a668020e --- /dev/null +++ b/phpBB/phpbb/textformatter/s9e/acp_utils.php @@ -0,0 +1,67 @@ +<?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\textformatter\s9e; + +use phpbb\textformatter\acp_utils_interface; +use s9e\TextFormatter\Configurator\Exceptions\UnsafeTemplateException; + +class acp_utils implements acp_utils_interface +{ + /** + * @var factory $factory + */ + protected $factory; + + /** + * @param factory $factory + */ + public function __construct(factory $factory) + { + $this->factory = $factory; + } + + /** + * {@inheritdoc} + */ + public function analyse_bbcode(string $definition, string $template): array + { + $configurator = $this->factory->get_configurator(); + $return = ['status' => self::BBCODE_STATUS_SAFE]; + + // Capture and normalize the BBCode name manually because there's no easy way to retrieve + // it in TextFormatter <= 2.x + if (preg_match('(\\[([-\\w]++))', $definition, $m)) + { + $return['name'] = strtoupper($m[1]); + } + + try + { + $configurator->BBCodes->addCustom($definition, $template); + } + catch (UnsafeTemplateException $e) + { + $return['status'] = self::BBCODE_STATUS_UNSAFE; + $return['error_text'] = $e->getMessage(); + $return['error_html'] = $e->highlightNode('<span class="highlight">'); + } + catch (\Exception $e) + { + $return['status'] = (preg_match('(xml|xpath|xsl)i', $e->getMessage())) ? self::BBCODE_STATUS_INVALID_TEMPLATE : self::BBCODE_STATUS_INVALID_DEFINITION; + $return['error_text'] = $e->getMessage(); + } + + return $return; + } +} diff --git a/phpBB/phpbb/textformatter/s9e/bbcode_merger.php b/phpBB/phpbb/textformatter/s9e/bbcode_merger.php index 264eb93782..d1bedb0b72 100644 --- a/phpBB/phpbb/textformatter/s9e/bbcode_merger.php +++ b/phpBB/phpbb/textformatter/s9e/bbcode_merger.php @@ -14,7 +14,7 @@ namespace phpbb\textformatter\s9e; use phpbb\textformatter\s9e\factory; -use s9e\TextFormatter\Configurator\Helpers\TemplateHelper; +use s9e\TextFormatter\Configurator\Helpers\TemplateLoader; use s9e\TextFormatter\Configurator\Items\UnsafeTemplate; class bbcode_merger @@ -91,9 +91,9 @@ class bbcode_merger */ protected function indent_template($template) { - $dom = TemplateHelper::loadTemplate($template); + $dom = TemplateLoader::load($template); $dom->formatOutput = true; - $template = TemplateHelper::saveTemplate($dom); + $template = TemplateLoader::save($dom); // Remove the first level of indentation if the template starts with whitespace if (preg_match('(^\\n +)', $template, $m)) diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php new file mode 100644 index 0000000000..5c27c4f414 --- /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 = '" . $this->db->sql_escape($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 9817e40edb..21d156e060 100644 --- a/phpBB/phpbb/user.php +++ b/phpBB/phpbb/user.php @@ -110,7 +110,7 @@ class user extends \phpbb\session function setup($lang_set = false, $style_id = false) { global $db, $request, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache; - global $phpbb_dispatcher; + global $phpbb_dispatcher, $phpbb_container; $this->language->set_default_language($config['default_lang']); @@ -361,8 +361,8 @@ class user extends \phpbb\session } // Disable board if the install/ directory is still present - // For the brave development army we do not care about this, else we need to comment out this everytime we develop locally - if (!defined('DEBUG') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install')) + // For the brave development army we do not care about this, else we need to comment out this every time we develop locally + if (!$phpbb_container->getParameter('allow_install_dir') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install')) { // Adjust the message slightly according to the permissions if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) @@ -480,7 +480,7 @@ class user extends \phpbb\session * @return int|bool The plural-case we need to use for the number plural-rule combination, false if $force_rule * was invalid. * - * @deprecated: 3.2.0-dev (To be removed: 3.3.0) + * @deprecated: 3.2.0-dev (To be removed: 4.0.0) */ function get_plural_form($number, $force_rule = false) { @@ -491,8 +491,8 @@ class user extends \phpbb\session * Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion) * * @param mixed $lang_set specifies the language entries to include - * @param bool $use_db internal variable for recursion, do not use @deprecated 3.2.0-dev (To be removed: 3.3.0) - * @param bool $use_help internal variable for recursion, do not use @deprecated 3.2.0-dev (To be removed: 3.3.0) + * @param bool $use_db internal variable for recursion, do not use @deprecated 3.2.0-dev (To be removed: 4.0.0) + * @param bool $use_help internal variable for recursion, do not use @deprecated 3.2.0-dev (To be removed: 4.0.0) * @param string $ext_name The extension to load language from, or empty for core files * * Examples: @@ -507,7 +507,7 @@ class user extends \phpbb\session * Note: $use_db and $use_help should be removed. The old function was kept for BC purposes, * so the BC logic is handled here. * - * @deprecated: 3.2.0-dev (To be removed: 3.3.0) + * @deprecated: 3.2.0-dev (To be removed: 4.0.0) */ function add_lang($lang_set, $use_db = false, $use_help = false, $ext_name = '') { @@ -548,7 +548,7 @@ class user extends \phpbb\session /** * BC function for loading language files * - * @deprecated 3.2.0-dev (To be removed: 3.3.0) + * @deprecated 3.2.0-dev (To be removed: 4.0.0) */ private function set_lang($lang_set, $use_help, $ext_name) { @@ -584,7 +584,7 @@ class user extends \phpbb\session * * Note: $use_db and $use_help should be removed. Kept for BC purposes. * - * @deprecated: 3.2.0-dev (To be removed: 3.3.0) + * @deprecated: 3.2.0-dev (To be removed: 4.0.0) */ function add_lang_ext($ext_name, $lang_set, $use_db = false, $use_help = false) { @@ -786,7 +786,7 @@ class user extends \phpbb\session } /** - * Funtion to make the user leave the NEWLY_REGISTERED system group. + * Function to make the user leave the NEWLY_REGISTERED system group. * @access public */ function leave_newly_registered() diff --git a/phpBB/phpbb/user_loader.php b/phpBB/phpbb/user_loader.php index 9297450f3e..3dacf07ff5 100644 --- a/phpBB/phpbb/user_loader.php +++ b/phpBB/phpbb/user_loader.php @@ -123,7 +123,7 @@ class user_loader /** * Get a user row from our users cache * - * @param int $user_id User ID of the user you want to retreive + * @param int $user_id User ID of the user you want to retrieve * @param bool $query Should we query the database if this user has not yet been loaded? * Typically this should be left as false and you should make sure * you load users ahead of time with load_users() @@ -150,7 +150,7 @@ class user_loader /** * Get username * - * @param int $user_id User ID of the user you want to retreive the username for + * @param int $user_id User ID of the user you want to retrieve the username for * @param string $mode The mode to load (same as get_username_string). One of the following: * profile (for getting an url to the profile) * username (for obtaining the username) @@ -204,7 +204,7 @@ class user_loader /** * Get rank * - * @param int $user_id User ID of the user you want to retreive the rank for + * @param int $user_id User ID of the user you want to retrieve the rank for * @param bool $query Should we query the database if this user has not yet been loaded? * Typically this should be left as false and you should make sure * you load users ahead of time with load_users() |