diff options
Diffstat (limited to 'phpBB/phpbb/install')
95 files changed, 14123 insertions, 0 deletions
diff --git a/phpBB/phpbb/install/console/command/install/config/show.php b/phpBB/phpbb/install/console/command/install/config/show.php new file mode 100644 index 0000000000..b6c11956fe --- /dev/null +++ b/phpBB/phpbb/install/console/command/install/config/show.php @@ -0,0 +1,123 @@ +<?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\install\console\command\install\config; + +use phpbb\install\helper\iohandler\factory; +use phpbb\install\installer_configuration; +use phpbb\language\language; +use Symfony\Component\Config\Definition\Exception\Exception; +use Symfony\Component\Config\Definition\Processor; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Yaml\Exception\ParseException; +use Symfony\Component\Yaml\Yaml; + +class show extends \phpbb\console\command\command +{ + /** + * @var factory + */ + protected $iohandler_factory; + + /** + * @var language + */ + protected $language; + + /** + * Constructor + * + * @param language $language + * @param factory $factory + */ + public function __construct(language $language, factory $factory) + { + $this->iohandler_factory = $factory; + $this->language = $language; + + parent::__construct(new \phpbb\user($language, 'datetime')); + } + + /** + * + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('install:config:show') + ->addArgument( + 'config-file', + InputArgument::REQUIRED, + $this->language->lang('CLI_CONFIG_FILE')) + ->setDescription($this->language->lang('CLI_INSTALL_SHOW_CONFIG')) + ; + } + + /** + * Show the validated configuration + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return null + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->iohandler_factory->set_environment('cli'); + + /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */ + $iohandler = $this->iohandler_factory->get(); + $style = new SymfonyStyle($input, $output); + $iohandler->set_style($style, $output); + + $config_file = $input->getArgument('config-file'); + + if (!is_file($config_file)) + { + $iohandler->add_error_message(array('MISSING_FILE', $config_file)); + + return; + } + + try + { + $config = Yaml::parse(file_get_contents($config_file), true, false); + } + catch (ParseException $e) + { + $iohandler->add_error_message('INVALID_YAML_FILE'); + + return; + } + + $processor = new Processor(); + $configuration = new installer_configuration(); + + try + { + $config = $processor->processConfiguration($configuration, $config); + } + catch (Exception $e) + { + $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage()); + + return; + } + + $style->block(Yaml::dump(array('installer' => $config), 10, 4, true, false)); + } +} diff --git a/phpBB/phpbb/install/console/command/install/config/validate.php b/phpBB/phpbb/install/console/command/install/config/validate.php new file mode 100644 index 0000000000..b48a1acbd4 --- /dev/null +++ b/phpBB/phpbb/install/console/command/install/config/validate.php @@ -0,0 +1,124 @@ +<?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\install\console\command\install\config; + +use phpbb\install\helper\iohandler\factory; +use phpbb\install\installer_configuration; +use phpbb\language\language; +use Symfony\Component\Config\Definition\Exception\Exception; +use Symfony\Component\Config\Definition\Processor; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Yaml\Exception\ParseException; +use Symfony\Component\Yaml\Yaml; + +class validate extends \phpbb\console\command\command +{ + /** + * @var factory + */ + protected $iohandler_factory; + + /** + * @var language + */ + protected $language; + + /** + * Constructor + * + * @param language $language + * @param factory $factory + */ + public function __construct(language $language, factory $factory) + { + $this->iohandler_factory = $factory; + $this->language = $language; + + parent::__construct(new \phpbb\user($language, 'datetime')); + } + + /** + * + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('install:config:validate') + ->addArgument( + 'config-file', + InputArgument::REQUIRED, + $this->language->lang('CLI_CONFIG_FILE')) + ->setDescription($this->language->lang('CLI_INSTALL_VALIDATE_CONFIG')) + ; + } + + /** + * Validate the configuration file + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return null + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->iohandler_factory->set_environment('cli'); + + /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */ + $iohandler = $this->iohandler_factory->get(); + $style = new SymfonyStyle($input, $output); + $iohandler->set_style($style, $output); + + $config_file = $input->getArgument('config-file'); + + if (!is_file($config_file)) + { + $iohandler->add_error_message(array('MISSING_FILE', array($config_file))); + + return 1; + } + + try + { + $config = Yaml::parse(file_get_contents($config_file), true, false); + } + catch (ParseException $e) + { + $iohandler->add_error_message('INVALID_YAML_FILE'); + + return 1; + } + + $processor = new Processor(); + $configuration = new installer_configuration(); + + try + { + $processor->processConfiguration($configuration, $config); + } + catch (Exception $e) + { + $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage()); + + return 1; + } + + $iohandler->add_success_message('CONFIGURATION_VALID'); + return 0; + } +} diff --git a/phpBB/phpbb/install/console/command/install/install.php b/phpBB/phpbb/install/console/command/install/install.php new file mode 100644 index 0000000000..52a348fe44 --- /dev/null +++ b/phpBB/phpbb/install/console/command/install/install.php @@ -0,0 +1,210 @@ +<?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\install\console\command\install; + +use phpbb\install\exception\installer_exception; +use phpbb\install\helper\install_helper; +use phpbb\install\helper\iohandler\cli_iohandler; +use phpbb\install\helper\iohandler\factory; +use phpbb\install\installer; +use phpbb\install\installer_configuration; +use phpbb\language\language; +use Symfony\Component\Config\Definition\Exception\Exception; +use Symfony\Component\Config\Definition\Processor; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Yaml\Exception\ParseException; +use Symfony\Component\Yaml\Yaml; + +class install extends \phpbb\console\command\command +{ + /** + * @var factory + */ + protected $iohandler_factory; + + /** + * @var installer + */ + protected $installer; + + /** + * @var install_helper + */ + protected $install_helper; + + /** + * @var language + */ + protected $language; + + /** + * Constructor + * + * @param language $language + * @param factory $factory + * @param installer $installer + * @param install_helper $install_helper + */ + public function __construct(language $language, factory $factory, installer $installer, install_helper $install_helper) + { + $this->iohandler_factory = $factory; + $this->installer = $installer; + $this->language = $language; + $this->install_helper = $install_helper; + + parent::__construct(new \phpbb\user($language, 'datetime')); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('install') + ->addArgument( + 'config-file', + InputArgument::REQUIRED, + $this->language->lang('CLI_CONFIG_FILE')) + ->setDescription($this->language->lang('CLI_INSTALL_BOARD')) + ; + } + + /** + * Executes the command install. + * + * Install the board + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return null + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->iohandler_factory->set_environment('cli'); + + /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */ + $iohandler = $this->iohandler_factory->get(); + $style = new SymfonyStyle($input, $output); + $iohandler->set_style($style, $output); + + $this->installer->set_iohandler($iohandler); + + $config_file = $input->getArgument('config-file'); + + if ($this->install_helper->is_phpbb_installed()) + { + $iohandler->add_error_message('INSTALL_PHPBB_INSTALLED'); + + return 1; + } + + if (!is_file($config_file)) + { + $iohandler->add_error_message(array('MISSING_FILE', $config_file)); + + return 1; + } + + try + { + $config = Yaml::parse(file_get_contents($config_file), true, false); + } + catch (ParseException $e) + { + $iohandler->add_error_message(array('INVALID_YAML_FILE', $config_file)); + + return 1; + } + + $processor = new Processor(); + $configuration = new installer_configuration(); + + try + { + $config = $processor->processConfiguration($configuration, $config); + } + catch (Exception $e) + { + $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage()); + + return 1; + } + + $this->register_configuration($iohandler, $config); + + try + { + $this->installer->run(); + return 0; + } + catch (installer_exception $e) + { + $iohandler->add_error_message($e->getMessage()); + return 1; + } + } + + /** + * Register the configuration to simulate the forms. + * + * @param cli_iohandler $iohandler + * @param array $config + */ + private function register_configuration(cli_iohandler $iohandler, $config) + { + $iohandler->set_input('admin_name', $config['admin']['name']); + $iohandler->set_input('admin_pass1', $config['admin']['password']); + $iohandler->set_input('admin_pass2', $config['admin']['password']); + $iohandler->set_input('board_email', $config['admin']['email']); + $iohandler->set_input('submit_admin', 'submit'); + + $iohandler->set_input('default_lang', $config['board']['lang']); + $iohandler->set_input('board_name', $config['board']['name']); + $iohandler->set_input('board_description', $config['board']['description']); + $iohandler->set_input('submit_board', 'submit'); + + $iohandler->set_input('dbms', $config['database']['dbms']); + $iohandler->set_input('dbhost', $config['database']['dbhost']); + $iohandler->set_input('dbport', $config['database']['dbport']); + $iohandler->set_input('dbuser', $config['database']['dbuser']); + $iohandler->set_input('dbpasswd', $config['database']['dbpasswd']); + $iohandler->set_input('dbname', $config['database']['dbname']); + $iohandler->set_input('table_prefix', $config['database']['table_prefix']); + $iohandler->set_input('submit_database', 'submit'); + + $iohandler->set_input('email_enable', $config['email']['enabled']); + $iohandler->set_input('smtp_delivery', $config['email']['smtp_delivery']); + $iohandler->set_input('smtp_host', $config['email']['smtp_host']); + $iohandler->set_input('smtp_port', $config['email']['smtp_port']); + $iohandler->set_input('smtp_auth', $config['email']['smtp_auth']); + $iohandler->set_input('smtp_user', $config['email']['smtp_user']); + $iohandler->set_input('smtp_pass', $config['email']['smtp_pass']); + $iohandler->set_input('submit_email', 'submit'); + + $iohandler->set_input('cookie_secure', $config['server']['cookie_secure']); + $iohandler->set_input('server_protocol', $config['server']['server_protocol']); + $iohandler->set_input('force_server_vars', $config['server']['force_server_vars']); + $iohandler->set_input('server_name', $config['server']['server_name']); + $iohandler->set_input('server_port', $config['server']['server_port']); + $iohandler->set_input('script_path', $config['server']['script_path']); + $iohandler->set_input('submit_server', 'submit'); + + $iohandler->set_input('install-extensions', $config['extensions']); + } +} diff --git a/phpBB/phpbb/install/console/command/update/config/show.php b/phpBB/phpbb/install/console/command/update/config/show.php new file mode 100644 index 0000000000..e462763b5d --- /dev/null +++ b/phpBB/phpbb/install/console/command/update/config/show.php @@ -0,0 +1,123 @@ +<?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\install\console\command\update\config; + +use phpbb\install\helper\iohandler\factory; +use phpbb\install\updater_configuration; +use phpbb\language\language; +use Symfony\Component\Config\Definition\Exception\Exception; +use Symfony\Component\Config\Definition\Processor; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Yaml\Exception\ParseException; +use Symfony\Component\Yaml\Yaml; + +class show extends \phpbb\console\command\command +{ + /** + * @var factory + */ + protected $iohandler_factory; + + /** + * @var language + */ + protected $language; + + /** + * Constructor + * + * @param language $language + * @param factory $factory + */ + public function __construct(language $language, factory $factory) + { + $this->iohandler_factory = $factory; + $this->language = $language; + + parent::__construct(new \phpbb\user($language, 'datetime')); + } + + /** + * + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('update:config:show') + ->addArgument( + 'config-file', + InputArgument::REQUIRED, + $this->language->lang('CLI_CONFIG_FILE')) + ->setDescription($this->language->lang('CLI_INSTALL_SHOW_CONFIG')) + ; + } + + /** + * Show the validated configuration + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return null + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->iohandler_factory->set_environment('cli'); + + /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */ + $iohandler = $this->iohandler_factory->get(); + $style = new SymfonyStyle($input, $output); + $iohandler->set_style($style, $output); + + $config_file = $input->getArgument('config-file'); + + if (!is_file($config_file)) + { + $iohandler->add_error_message(array('MISSING_FILE', $config_file)); + + return; + } + + try + { + $config = Yaml::parse(file_get_contents($config_file), true, false); + } + catch (ParseException $e) + { + $iohandler->add_error_message('INVALID_YAML_FILE'); + + return; + } + + $processor = new Processor(); + $configuration = new updater_configuration(); + + try + { + $config = $processor->processConfiguration($configuration, $config); + } + catch (Exception $e) + { + $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage()); + + return; + } + + $style->block(Yaml::dump(array('updater' => $config), 10, 4, true, false)); + } +} diff --git a/phpBB/phpbb/install/console/command/update/config/validate.php b/phpBB/phpbb/install/console/command/update/config/validate.php new file mode 100644 index 0000000000..18de5eab46 --- /dev/null +++ b/phpBB/phpbb/install/console/command/update/config/validate.php @@ -0,0 +1,124 @@ +<?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\install\console\command\update\config; + +use phpbb\install\helper\iohandler\factory; +use phpbb\install\updater_configuration; +use phpbb\language\language; +use Symfony\Component\Config\Definition\Exception\Exception; +use Symfony\Component\Config\Definition\Processor; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Yaml\Exception\ParseException; +use Symfony\Component\Yaml\Yaml; + +class validate extends \phpbb\console\command\command +{ + /** + * @var factory + */ + protected $iohandler_factory; + + /** + * @var language + */ + protected $language; + + /** + * Constructor + * + * @param language $language + * @param factory $factory + */ + public function __construct(language $language, factory $factory) + { + $this->iohandler_factory = $factory; + $this->language = $language; + + parent::__construct(new \phpbb\user($language, 'datetime')); + } + + /** + * + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('update:config:validate') + ->addArgument( + 'config-file', + InputArgument::REQUIRED, + $this->language->lang('CLI_CONFIG_FILE')) + ->setDescription($this->language->lang('CLI_INSTALL_VALIDATE_CONFIG')) + ; + } + + /** + * Validate the configuration file + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return null + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->iohandler_factory->set_environment('cli'); + + /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */ + $iohandler = $this->iohandler_factory->get(); + $style = new SymfonyStyle($input, $output); + $iohandler->set_style($style, $output); + + $config_file = $input->getArgument('config-file'); + + if (!is_file($config_file)) + { + $iohandler->add_error_message(array('MISSING_FILE', array($config_file))); + + return 1; + } + + try + { + $config = Yaml::parse(file_get_contents($config_file), true, false); + } + catch (ParseException $e) + { + $iohandler->add_error_message('INVALID_YAML_FILE'); + + return 1; + } + + $processor = new Processor(); + $configuration = new updater_configuration(); + + try + { + $processor->processConfiguration($configuration, $config); + } + catch (Exception $e) + { + $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage()); + + return 1; + } + + $iohandler->add_success_message('CONFIGURATION_VALID'); + return 0; + } +} diff --git a/phpBB/phpbb/install/console/command/update/update.php b/phpBB/phpbb/install/console/command/update/update.php new file mode 100644 index 0000000000..e827761d1c --- /dev/null +++ b/phpBB/phpbb/install/console/command/update/update.php @@ -0,0 +1,182 @@ +<?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\install\console\command\update; + +use phpbb\install\exception\installer_exception; +use phpbb\install\helper\install_helper; +use phpbb\install\helper\iohandler\cli_iohandler; +use phpbb\install\helper\iohandler\factory; +use phpbb\install\installer; +use phpbb\install\updater_configuration; +use phpbb\language\language; +use Symfony\Component\Config\Definition\Exception\Exception; +use Symfony\Component\Config\Definition\Processor; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Yaml\Exception\ParseException; +use Symfony\Component\Yaml\Yaml; + +class update extends \phpbb\console\command\command +{ + /** + * @var factory + */ + protected $iohandler_factory; + + /** + * @var installer + */ + protected $installer; + + /** + * @var install_helper + */ + protected $install_helper; + + /** + * @var language + */ + protected $language; + + /** + * Constructor + * + * @param language $language + * @param factory $factory + * @param installer $installer + * @param install_helper $install_helper + */ + public function __construct(language $language, factory $factory, installer $installer, install_helper $install_helper) + { + $this->iohandler_factory = $factory; + $this->installer = $installer; + $this->language = $language; + $this->install_helper = $install_helper; + + parent::__construct(new \phpbb\user($language, 'datetime')); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('update') + ->addArgument( + 'config-file', + InputArgument::REQUIRED, + $this->language->lang('CLI_CONFIG_FILE')) + ->setDescription($this->language->lang('CLI_UPDATE_BOARD')) + ; + } + + /** + * Executes the command update. + * + * Update the board + * + * @param InputInterface $input An InputInterface instance + * @param OutputInterface $output An OutputInterface instance + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->iohandler_factory->set_environment('cli'); + + /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */ + $iohandler = $this->iohandler_factory->get(); + $style = new SymfonyStyle($input, $output); + $iohandler->set_style($style, $output); + + $this->installer->set_iohandler($iohandler); + + $config_file = $input->getArgument('config-file'); + + if (!$this->install_helper->is_phpbb_installed()) + { + $iohandler->add_error_message('INSTALL_PHPBB_NOT_INSTALLED'); + + return 1; + } + + if (!is_file($config_file)) + { + $iohandler->add_error_message(array('MISSING_FILE', $config_file)); + + return 1; + } + + try + { + $config = Yaml::parse(file_get_contents($config_file), true, false); + } + catch (ParseException $e) + { + $iohandler->add_error_message(array('INVALID_YAML_FILE', $config_file)); + + return 1; + } + + $processor = new Processor(); + $configuration = new updater_configuration(); + + try + { + $config = $processor->processConfiguration($configuration, $config); + } + catch (Exception $e) + { + $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage()); + + return 1; + } + + $this->register_configuration($iohandler, $config); + + try + { + $this->installer->run(); + return 0; + } + catch (installer_exception $e) + { + $iohandler->add_error_message($e->getMessage()); + return 1; + } + } + + /** + * Register the configuration to simulate the forms. + * + * @param cli_iohandler $iohandler + * @param array $config + */ + private function register_configuration(cli_iohandler $iohandler, $config) + { + $iohandler->set_input('update_type', $config['type']); + $iohandler->set_input('submit_update', 'submit'); + + $iohandler->set_input('compression_method', '.tar'); + $iohandler->set_input('method', 'direct_file'); + $iohandler->set_input('submit_update_file', 'submit'); + + $iohandler->set_input('submit_continue_file_update', 'submit'); + + $iohandler->set_input('update-extensions', $config['extensions']); + } +} diff --git a/phpBB/phpbb/install/controller/archive_download.php b/phpBB/phpbb/install/controller/archive_download.php new file mode 100644 index 0000000000..eabc0a9976 --- /dev/null +++ b/phpBB/phpbb/install/controller/archive_download.php @@ -0,0 +1,93 @@ +<?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\install\controller; + +use phpbb\exception\http_exception; +use phpbb\install\helper\config; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; + +class archive_download +{ + /** + * @var config + */ + protected $installer_config; + + /** + * Constructor + * + * @param config $config + */ + public function __construct(config $config) + { + $this->installer_config = $config; + $this->installer_config->load_config(); + } + + /** + * Sends response with the merge conflict archive + * + * Merge conflicts always have to be resolved manually, + * so we use a different archive for that. + * + * @return BinaryFileResponse + */ + public function conflict_archive() + { + $filename = $this->installer_config->get('update_file_conflict_archive', ''); + + if (empty($filename)) + { + throw new http_exception(404, 'URL_NOT_FOUND'); + } + + return $this->send_response($filename); + } + + /** + * Sends response with the updated files' archive + * + * @return BinaryFileResponse + */ + public function update_archive() + { + $filename = $this->installer_config->get('update_file_archive', ''); + + if (empty($filename)) + { + throw new http_exception(404, 'URL_NOT_FOUND'); + } + + return $this->send_response($filename); + } + + /** + * Generates a download response + * + * @param string $filename Path to the file to download + * + * @return BinaryFileResponse Response object + */ + private function send_response($filename) + { + $response = new BinaryFileResponse($filename); + $response->setContentDisposition( + ResponseHeaderBag::DISPOSITION_ATTACHMENT, + basename($filename) + ); + + return $response; + } +} diff --git a/phpBB/phpbb/install/controller/helper.php b/phpBB/phpbb/install/controller/helper.php new file mode 100644 index 0000000000..ff7e691224 --- /dev/null +++ b/phpBB/phpbb/install/controller/helper.php @@ -0,0 +1,413 @@ +<?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\install\controller; + +use phpbb\install\helper\config; +use phpbb\install\helper\navigation\navigation_provider; +use phpbb\language\language; +use phpbb\language\language_file_helper; +use phpbb\path_helper; +use phpbb\request\request; +use phpbb\request\request_interface; +use phpbb\routing\router; +use phpbb\symfony_request; +use phpbb\template\template; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Cookie; + +/** + * A duplicate of \phpbb\controller\helper + * + * This class is necessary because of controller\helper's legacy function calls + * to page_header() page_footer() functions which has unavailable dependencies. + */ +class helper +{ + /** + * @var config + */ + protected $installer_config; + + /** + * @var \phpbb\language\language + */ + protected $language; + + /** + * @var bool|string + */ + protected $language_cookie; + + /** + * @var \phpbb\language\language_file_helper + */ + protected $lang_helper; + + /** + * @var \phpbb\install\helper\navigation\navigation_provider + */ + protected $navigation_provider; + + /** + * @var \phpbb\template\template + */ + protected $template; + + /** + * @var \phpbb\path_helper + */ + protected $path_helper; + + /** + * @var \phpbb\request\request + */ + protected $phpbb_request; + + /** + * @var \phpbb\symfony_request + */ + protected $request; + + /** + * @var \phpbb\routing\router + */ + protected $router; + + /** + * @var string + */ + protected $phpbb_admin_path; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param config $config + * @param language $language + * @param language_file_helper $lang_helper + * @param navigation_provider $nav + * @param template $template + * @param path_helper $path_helper + * @param request $phpbb_request + * @param symfony_request $request + * @param router $router + * @param string $phpbb_root_path + */ + public function __construct(config $config, language $language, language_file_helper $lang_helper, navigation_provider $nav, template $template, path_helper $path_helper, request $phpbb_request, symfony_request $request, router $router, $phpbb_root_path) + { + $this->installer_config = $config; + $this->language = $language; + $this->language_cookie = false; + $this->lang_helper = $lang_helper; + $this->navigation_provider = $nav; + $this->template = $template; + $this->path_helper = $path_helper; + $this->phpbb_request = $phpbb_request; + $this->request = $request; + $this->router = $router; + $this->phpbb_root_path = $phpbb_root_path; + $this->phpbb_admin_path = $phpbb_root_path . 'adm/'; + } + + /** + * Automate setting up the page and creating the response object. + * + * @param string $template_file The template handle to render + * @param string $page_title The title of the page to output + * @param bool $selected_language True to enable language selector it, false otherwise + * @param int $status_code The status code to be sent to the page header + * + * @return Response object containing rendered page + */ + public function render($template_file, $page_title = '', $selected_language = false, $status_code = 200) + { + $this->page_header($page_title, $selected_language); + + $this->template->set_filenames(array( + 'body' => $template_file, + )); + + $response = new Response($this->template->assign_display('body'), $status_code); + + // Set language cookie + if ($this->language_cookie !== false) + { + $cookie = new Cookie('lang', $this->language_cookie, time() + 3600); + $response->headers->setCookie($cookie); + + $this->language_cookie = false; + } + + return $response; + } + + /** + * Returns path from route name + * + * @param string $route_name + * @param array $parameters + * + * @return string + */ + public function route($route_name, $parameters = array()) + { + $url = $this->router->generate($route_name, $parameters); + + return $url; + } + + /** + * Handles language selector form + */ + public function handle_language_select() + { + $lang = null; + + // Check if language form has been submited + $submit = $this->phpbb_request->variable('change_lang', ''); + if (!empty($submit)) + { + $lang = $this->phpbb_request->variable('language', ''); + } + + // Retrieve language from cookie + $lang_cookie = $this->phpbb_request->variable('lang', '', false, request_interface::COOKIE); + if (empty($lang) && !empty($lang_cookie)) + { + $lang = $lang_cookie; + } + + $lang = (!empty($lang) && strpos($lang, '/') === false) ? $lang : null; + $this->language_cookie = $lang; + + $this->render_language_select($lang); + + if ($lang !== null) + { + $this->language->set_user_language($lang, true); + $this->installer_config->set('user_language', $lang); + } + } + + /** + * Process navigation data to reflect active/completed stages + * + * @param \phpbb\install\helper\iohandler\iohandler_interface|null $iohandler + */ + public function handle_navigation($iohandler = null) + { + $nav_data = $this->installer_config->get_navigation_data(); + + // Set active navigation stage + if (isset($nav_data['active']) && is_array($nav_data['active'])) + { + if ($iohandler !== null) + { + $iohandler->set_active_stage_menu($nav_data['active']); + } + + $this->navigation_provider->set_nav_property($nav_data['active'], array( + 'selected' => true, + 'completed' => false, + )); + } + + // Set finished navigation stages + if (isset($nav_data['finished']) && is_array($nav_data['finished'])) + { + foreach ($nav_data['finished'] as $finished_stage) + { + if ($iohandler !== null) + { + $iohandler->set_finished_stage_menu($finished_stage); + } + + $this->navigation_provider->set_nav_property($finished_stage, array( + 'selected' => false, + 'completed' => true, + )); + } + } + } + + /** + * Set default template variables + * + * @param string $page_title Title of the page + * @param bool $selected_language True to enable language selector it, false otherwise + */ + protected function page_header($page_title, $selected_language = false) + { + // Path to templates + $paths = array($this->phpbb_root_path . 'install/update/new/adm/', $this->phpbb_admin_path); + $paths = array_filter($paths, 'is_dir'); + $path = array_shift($paths); + $path = substr($path, strlen($this->phpbb_root_path)); + + $this->template->assign_vars(array( + 'L_CHANGE' => $this->language->lang('CHANGE'), + 'L_COLON' => $this->language->lang('COLON'), + 'L_INSTALL_PANEL' => $this->language->lang('INSTALL_PANEL'), + 'L_SELECT_LANG' => $this->language->lang('SELECT_LANG'), + '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_TEMPLATE_PATH' => $this->path_helper->get_web_root_path() . $path . 'style', + 'T_ASSETS_PATH' => $this->path_helper->get_web_root_path() . $path . '../assets', + + 'S_CONTENT_DIRECTION' => $this->language->lang('DIRECTION'), + 'S_CONTENT_FLOW_BEGIN' => ($this->language->lang('DIRECTION') === 'ltr') ? 'left' : 'right', + 'S_CONTENT_FLOW_END' => ($this->language->lang('DIRECTION') === 'ltr') ? 'right' : 'left', + 'S_CONTENT_ENCODING' => 'UTF-8', + 'S_LANG_SELECT' => $selected_language, + + 'S_USER_LANG' => $this->language->lang('USER_LANG'), + )); + + $this->render_navigation(); + } + + /** + * Render navigation + */ + protected function render_navigation() + { + // Get navigation items + $nav_array = $this->navigation_provider->get(); + $nav_array = $this->sort_navigation_level($nav_array); + + $active_main_menu = $this->get_active_main_menu($nav_array); + + // Pass navigation to template + foreach ($nav_array as $key => $entry) + { + $this->template->assign_block_vars('t_block1', array( + 'L_TITLE' => $this->language->lang($entry['label']), + 'S_SELECTED' => ($active_main_menu === $key), + 'U_TITLE' => $this->route($entry['route']), + )); + + if (is_array($entry[0]) && $active_main_menu === $key) + { + $entry[0] = $this->sort_navigation_level($entry[0]); + + foreach ($entry[0] as $name => $sub_entry) + { + if (isset($sub_entry['stage']) && $sub_entry['stage'] === true) + { + $this->template->assign_block_vars('l_block2', array( + 'L_TITLE' => $this->language->lang($sub_entry['label']), + 'S_SELECTED' => (isset($sub_entry['selected']) && $sub_entry['selected'] === true), + 'S_COMPLETE' => (isset($sub_entry['completed']) && $sub_entry['completed'] === true), + 'STAGE_NAME' => $name, + )); + } + else + { + $this->template->assign_block_vars('l_block1', array( + 'L_TITLE' => $this->language->lang($sub_entry['label']), + 'S_SELECTED' => (isset($sub_entry['route']) && $sub_entry['route'] === $this->request->get('_route')), + 'U_TITLE' => $this->route($sub_entry['route']), + )); + } + } + } + } + } + + /** + * Render language select form + * + * @param string $selected_language + */ + protected function render_language_select($selected_language = null) + { + $langs = $this->lang_helper->get_available_languages(); + foreach ($langs as $lang) + { + $this->template->assign_block_vars('language_select_item', array( + 'VALUE' => $lang['iso'], + 'NAME' => $lang['local_name'], + 'SELECTED' => ($lang['iso'] === $selected_language), + )); + } + } + + /** + * Returns the name of the active main menu item + * + * @param array $nav_array + * + * @return string|bool Returns the name of the active main menu element, if the element not found, returns false + */ + protected function get_active_main_menu($nav_array) + { + $active_route = $this->request->get('_route'); + + foreach ($nav_array as $nav_name => $nav_options) + { + $current_menu = $nav_name; + + if (isset($nav_options['route']) && $nav_options['route'] === $active_route) + { + return $nav_name; + } + + if (is_array($nav_options[0])) + { + foreach ($nav_options[0] as $sub_menus) + { + if (isset($sub_menus['route']) && $sub_menus['route'] === $active_route) + { + return $current_menu; + } + } + } + } + + return false; + } + + /** + * Sorts the top level of navigation array + * + * @param array $nav_array Navigation array + * + * @return array + */ + protected function sort_navigation_level($nav_array) + { + $sorted = array(); + foreach ($nav_array as $key => $nav) + { + $order = (isset($nav['order'])) ? $nav['order'] : 0; + $sorted[$order][$key] = $nav; + } + + // Linearization of navigation array + $nav_array = array(); + ksort($sorted); + foreach ($sorted as $nav) + { + $nav_array = array_merge($nav_array, $nav); + } + + return $nav_array; + } +} diff --git a/phpBB/phpbb/install/controller/install.php b/phpBB/phpbb/install/controller/install.php new file mode 100644 index 0000000000..92506872a3 --- /dev/null +++ b/phpBB/phpbb/install/controller/install.php @@ -0,0 +1,172 @@ +<?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\install\controller; + +use phpbb\exception\http_exception; +use phpbb\install\helper\install_helper; +use phpbb\install\helper\navigation\navigation_provider; +use Symfony\Component\HttpFoundation\StreamedResponse; +use Symfony\Component\HttpFoundation\Response; +use phpbb\install\helper\iohandler\factory; +use phpbb\template\template; +use phpbb\request\request_interface; +use phpbb\install\installer; +use phpbb\language\language; + +/** + * Controller for installing phpBB + */ +class install +{ + /** + * @var helper + */ + protected $controller_helper; + + /** + * @var factory + */ + protected $iohandler_factory; + + /** + * @var navigation_provider + */ + protected $menu_provider; + + /** + * @var language + */ + protected $language; + + /** + * @var template + */ + protected $template; + + /** + * @var request_interface + */ + protected $request; + + /** + * @var installer + */ + protected $installer; + + /** + * @var install_helper + */ + protected $install_helper; + + /** + * Constructor + * + * @param helper $helper + * @param factory $factory + * @param navigation_provider $nav_provider + * @param language $language + * @param template $template + * @param request_interface $request + * @param installer $installer + * @param install_helper $install_helper + */ + public function __construct(helper $helper, factory $factory, navigation_provider $nav_provider, language $language, template $template, request_interface $request, installer $installer, install_helper $install_helper) + { + $this->controller_helper = $helper; + $this->iohandler_factory = $factory; + $this->menu_provider = $nav_provider; + $this->language = $language; + $this->template = $template; + $this->request = $request; + $this->installer = $installer; + $this->install_helper = $install_helper; + } + + /** + * Controller logic + * + * @return Response|StreamedResponse + * + * @throws http_exception When phpBB is already installed + */ + public function handle() + { + if ($this->install_helper->is_phpbb_installed()) + { + throw new http_exception(403, 'INSTALL_PHPBB_INSTALLED'); + } + + $this->template->assign_vars(array( + 'U_ACTION' => $this->controller_helper->route('phpbb_installer_install'), + )); + + // Set up input-output handler + if ($this->request->is_ajax()) + { + $this->iohandler_factory->set_environment('ajax'); + } + else + { + $this->iohandler_factory->set_environment('nojs'); + } + + // Set the appropriate input-output handler + $this->installer->set_iohandler($this->iohandler_factory->get()); + $this->controller_helper->handle_language_select(); + + if ($this->request->is_ajax()) + { + $installer = $this->installer; + $response = new StreamedResponse(); + $response->setCallback(function() use ($installer) { + $installer->run(); + }); + + // Try to bypass any server output buffers + $response->headers->set('X-Accel-Buffering', 'no'); + + return $response; + } + else + { + // Determine whether the installation was started or not + if (true) + { + // Set active stage + $this->menu_provider->set_nav_property( + array('install', 0, 'introduction'), + array( + 'selected' => true, + 'completed' => false, + ) + ); + + // If not, let's render the welcome page + $this->template->assign_vars(array( + 'SHOW_INSTALL_START_FORM' => true, + 'TITLE' => $this->language->lang('INSTALL_INTRO'), + 'CONTENT' => $this->language->lang('INSTALL_INTRO_BODY'), + )); + + /** @var \phpbb\install\helper\iohandler\iohandler_interface $iohandler */ + $iohandler = $this->iohandler_factory->get(); + $this->controller_helper->handle_navigation($iohandler); + + return $this->controller_helper->render('installer_install.html', 'INSTALL', true); + } + + // @todo: implement no js controller logic + } + } +} diff --git a/phpBB/phpbb/install/controller/installer_index.php b/phpBB/phpbb/install/controller/installer_index.php new file mode 100644 index 0000000000..c2d9572284 --- /dev/null +++ b/phpBB/phpbb/install/controller/installer_index.php @@ -0,0 +1,81 @@ +<?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\install\controller; + +class installer_index +{ + /** + * @var helper + */ + protected $helper; + + /** + * @var \phpbb\language\language + */ + protected $language; + + /** + * @var \phpbb\template\template + */ + protected $template; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param helper $helper + * @param \phpbb\language\language $language + * @param \phpbb\template\template $template + * @param string $phpbb_root_path + */ + public function __construct(helper $helper, \phpbb\language\language $language, \phpbb\template\template $template, $phpbb_root_path) + { + $this->helper = $helper; + $this->language = $language; + $this->template = $template; + $this->phpbb_root_path = $phpbb_root_path; + } + + public function handle($mode) + { + $this->helper->handle_language_select(); + + switch ($mode) + { + case "intro": + $title = $this->language->lang('INTRODUCTION_TITLE'); + $body = $this->language->lang('INTRODUCTION_BODY'); + break; + case "support": + $title = $this->language->lang('SUPPORT_TITLE'); + $body = $this->language->lang('SUPPORT_BODY'); + break; + case "license": + $title = $this->language->lang('LICENSE_TITLE'); + $body = implode("<br/>\n", file($this->phpbb_root_path . 'docs/LICENSE.txt')); + break; + } + + $this->template->assign_vars(array( + 'TITLE' => $title, + 'BODY' => $body, + )); + + return $this->helper->render('installer_main.html', $title, true); + } +} diff --git a/phpBB/phpbb/install/controller/timeout_check.php b/phpBB/phpbb/install/controller/timeout_check.php new file mode 100644 index 0000000000..1c90e3caf3 --- /dev/null +++ b/phpBB/phpbb/install/controller/timeout_check.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\install\controller; + +use Symfony\Component\HttpFoundation\JsonResponse; + +class timeout_check +{ + /** + * @var helper + */ + protected $helper; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param helper $helper + * @param string $phpbb_root_path + */ + public function __construct(helper $helper, $phpbb_root_path) + { + $this->helper = $helper; + $this->phpbb_root_path = $phpbb_root_path; + } + + /** + * Controller for querying installer status + */ + public function status() + { + $lock_file = $this->phpbb_root_path . 'store/io_lock.lock'; + $response = new JsonResponse(); + + if (!file_exists($lock_file)) + { + $response->setData(array( + 'status' => 'fail', + )); + } + else + { + $fp = @fopen($lock_file, 'r'); + + if ($fp && flock($fp, LOCK_EX | LOCK_NB)) + { + $status = (filesize($lock_file) >= 2 && fread($fp, 2) === 'ok') ? 'continue' : 'fail'; + + $response->setData(array( + 'status' => $status, + )); + flock($fp, LOCK_UN); + fclose($fp); + } + else + { + $response->setData(array( + 'status' => 'running', + )); + } + } + + return $response; + } +} diff --git a/phpBB/phpbb/install/controller/update.php b/phpBB/phpbb/install/controller/update.php new file mode 100644 index 0000000000..6b88827940 --- /dev/null +++ b/phpBB/phpbb/install/controller/update.php @@ -0,0 +1,166 @@ +<?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\install\controller; + +use phpbb\exception\http_exception; +use phpbb\install\helper\install_helper; +use phpbb\install\helper\iohandler\factory; +use phpbb\install\helper\navigation\navigation_provider; +use phpbb\install\installer; +use phpbb\language\language; +use phpbb\request\request_interface; +use phpbb\template\template; +use Symfony\Component\HttpFoundation\StreamedResponse; + +/** + * Updater controller + */ +class update +{ + /** + * @var helper + */ + protected $controller_helper; + + /** + * @var installer + */ + protected $installer; + + /** + * @var install_helper + */ + protected $install_helper; + + /** + * @var factory + */ + protected $iohandler_factory; + + /** + * @var language + */ + protected $language; + + /** + * @var navigation_provider + */ + protected $menu_provider; + + /** + * @var request_interface + */ + protected $request; + + /** + * @var template + */ + protected $template; + + /** + * Constructor + * + * @param helper $controller_helper + * @param installer $installer + * @param install_helper $install_helper + * @param factory $iohandler + * @param language $language + * @param navigation_provider $menu_provider + * @param request_interface $request + * @param template $template + */ + public function __construct(helper $controller_helper, installer $installer, install_helper $install_helper, factory $iohandler, language $language, navigation_provider $menu_provider, request_interface $request, template $template) + { + $this->controller_helper = $controller_helper; + $this->installer = $installer; + $this->install_helper = $install_helper; + $this->iohandler_factory = $iohandler; + $this->language = $language; + $this->menu_provider = $menu_provider; + $this->request = $request; + $this->template = $template; + } + + /** + * Controller entry point + * + * @return Response|StreamedResponse + * + * @throws http_exception When phpBB is not installed + */ + public function handle() + { + if (!$this->install_helper->is_phpbb_installed()) + { + throw new http_exception(403, 'INSTALL_PHPBB_NOT_INSTALLED'); + } + + $this->template->assign_vars(array( + 'U_ACTION' => $this->controller_helper->route('phpbb_installer_update'), + )); + + // Set up input-output handler + if ($this->request->is_ajax()) + { + $this->iohandler_factory->set_environment('ajax'); + } + else + { + $this->iohandler_factory->set_environment('nojs'); + } + + // Set the appropriate input-output handler + $this->installer->set_iohandler($this->iohandler_factory->get()); + $this->controller_helper->handle_language_select(); + + // Render the intro page + if ($this->request->is_ajax()) + { + $installer = $this->installer; + $response = new StreamedResponse(); + $response->setCallback(function() use ($installer) { + $installer->run(); + }); + + // Try to bypass any server output buffers + $response->headers->set('X-Accel-Buffering', 'no'); + $response->headers->set('Content-type', 'application/json'); + + return $response; + } + else + { + // Set active stage + $this->menu_provider->set_nav_property( + array('update', 0, 'introduction'), + array( + 'selected' => true, + 'completed' => false, + ) + ); + + $this->template->assign_vars(array( + 'SHOW_INSTALL_START_FORM' => true, + 'TITLE' => $this->language->lang('UPDATE_INSTALLATION'), + 'CONTENT' => $this->language->lang('UPDATE_INSTALLATION_EXPLAIN'), + )); + + /** @var \phpbb\install\helper\iohandler\iohandler_interface $iohandler */ + $iohandler = $this->iohandler_factory->get(); + $this->controller_helper->handle_navigation($iohandler); + + return $this->controller_helper->render('installer_update.html', 'UPDATE_INSTALLATION', true); + } + } +} diff --git a/phpBB/phpbb/install/event/kernel_exception_subscriber.php b/phpBB/phpbb/install/event/kernel_exception_subscriber.php new file mode 100644 index 0000000000..60b7d9a400 --- /dev/null +++ b/phpBB/phpbb/install/event/kernel_exception_subscriber.php @@ -0,0 +1,126 @@ +<?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\install\event; + +use phpbb\exception\exception_interface; +use phpbb\install\controller\helper; +use phpbb\language\language; +use phpbb\template\template; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; +use Symfony\Component\HttpFoundation\JsonResponse; + +/** + * Exception handler for the installer + */ +class kernel_exception_subscriber implements EventSubscriberInterface +{ + /** + * @var helper + */ + protected $controller_helper; + + /** + * @var language + */ + protected $language; + + /** + * @var template + */ + protected $template; + + /** + * Constructor + * + * @param helper $controller_helper + * @param language $language + * @param template $template + */ + public function __construct(helper $controller_helper, language $language, template $template) + { + $this->controller_helper = $controller_helper; + $this->language = $language; + $this->template = $template; + } + + /** + * This listener is run when the KernelEvents::EXCEPTION event is triggered + * + * @param GetResponseForExceptionEvent $event + */ + public function on_kernel_exception(GetResponseForExceptionEvent $event) + { + $exception = $event->getException(); + $message = $exception->getMessage(); + + if ($exception instanceof exception_interface) + { + $message = $this->language->lang_array($message, $exception->get_parameters()); + } + + if (!$event->getRequest()->isXmlHttpRequest()) + { + $this->template->assign_vars(array( + 'TITLE' => $this->language->lang('INFORMATION'), + 'BODY' => $message, + )); + + $response = $this->controller_helper->render( + 'installer_main.html', + $this->language->lang('INFORMATION'), + false, + 500 + ); + } + else + { + $data = array(); + + if (!empty($message)) + { + $data['message'] = $message; + } + + if (defined('DEBUG')) + { + $data['trace'] = $exception->getTrace(); + } + + $response = new JsonResponse($data, 500); + } + + if ($exception instanceof HttpExceptionInterface) + { + $response->setStatusCode($exception->getStatusCode()); + $response->headers->add($exception->getHeaders()); + } + + $event->setResponse($response); + } + + /** + * Returns an array of events the object is subscribed to + * + * @return array Array of events the object is subscribed to + */ + static public function getSubscribedEvents() + { + return array( + KernelEvents::EXCEPTION => 'on_kernel_exception', + ); + } +} diff --git a/phpBB/phpbb/install/exception/cannot_build_container_exception.php b/phpBB/phpbb/install/exception/cannot_build_container_exception.php new file mode 100644 index 0000000000..6cf12b008b --- /dev/null +++ b/phpBB/phpbb/install/exception/cannot_build_container_exception.php @@ -0,0 +1,22 @@ +<?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\install\exception; + +/** + * Thrown when the container cannot be built + */ +class cannot_build_container_exception extends installer_exception +{ + +} diff --git a/phpBB/phpbb/install/exception/file_updater_failure_exception.php b/phpBB/phpbb/install/exception/file_updater_failure_exception.php new file mode 100644 index 0000000000..46ba2ed32d --- /dev/null +++ b/phpBB/phpbb/install/exception/file_updater_failure_exception.php @@ -0,0 +1,22 @@ +<?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\install\exception; + +/** + * Thrown when the file updater fails + */ +class file_updater_failure_exception extends installer_exception +{ + +} diff --git a/phpBB/phpbb/install/exception/installer_config_not_writable_exception.php b/phpBB/phpbb/install/exception/installer_config_not_writable_exception.php new file mode 100644 index 0000000000..51864c5dca --- /dev/null +++ b/phpBB/phpbb/install/exception/installer_config_not_writable_exception.php @@ -0,0 +1,22 @@ +<?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\install\exception; + +/** + * Thrown when installer config is not writable to disk + */ +class installer_config_not_writable_exception extends installer_exception +{ + +} diff --git a/phpBB/phpbb/install/exception/installer_exception.php b/phpBB/phpbb/install/exception/installer_exception.php new file mode 100644 index 0000000000..f17dca8f17 --- /dev/null +++ b/phpBB/phpbb/install/exception/installer_exception.php @@ -0,0 +1,24 @@ +<?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\install\exception; + +use phpbb\exception\runtime_exception; + +/** + * Installer's base exception + */ +class installer_exception extends runtime_exception +{ + +} diff --git a/phpBB/phpbb/install/exception/invalid_dbms_exception.php b/phpBB/phpbb/install/exception/invalid_dbms_exception.php new file mode 100644 index 0000000000..38de5f613a --- /dev/null +++ b/phpBB/phpbb/install/exception/invalid_dbms_exception.php @@ -0,0 +1,22 @@ +<?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\install\exception; + +/** + * Thrown when an unavailable DBMS has been selected + */ +class invalid_dbms_exception extends installer_exception +{ + +} diff --git a/phpBB/phpbb/install/exception/jump_to_restart_point_exception.php b/phpBB/phpbb/install/exception/jump_to_restart_point_exception.php new file mode 100644 index 0000000000..b628c4fbe3 --- /dev/null +++ b/phpBB/phpbb/install/exception/jump_to_restart_point_exception.php @@ -0,0 +1,44 @@ +<?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\install\exception; + +class jump_to_restart_point_exception extends installer_exception +{ + /** + * @var string + */ + protected $restart_point_name; + + /** + * Constructor + * + * @param string $restart_point_name + */ + public function __construct($restart_point_name) + { + $this->restart_point_name = $restart_point_name; + + parent::__construct(); + } + + /** + * Returns the restart point's name + * + * @return string + */ + public function get_restart_point_name() + { + return $this->restart_point_name; + } +} diff --git a/phpBB/phpbb/install/exception/resource_limit_reached_exception.php b/phpBB/phpbb/install/exception/resource_limit_reached_exception.php new file mode 100644 index 0000000000..025e09fbd3 --- /dev/null +++ b/phpBB/phpbb/install/exception/resource_limit_reached_exception.php @@ -0,0 +1,22 @@ +<?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\install\exception; + +/** + * Thrown when the installer is out of memory or time + */ +class resource_limit_reached_exception extends installer_exception +{ + +} diff --git a/phpBB/phpbb/install/exception/user_interaction_required_exception.php b/phpBB/phpbb/install/exception/user_interaction_required_exception.php new file mode 100644 index 0000000000..d65a448841 --- /dev/null +++ b/phpBB/phpbb/install/exception/user_interaction_required_exception.php @@ -0,0 +1,25 @@ +<?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\install\exception; + +/** + * This exception should be thrown when user interaction is inevitable + * + * Note: Please note that the output should already be setup for the user + * when you use throw this exception + */ +class user_interaction_required_exception extends installer_exception +{ + +} diff --git a/phpBB/phpbb/install/helper/config.php b/phpBB/phpbb/install/helper/config.php new file mode 100644 index 0000000000..fad6749019 --- /dev/null +++ b/phpBB/phpbb/install/helper/config.php @@ -0,0 +1,450 @@ +<?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\install\helper; + +use phpbb\install\exception\installer_config_not_writable_exception; + +/** + * Stores common settings and installation status + */ +class config +{ + /** + * @var \phpbb\filesystem\filesystem_interface + */ + protected $filesystem; + + /** + * Array which contains config settings for the installer + * + * The array will also store all the user input, as well as any + * data that is passed to other tasks by a task. + * + * @var array + */ + protected $installer_config; + + /** + * @var string + */ + protected $install_config_file; + + /** + * @var \bantu\IniGetWrapper\IniGetWrapper + */ + protected $php_ini; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Array containing progress information + * + * @var array + */ + protected $progress_data; + + /** + * Array containing system information + * + * The array contains run time and memory limitations. + * + * @var array + */ + protected $system_data; + + /** + * Array containing navigation bar information + * + * @var array + */ + protected $navigation_data; + + /** + * Flag indicating that config file should be cleaned up + * + * @var bool + */ + protected $do_clean_up; + + /** + * Constructor + */ + public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, \bantu\IniGetWrapper\IniGetWrapper $php_ini, $phpbb_root_path) + { + $this->filesystem = $filesystem; + $this->php_ini = $php_ini; + $this->phpbb_root_path = $phpbb_root_path; + $this->do_clean_up = false; + + // Set up data arrays + $this->navigation_data = array(); + $this->installer_config = array(); + $this->system_data = array(); + $this->progress_data = array( + 'last_task_module_name' => '', // Stores the service name of the latest finished module + 'last_task_module_index' => 0, // Stores the index of the latest finished module + 'last_task_index' => 0, // Stores the index of the latest finished task + 'max_task_progress' => 0, + 'current_task_progress' => 0, + '_restart_points' => array(), + 'use_restart_point' => false, + ); + + $this->install_config_file = $this->phpbb_root_path . 'store/install_config.php'; + + $this->setup_system_data(); + } + + /** + * Returns data for a specified parameter + * + * @param string $param_name Name of the parameter to return + * @param mixed $default Default value to return when the specified data + * does not exist. + * + * @return mixed value of the specified parameter or the default value if the data + * cannot be recovered. + */ + public function get($param_name, $default = false) + { + return (isset($this->installer_config[$param_name])) ? $this->installer_config[$param_name] : $default; + } + + /** + * Sets a parameter in installer_config + * + * @param string $param_name Name of the parameter + * @param mixed $value Values to set the parameter + */ + public function set($param_name, $value) + { + $this->installer_config = array_merge($this->installer_config, array( + $param_name => $value, + )); + } + + /** + * Returns system parameter + * + * @param string $param_name Name of the parameter + * + * @return mixed Returns system parameter if it is defined, false otherwise + */ + public function system_get($param_name) + { + return (isset($this->system_data[$param_name])) ? $this->system_data[$param_name] : false; + } + + /** + * Returns remaining time until the run time limit + * + * @return int Remaining time until the run time limit in seconds + */ + public function get_time_remaining() + { + if ($this->system_data['max_execution_time'] <= 0) + { + return PHP_INT_MAX; + } + + return ($this->system_data['start_time'] + $this->system_data['max_execution_time']) - microtime(true); + } + + /** + * Returns remaining memory available for PHP + * + * @return int Remaining memory until reaching the limit + */ + public function get_memory_remaining() + { + if ($this->system_data['memory_limit'] <= 0) + { + return 1; + } + + if (function_exists('memory_get_usage')) + { + return ($this->system_data['memory_limit'] - memory_get_usage()); + } + + // If we cannot get the information then just return a positive number (and cross fingers) + return 1; + } + + /** + * Saves the latest executed task + * + * @param int $task_service_index Index of the installer task service in the module + */ + public function set_finished_task($task_service_index) + { + $this->progress_data['last_task_index'] = $task_service_index; + } + + /** + * Set active module + * + * @param string $module_service_name Name of the installer module service + * @param int $module_service_index Index of the installer module service + */ + public function set_active_module($module_service_name, $module_service_index) + { + $this->progress_data['last_task_module_name'] = $module_service_name; + $this->progress_data['last_task_module_index'] = $module_service_index; + } + + /** + * Getter for progress data + * + * @return array + */ + public function get_progress_data() + { + return $this->progress_data; + } + + /** + * Recovers install configuration from file + */ + public function load_config() + { + if (!$this->filesystem->exists($this->install_config_file)) + { + return; + } + + $file_content = @file_get_contents($this->install_config_file); + $serialized_data = trim(substr($file_content, 8)); + + $installer_config = array(); + $progress_data = array(); + $navigation_data = array(); + + if (!empty($serialized_data)) + { + $unserialized_data = json_decode($serialized_data, true); + + $installer_config = (is_array($unserialized_data['installer_config'])) ? $unserialized_data['installer_config'] : array(); + $progress_data = (is_array($unserialized_data['progress_data'])) ? $unserialized_data['progress_data'] : array(); + $navigation_data = (is_array($unserialized_data['navigation_data'])) ? $unserialized_data['navigation_data'] : array(); + } + + $this->installer_config = array_merge($this->installer_config, $installer_config); + $this->progress_data = array_merge($this->progress_data, $progress_data); + $this->navigation_data = array_merge($this->navigation_data, $navigation_data); + } + + /** + * Creates a progress restart point + * + * Restart points can be used to repeat certain tasks periodically. + * You need to call this method from the first task you want to repeat. + * + * @param string $name Name of the restart point + */ + public function create_progress_restart_point($name) + { + $tmp_progress_data = $this->progress_data; + unset($tmp_progress_data['_restart_points']); + + $this->progress_data['_restart_points'][$name] = $tmp_progress_data; + } + + /** + * Set restart point to continue from + * + * @param string $name Name of the restart point + * + * @return bool Returns false if the restart point name does not exist, otherwise true + */ + public function jump_to_restart_point($name) + { + if (!isset($this->progress_data['_restart_points'][$name]) || empty($this->progress_data['_restart_points'][$name])) + { + return false; + } + + foreach ($this->progress_data['_restart_points'][$name] as $key => $value) + { + $this->progress_data[$key] = $value; + } + + return true; + } + + /** + * Returns whether a restart point with a given name exists or not + * + * @param string $name Name of the restart point + * + * @return bool + */ + public function has_restart_point($name) + { + return isset($this->progress_data['_restart_points'][$name]); + } + + /** + * Dumps install configuration to disk + */ + public function save_config() + { + if ($this->do_clean_up) + { + @unlink($this->install_config_file); + return; + } + + // Create array to save + $save_array = array( + 'installer_config' => $this->installer_config, + 'progress_data' => $this->progress_data, + 'navigation_data' => $this->navigation_data, + ); + + // Create file content + $file_content = '<?php // '; + $file_content .= json_encode($save_array); + $file_content .= "\n"; + + // Dump file_content to disk + $fp = @fopen($this->install_config_file, 'w'); + if (!$fp) + { + throw new installer_config_not_writable_exception(); + } + + fwrite($fp, $file_content); + fclose($fp); + } + + /** + * Increments the task progress + * + * @param int $increment_by The amount to increment by + */ + public function increment_current_task_progress($increment_by = 1) + { + $this->progress_data['current_task_progress'] += $increment_by; + + if ($this->progress_data['current_task_progress'] > $this->progress_data['max_task_progress']) + { + $this->progress_data['current_task_progress'] = $this->progress_data['max_task_progress']; + } + } + + /** + * Sets the task progress to a specific number + * + * @param int $task_progress The task progress number to be set + */ + public function set_current_task_progress($task_progress) + { + $this->progress_data['current_task_progress'] = $task_progress; + } + + /** + * Sets the number of tasks belonging to the installer in the current mode. + * + * @param int $task_progress_count Number of tasks + */ + public function set_task_progress_count($task_progress_count) + { + $this->progress_data['max_task_progress'] = $task_progress_count; + } + + /** + * Returns the number of the current task being executed + * + * @return int + */ + public function get_current_task_progress() + { + return $this->progress_data['current_task_progress']; + } + + /** + * Returns the number of tasks belonging to the installer in the current mode. + * + * @return int + */ + public function get_task_progress_count() + { + return $this->progress_data['max_task_progress']; + } + + /** + * Marks stage as completed in the navigation bar + * + * @param array $nav_path Array to the navigation elem + */ + public function set_finished_navigation_stage($nav_path) + { + if (isset($this->navigation_data['finished']) && in_array($nav_path, $this->navigation_data['finished'])) + { + return; + } + + $this->navigation_data['finished'][] = $nav_path; + } + + /** + * Marks stage as active in the navigation bar + * + * @param array $nav_path Array to the navigation elem + */ + public function set_active_navigation_stage($nav_path) + { + $this->navigation_data['active'] = $nav_path; + } + + /** + * Returns navigation data + * + * @return array + */ + public function get_navigation_data() + { + return $this->navigation_data; + } + + /** + * Removes install config file + */ + public function clean_up_config_file() + { + $this->do_clean_up = true; + @unlink($this->install_config_file); + } + + /** + * Filling up system_data array + */ + protected function setup_system_data() + { + // Query maximum runtime from php.ini + $execution_time = $this->php_ini->getNumeric('max_execution_time'); + $execution_time = min(15, $execution_time / 2); + $this->system_data['max_execution_time'] = $execution_time; + + // Set start time + $this->system_data['start_time'] = microtime(true); + + // Get memory limit + $this->system_data['memory_limit'] = $this->php_ini->getBytes('memory_limit'); + } +} diff --git a/phpBB/phpbb/install/helper/container_factory.php b/phpBB/phpbb/install/helper/container_factory.php new file mode 100644 index 0000000000..9e372fecde --- /dev/null +++ b/phpBB/phpbb/install/helper/container_factory.php @@ -0,0 +1,191 @@ +<?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\install\helper; + +use phpbb\install\exception\cannot_build_container_exception; +use phpbb\language\language; +use phpbb\request\request; + +class container_factory +{ + /** + * @var language + */ + protected $language; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * @var \phpbb\request\request + */ + protected $request; + + /** + * @var update_helper + */ + protected $update_helper; + + /** + * The full phpBB container + * + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + protected $container; + + /** + * Constructor + * + * @param language $language Language service + * @param request $request Request interface + * @param update_helper $update_helper Update helper + * @param string $phpbb_root_path Path to phpBB's root + * @param string $php_ext Extension of PHP files + */ + public function __construct(language $language, request $request, update_helper $update_helper, $phpbb_root_path, $php_ext) + { + $this->language = $language; + $this->request = $request; + $this->update_helper = $update_helper; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + $this->container = null; + } + + /** + * Container getter + * + * @param null|string $service_name Name of the service to return + * + * @return \Symfony\Component\DependencyInjection\ContainerInterface|Object phpBB's dependency injection container + * or the service specified in $service_name + * + * @throws \phpbb\install\exception\cannot_build_container_exception When container cannot be built + * @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException If the service is not defined + * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException When a circular reference is detected + * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException When the service is not defined + */ + public function get($service_name = null) + { + // Check if container was built, if not try to build it + if ($this->container === null) + { + $this->build_container(); + } + + return ($service_name === null) ? $this->container : $this->container->get($service_name); + } + + /** + * Returns the specified parameter from the container + * + * @param string $param_name + * + * @return mixed + * + * @throws \phpbb\install\exception\cannot_build_container_exception When container cannot be built + */ + public function get_parameter($param_name) + { + // Check if container was built, if not try to build it + if ($this->container === null) + { + $this->build_container(); + } + + return $this->container->getParameter($param_name); + } + + /** + * Build dependency injection container + * + * @throws \phpbb\install\exception\cannot_build_container_exception When container cannot be built + */ + protected function build_container() + { + // If the container has been already built just return. + // Although this should never happen + if ($this->container instanceof \Symfony\Component\DependencyInjection\ContainerInterface) + { + return; + } + + // Check whether container can be built + // We need config.php for that so let's check if it has been set up yet + if (!filesize($this->phpbb_root_path . 'config.' . $this->php_ext)) + { + throw new cannot_build_container_exception(); + } + + $phpbb_config_php_file = new \phpbb\config_php_file($this->phpbb_root_path, $this->php_ext); + $phpbb_container_builder = new \phpbb\di\container_builder($this->phpbb_root_path, $this->php_ext); + + // For BC with functions that we need during install + global $phpbb_container, $table_prefix; + + $disable_super_globals = $this->request->super_globals_disabled(); + + // This is needed because container_builder::get_env_parameters() uses $_SERVER + if ($disable_super_globals) + { + $this->request->enable_super_globals(); + } + + $other_config_path = $this->phpbb_root_path . 'install/update/new/config'; + $config_path = (is_dir($other_config_path)) ? $other_config_path : $this->phpbb_root_path . 'config'; + + $this->container = $phpbb_container_builder + ->with_environment('production') + ->with_config($phpbb_config_php_file) + ->with_config_path($config_path) + ->without_compiled_container() + ->get_container(); + + // Setting request is required for the compatibility globals as those are generated from + // this container + if (!$this->container->isFrozen()) + { + $this->container->register('request')->setSynthetic(true); + $this->container->register('language')->setSynthetic(true); + } + + $this->container->set('request', $this->request); + $this->container->set('language', $this->language); + + $this->container->compile(); + + $phpbb_container = $this->container; + $table_prefix = $phpbb_config_php_file->get('table_prefix'); + + // Restore super globals to previous state + if ($disable_super_globals) + { + $this->request->disable_super_globals(); + } + + // Get compatibilty globals and constants + $this->update_helper->include_file('includes/compatibility_globals.' . $this->php_ext); + + register_compatibility_globals(); + + $this->update_helper->include_file('includes/constants.' . $this->php_ext); + } +} diff --git a/phpBB/phpbb/install/helper/database.php b/phpBB/phpbb/install/helper/database.php new file mode 100644 index 0000000000..192f0a3654 --- /dev/null +++ b/phpBB/phpbb/install/helper/database.php @@ -0,0 +1,430 @@ +<?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\install\helper; + +use phpbb\install\exception\invalid_dbms_exception; + +/** + * Database related general functionality for installer + */ +class database +{ + /** + * @var \phpbb\filesystem\filesystem_interface + */ + protected $filesystem; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var array + */ + protected $supported_dbms = array( + // Note: php 5.5 alpha 2 deprecated mysql. + // Keep mysqli before mysql in this list. + 'mysqli' => array( + 'LABEL' => 'MySQL with MySQLi Extension', + 'SCHEMA' => 'mysql_41', + 'MODULE' => 'mysqli', + 'DELIM' => ';', + 'DRIVER' => 'phpbb\db\driver\mysqli', + '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', + 'MODULE' => 'odbc', + 'DELIM' => ';', + 'DRIVER' => 'phpbb\db\driver\mssql_odbc', + 'AVAILABLE' => true, + '2.0.x' => true, + ), + 'mssqlnative' => array( + 'LABEL' => 'MS SQL Server 2005+ [ Native ]', + 'SCHEMA' => 'mssql', + 'MODULE' => 'sqlsrv', + 'DELIM' => ';', + 'DRIVER' => 'phpbb\db\driver\mssqlnative', + 'AVAILABLE' => true, + '2.0.x' => false, + ), + 'oracle' => array( + 'LABEL' => 'Oracle', + 'SCHEMA' => 'oracle', + 'MODULE' => 'oci8', + 'DELIM' => '/', + 'DRIVER' => 'phpbb\db\driver\oracle', + 'AVAILABLE' => true, + '2.0.x' => false, + ), + 'postgres' => array( + 'LABEL' => 'PostgreSQL 8.3+', + 'SCHEMA' => 'postgres', + 'MODULE' => 'pgsql', + 'DELIM' => ';', + 'DRIVER' => 'phpbb\db\driver\postgres', + 'AVAILABLE' => true, + '2.0.x' => true, + ), + 'sqlite3' => array( + 'LABEL' => 'SQLite3', + 'SCHEMA' => 'sqlite', + 'MODULE' => 'sqlite3', + 'DELIM' => ';', + 'DRIVER' => 'phpbb\db\driver\sqlite3', + 'AVAILABLE' => true, + '2.0.x' => false, + ), + ); + + /** + * Constructor + * + * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem interface + * @param string $phpbb_root_path Path to phpBB's root + */ + public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path) + { + $this->filesystem = $filesystem; + $this->phpbb_root_path = $phpbb_root_path; + } + + /** + * Returns an array of available DBMS supported by phpBB + * + * If a DBMS is specified it will only return data for that DBMS + * and will load its extension if necessary. + * + * @param mixed $dbms name of the DBMS that's info is required or false for all DBMS info + * @param bool $return_unavailable set it to true if you expect unavailable but supported DBMS + * returned as well + * @param bool $only_20x_options set it to true if you only want to recover 2.0.x options + * + * @return array Array of available and supported DBMS + */ + public function get_available_dbms($dbms = false, $return_unavailable = false, $only_20x_options = false) + { + $available_dbms = $this->supported_dbms; + + if ($dbms) + { + if (isset($this->supported_dbms[$dbms])) + { + $available_dbms = array($dbms => $this->supported_dbms[$dbms]); + } + else + { + return array(); + } + } + + $any_dbms_available = false; + foreach ($available_dbms as $db_name => $db_array) + { + if ($only_20x_options && !$db_array['2.0.x']) + { + if ($return_unavailable) + { + $available_dbms[$db_name]['AVAILABLE'] = false; + } + else + { + unset($available_dbms[$db_name]); + } + + continue; + } + + $dll = $db_array['MODULE']; + if (!@extension_loaded($dll)) + { + if ($return_unavailable) + { + $available_dbms[$db_name]['AVAILABLE'] = false; + } + else + { + unset($available_dbms[$db_name]); + } + + continue; + } + + $any_dbms_available = true; + } + + if ($return_unavailable) + { + $available_dbms['ANY_DB_SUPPORT'] = $any_dbms_available; + } + + return $available_dbms; + } + + /** + * Removes "/* style" as well as "# style" comments from $input. + * + * @param string $sql_query Input string + * + * @return string Input string with comments removed + */ + public function remove_comments($sql_query) + { + // Remove /* */ comments (http://ostermiller.org/findcomment.html) + $sql_query = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $sql_query); + + // Remove # style comments + $sql_query = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $sql_query)); + + return $sql_query; + } + + /** + * split_sql_file() will split an uploaded sql file into single sql statements. + * + * Note: expects trim() to have already been run on $sql. + * + * @param string $sql SQL statements + * @param string $delimiter Delimiter between sql statements + * + * @return array Array of sql statements + */ + public function split_sql_file($sql, $delimiter) + { + $sql = str_replace("\r" , '', $sql); + $data = preg_split('/' . preg_quote($delimiter, '/') . '$/m', $sql); + + $data = array_map('trim', $data); + + // The empty case + $end_data = end($data); + + if (empty($end_data)) + { + unset($data[key($data)]); + } + + return $data; + } + + /** + * Validates table prefix + * + * @param string $dbms The selected dbms + * @param string $table_prefix The table prefix to validate + * + * @return bool|array true if table prefix is valid, array of errors otherwise + * + * @throws \phpbb\install\exception\invalid_dbms_exception When $dbms is not a valid + */ + public function validate_table_prefix($dbms, $table_prefix) + { + $errors = array(); + + if (!preg_match('#^[a-zA-Z][a-zA-Z0-9_]*$#', $table_prefix)) + { + $errors[] = array( + 'title' => 'INST_ERR_DB_INVALID_PREFIX', + ); + } + + // Do dbms specific checks + $dbms_info = $this->get_available_dbms($dbms); + switch ($dbms_info[$dbms]['SCHEMA']) + { + case 'mysql': + case 'mysql_41': + $prefix_length = 36; + break; + case 'mssql': + $prefix_length = 90; + break; + case 'oracle': + $prefix_length = 6; + break; + case 'postgres': + $prefix_length = 36; + break; + case 'sqlite': + $prefix_length = 200; + break; + default: + throw new invalid_dbms_exception(); + break; + } + + // Check the prefix length to ensure that index names are not too long + if (strlen($table_prefix) > $prefix_length) + { + $errors[] = array( + 'title' => array('INST_ERR_PREFIX_TOO_LONG', $prefix_length), + ); + } + + return (empty($errors)) ? true : $errors; + } + + /** + * Check if the user provided database parameters are correct + * + * This function checks the database connection data and also checks for + * any other problems that could cause an error during the installation + * such as if there is any database table names conflicting. + * + * Note: The function assumes that $table_prefix has been already validated + * with validate_table_prefix(). + * + * @param string $dbms Selected database type + * @param string $dbhost Database host address + * @param int $dbport Database port number + * @param string $dbuser Database username + * @param string $dbpass Database password + * @param string $dbname Database name + * @param string $table_prefix Database table prefix + * + * @return array|bool Returns true if test is successful, array of errors otherwise + */ + public function check_database_connection($dbms, $dbhost, $dbport, $dbuser, $dbpass, $dbname, $table_prefix) + { + $dbms_info = $this->get_available_dbms($dbms); + $dbms_info = $dbms_info[$dbms]; + $errors = array(); + + // Instantiate it and set return on error true + /** @var \phpbb\db\driver\driver_interface $db */ + $db = new $dbms_info['DRIVER']; + $db->sql_return_on_error(true); + + // Check that we actually have a database name before going any further + if (!in_array($dbms_info['SCHEMA'], array('sqlite', 'oracle'), true) && $dbname === '') + { + $errors[] = array( + 'title' => 'INST_ERR_DB_NO_NAME', + ); + } + + // Make sure we don't have a daft user who thinks having the SQLite database in the forum directory is a good idea + if ($dbms_info['SCHEMA'] === 'sqlite' + && stripos($this->filesystem->realpath($dbhost), $this->filesystem->realpath($this->phpbb_root_path) === 0)) + { + $errors[] = array( + 'title' =>'INST_ERR_DB_FORUM_PATH', + ); + } + + // Try to connect to db + if (is_array($db->sql_connect($dbhost, $dbuser, $dbpass, $dbname, $dbport, false, true))) + { + $db_error = $db->sql_error(); + $errors[] = array( + 'title' => 'INST_ERR_DB_CONNECT', + 'description' => ($db_error['message']) ? utf8_convert_message($db_error['message']) : 'INST_ERR_DB_NO_ERROR', + ); + } + else + { + // Check if there is any table name collisions + $temp_prefix = strtolower($table_prefix); + $table_ary = array( + $temp_prefix . 'attachments', + $temp_prefix . 'config', + $temp_prefix . 'sessions', + $temp_prefix . 'topics', + $temp_prefix . 'users', + ); + + $db_tools_factory = new \phpbb\db\tools\factory(); + $db_tools = $db_tools_factory->get($db); + $tables = $db_tools->sql_list_tables(); + $tables = array_map('strtolower', $tables); + $table_intersect = array_intersect($tables, $table_ary); + + if (sizeof($table_intersect)) + { + $errors[] = array( + 'title' => 'INST_ERR_PREFIX', + ); + } + + // 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', '<')) + { + $errors[] = array( + 'title' => 'INST_ERR_DB_NO_SQLITE3', + ); + } + break; + case 'oracle': + $sql = "SELECT * + FROM NLS_DATABASE_PARAMETERS + WHERE PARAMETER = 'NLS_RDBMS_VERSION' + OR PARAMETER = 'NLS_CHARACTERSET'"; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $stats[$row['parameter']] = $row['value']; + } + $db->sql_freeresult($result); + + if (version_compare($stats['NLS_RDBMS_VERSION'], '9.2', '<') && $stats['NLS_CHARACTERSET'] !== 'UTF8') + { + $errors[] = array( + 'title' => 'INST_ERR_DB_NO_ORACLE', + ); + } + break; + case 'postgres': + $sql = "SHOW server_encoding;"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row['server_encoding'] !== 'UNICODE' && $row['server_encoding'] !== 'UTF8') + { + $errors[] = array( + 'title' => 'INST_ERR_DB_NO_POSTGRES', + ); + } + break; + } + } + + return (empty($errors)) ? true : $errors; + } +} diff --git a/phpBB/phpbb/install/helper/file_updater/compression_file_updater.php b/phpBB/phpbb/install/helper/file_updater/compression_file_updater.php new file mode 100644 index 0000000000..ede992fb6e --- /dev/null +++ b/phpBB/phpbb/install/helper/file_updater/compression_file_updater.php @@ -0,0 +1,133 @@ +<?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\install\helper\file_updater; + +use phpbb\install\helper\update_helper; + +/** + * File updater for generating archive with updated files + */ +class compression_file_updater implements file_updater_interface +{ + /** + * @var \compress + */ + protected $compress; + + /** + * @var update_helper + */ + protected $update_helper; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * Constructor + * + * @param update_helper $update_helper + * @param string $phpbb_root_path + * @param string $php_ext + */ + public function __construct(update_helper $update_helper, $phpbb_root_path, $php_ext) + { + $this->compress = null; + $this->update_helper = $update_helper; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + } + + /** + * Set the compression method + * + * @param string $method Compression method's file extension + * + * @return string Archive's filename + */ + public function init($method) + { + $this->update_helper->include_file('includes/functions_compress.' . $this->php_ext); + + $archive_filename = 'update_archive_' . time() . '_' . uniqid(); + $path = $this->phpbb_root_path . 'store/' . $archive_filename . '' . $method; + + if ($method === '.zip') + { + $this->compress = new \compress_zip('w', $path); + } + else + { + $this->compress = new \compress_tar('w', $path, $method); + } + + return $path; + } + + /** + * Close archive writing process + */ + public function close() + { + $this->compress->close(); + } + + /** + * {@inheritdoc} + */ + public function delete_file($path_to_file) + { + // We do absolutely nothing here, as this function is called when a file should be + // removed from the filesystem, but since this is an archive generator, it clearly + // cannot do that. + } + + /** + * {@inheritdoc} + */ + public function create_new_file($path_to_file_to_create, $source, $create_from_content = false) + { + if ($create_from_content) + { + $this->compress->add_data($source, $path_to_file_to_create); + } + else + { + $this->compress->add_custom_file($source, $path_to_file_to_create); + } + } + + /** + * {@inheritdoc} + */ + public function update_file($path_to_file_to_update, $source, $create_from_content = false) + { + // Both functions are identical here + $this->create_new_file($path_to_file_to_update, $source, $create_from_content); + } + + /** + * {@inheritdoc} + */ + public function get_method_name() + { + return 'compression'; + } +} diff --git a/phpBB/phpbb/install/helper/file_updater/factory.php b/phpBB/phpbb/install/helper/file_updater/factory.php new file mode 100644 index 0000000000..d3a2f22782 --- /dev/null +++ b/phpBB/phpbb/install/helper/file_updater/factory.php @@ -0,0 +1,69 @@ +<?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\install\helper\file_updater; + +use phpbb\di\service_collection; +use phpbb\install\exception\file_updater_failure_exception; + +/** + * File updater factory + */ +class factory +{ + /** + * @var array + */ + protected $file_updaters; + + /** + * Constructor + * + * @param service_collection $collection File updater service collection + */ + public function __construct(service_collection $collection) + { + foreach ($collection as $service) + { + $this->register($service); + } + } + + /** + * Register updater object + * + * @param file_updater_interface $updater Updater object + */ + public function register(file_updater_interface $updater) + { + $name = $updater->get_method_name(); + $this->file_updaters[$name] = $updater; + } + + /** + * Returns file updater object + * + * @param string $name Name of the updater method + * + * @throws file_updater_failure_exception When the specified file updater does not exist + */ + public function get($name) + { + if (!isset($this->file_updaters[$name])) + { + throw new file_updater_failure_exception(); + } + + return $this->file_updaters[$name]; + } +} diff --git a/phpBB/phpbb/install/helper/file_updater/file_updater.php b/phpBB/phpbb/install/helper/file_updater/file_updater.php new file mode 100644 index 0000000000..cc0f5c6b5f --- /dev/null +++ b/phpBB/phpbb/install/helper/file_updater/file_updater.php @@ -0,0 +1,202 @@ +<?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\install\helper\file_updater; + +use phpbb\filesystem\exception\filesystem_exception; +use phpbb\filesystem\filesystem; +use phpbb\install\exception\file_updater_failure_exception; + +/** + * File updater for direct filesystem access + */ +class file_updater implements file_updater_interface +{ + /** + * @var filesystem + */ + protected $filesystem; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param filesystem $filesystem + * @param string $phpbb_root_path + */ + public function __construct(filesystem $filesystem, $phpbb_root_path) + { + $this->filesystem = $filesystem; + $this->phpbb_root_path = $phpbb_root_path; + } + + /** + * {@inheritdoc} + * + * @throws file_updater_failure_exception When the file is not writable + * @throws filesystem_exception When the filesystem class fails + */ + public function delete_file($path_to_file) + { + $this->filesystem->remove($this->phpbb_root_path . $path_to_file); + } + + /** + * {@inheritdoc} + * + * @throws file_updater_failure_exception When the file is not writable + * @throws filesystem_exception When the filesystem class fails + */ + public function create_new_file($path_to_file_to_create, $source, $create_from_content = false) + { + $path_to_file_to_create = $this->phpbb_root_path . $path_to_file_to_create; + + $dir = dirname($path_to_file_to_create); + if (!$this->filesystem->exists($dir)) + { + $this->make_dir($dir); + } + + $original_dir_perms = false; + + if (!$this->filesystem->is_writable($dir)) + { + // Extract last 9 bits we actually need + $original_dir_perms = @fileperms($dir) & 511; + $this->filesystem->phpbb_chmod($dir, filesystem::CHMOD_ALL); + } + + if (!$create_from_content) + { + try + { + $this->filesystem->copy($source, $path_to_file_to_create); + } + catch (filesystem_exception $e) + { + $this->write_file($path_to_file_to_create, $source, $create_from_content); + } + } + else + { + $this->write_file($path_to_file_to_create, $source, $create_from_content); + } + + if ($original_dir_perms !== false) + { + $this->filesystem->phpbb_chmod($dir, $original_dir_perms); + } + } + + /** + * {@inheritdoc} + * + * @throws file_updater_failure_exception When the file is not writable + * @throws filesystem_exception When the filesystem class fails + */ + public function update_file($path_to_file_to_update, $source, $create_from_content = false) + { + $path_to_file_to_update = $this->phpbb_root_path . $path_to_file_to_update; + $original_file_perms = false; + + // Maybe necessary for binary files + $dir = dirname($path_to_file_to_update); + if (!$this->filesystem->exists($dir)) + { + $this->make_dir($dir); + } + + if (!$this->filesystem->is_writable($path_to_file_to_update)) + { + // Extract last 9 bits we actually need + $original_file_perms = @fileperms($path_to_file_to_update) & 511; + $this->filesystem->phpbb_chmod($path_to_file_to_update, filesystem::CHMOD_WRITE); + } + + if (!$create_from_content) + { + try + { + $this->filesystem->copy($source, $path_to_file_to_update, true); + } + catch (filesystem_exception $e) + { + $this->write_file($path_to_file_to_update, $source, $create_from_content); + } + } + else + { + $this->write_file($path_to_file_to_update, $source, $create_from_content); + } + + if ($original_file_perms !== false) + { + $this->filesystem->phpbb_chmod($path_to_file_to_update, $original_file_perms); + } + } + + /** + * Creates directory structure + * + * @param string $path Path to the directory where the file should be placed (and non-existent) + */ + private function make_dir($path) + { + if (is_dir($path)) + { + return; + } + + $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); + $this->filesystem->mkdir($path, 493); // 493 === 0755 + } + + /** + * Fallback function for file writing + * + * @param string $path_to_file Path to the file's location + * @param string $source Path to file to copy or string with the new file's content + * @param bool|false $create_from_content Whether or not to use $source as the content, false by default + * + * @throws file_updater_failure_exception When the file is not writable + */ + private function write_file($path_to_file, $source, $create_from_content = false) + { + if (!$create_from_content) + { + $source = @file_get_contents($source); + } + + $file_pointer = @fopen($path_to_file, 'w'); + + if (!is_resource($file_pointer)) + { + throw new file_updater_failure_exception(); + } + + @fwrite($file_pointer, $source); + @fclose($file_pointer); + } + + /** + * {@inheritdoc} + */ + public function get_method_name() + { + return 'direct_file'; + } +} diff --git a/phpBB/phpbb/install/helper/file_updater/file_updater_interface.php b/phpBB/phpbb/install/helper/file_updater/file_updater_interface.php new file mode 100644 index 0000000000..b13d7c9fe1 --- /dev/null +++ b/phpBB/phpbb/install/helper/file_updater/file_updater_interface.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\install\helper\file_updater; + +interface file_updater_interface +{ + /** + * Deletes a file + * + * @param string $path_to_file Path to the file to delete + */ + public function delete_file($path_to_file); + + /** + * Creates a new file + * + * @param string $path_to_file_to_create Path to the new file's location + * @param string $source Path to file to copy or string with the new file's content + * @param bool $create_from_content Whether or not to use $source as the content, false by default + */ + public function create_new_file($path_to_file_to_create, $source, $create_from_content = false); + + /** + * Update file + * + * @param string $path_to_file_to_update Path to the file's location + * @param string $source Path to file to copy or string with the new file's content + * @param bool $create_from_content Whether or not to use $source as the content, false by default + */ + public function update_file($path_to_file_to_update, $source, $create_from_content = false); + + /** + * Returns the name of the file updater method + * + * @return string + */ + public function get_method_name(); +} diff --git a/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php b/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php new file mode 100644 index 0000000000..5cdc331cbc --- /dev/null +++ b/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php @@ -0,0 +1,136 @@ +<?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\install\helper\file_updater; + +use phpbb\install\helper\update_helper; + +/** + * File updater for FTP updates + */ +class ftp_file_updater implements file_updater_interface +{ + /** + * @var \transfer + */ + protected $transfer; + + /** + * @var update_helper + */ + protected $update_helper; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * Constructor + * + * @param update_helper $update_helper + * @param string $phpbb_root_path + * @param string $php_ext + */ + public function __construct(update_helper $update_helper, $phpbb_root_path, $php_ext) + { + $this->transfer = null; + $this->update_helper = $update_helper; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + } + + /** + * Initialize FTP connection + * + * @param string $method + * @param string $host + * @param string $user + * @param string $pass + * @param string $path + * @param int $port + * @param int $timeout + */ + public function init($method, $host, $user, $pass, $path, $port, $timeout) + { + $this->update_helper->include_file('includes/functions_transfer.' . $this->php_ext); + $this->transfer = new $method($host, $user, $pass, $path, $port, $timeout); + $this->transfer->open_session(); + } + + /** + * Close FTP session + */ + public function close() + { + $this->transfer->close_session(); + } + + /** + * {@inheritdoc} + */ + public function delete_file($path_to_file) + { + $this->transfer->delete_file($path_to_file); + } + + /** + * {@inheritdoc} + */ + public function create_new_file($path_to_file_to_create, $source, $create_from_content = false) + { + $dirname = dirname($path_to_file_to_create); + + if ($dirname && !file_exists($this->phpbb_root_path . $dirname)) + { + $this->transfer->make_dir($dirname); + } + + if ($create_from_content) + { + $this->transfer->write_file($path_to_file_to_create, $source); + } + else + { + $this->transfer->copy_file($path_to_file_to_create, $source); + } + } + + /** + * {@inheritdoc} + */ + public function update_file($path_to_file_to_update, $source, $create_from_content = false) + { + if ($create_from_content) + { + $this->transfer->write_file($path_to_file_to_update, $source); + } + else + { + $this->transfer->copy_file($path_to_file_to_update, $source); + } + } + + /** + * {@inheritdoc} + */ + public function get_method_name() + { + return 'ftp'; + } +} diff --git a/phpBB/phpbb/install/helper/install_helper.php b/phpBB/phpbb/install/helper/install_helper.php new file mode 100644 index 0000000000..ffe36cd645 --- /dev/null +++ b/phpBB/phpbb/install/helper/install_helper.php @@ -0,0 +1,60 @@ +<?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\install\helper; + +/** + * General helper functionality for the installer + */ +class install_helper +{ + /** + * @var string + */ + protected $php_ext; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param string $phpbb_root_path path to phpBB's root + * @param string $php_ext Extension of PHP files + */ + public function __construct($phpbb_root_path, $php_ext) + { + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + } + + /** + * Check whether phpBB is installed. + * + * @return bool + */ + public function is_phpbb_installed() + { + $config_path = $this->phpbb_root_path . 'config.' . $this->php_ext; + $install_lock_path = $this->phpbb_root_path . 'cache/install_lock'; + + if (file_exists($config_path) && !file_exists($install_lock_path) && filesize($config_path)) + { + return true; + } + + return false; + } +} diff --git a/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php b/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php new file mode 100644 index 0000000000..a40d457466 --- /dev/null +++ b/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php @@ -0,0 +1,497 @@ +<?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\install\helper\iohandler; + +use phpbb\path_helper; +use phpbb\routing\router; + +/** + * Input-Output handler for the AJAX frontend + */ +class ajax_iohandler extends iohandler_base +{ + /** + * @var path_helper + */ + protected $path_helper; + + /** + * @var \phpbb\request\request_interface + */ + protected $request; + + /** + * @var \phpbb\template\template + */ + protected $template; + + /** + * @var router + */ + protected $router; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $file_status; + + /** + * @var string + */ + protected $form; + + /** + * @var bool + */ + protected $request_client_refresh; + + /** + * @var array + */ + protected $nav_data; + + /** + * @var array + */ + protected $cookies; + + /** + * @var array + */ + protected $download; + + /** + * @var array + */ + protected $redirect_url; + + /** + * @var resource + */ + protected $file_lock_pointer; + + /** + * Constructor + * + * @param path_helper $path_helper + * @param \phpbb\request\request_interface $request HTTP request interface + * @param \phpbb\template\template $template Template engine + * @param router $router Router + * @param string $root_path Path to phpBB's root + */ + public function __construct(path_helper $path_helper, \phpbb\request\request_interface $request, \phpbb\template\template $template, router $router, $root_path) + { + $this->path_helper = $path_helper; + $this->request = $request; + $this->router = $router; + $this->template = $template; + $this->form = ''; + $this->nav_data = array(); + $this->cookies = array(); + $this->download = array(); + $this->redirect_url = array(); + $this->file_status = ''; + $this->phpbb_root_path = $root_path; + + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + public function get_input($name, $default, $multibyte = false) + { + return $this->request->variable($name, $default, $multibyte); + } + + /** + * {@inheritdoc} + */ + public function get_raw_input($name, $default) + { + return $this->request->raw_variable($name, $default); + } + + /** + * {@inheritdoc} + */ + public function get_server_variable($name, $default = '') + { + return $this->request->server($name, $default); + } + + /** + * {@inheritdoc} + */ + public function get_header_variable($name, $default = '') + { + return $this->request->header($name, $default); + } + + /** + * {@inheritdoc} + */ + public function is_secure() + { + return $this->request->is_secure(); + } + + /** + * {@inheritdoc} + */ + public function add_user_form_group($title, $form) + { + $this->form = $this->generate_form_render_data($title, $form); + } + + /** + * {@inheritdoc} + */ + public function generate_form_render_data($title, $form) + { + $this->template->assign_block_vars('options', array( + 'LEGEND' => $this->language->lang($title), + 'S_LEGEND' => true, + )); + + $not_button_form = false; + + foreach ($form as $input_name => $input_options) + { + if (!isset($input_options['type'])) + { + continue; + } + + $tpl_ary = array(); + $not_button_form = ($input_options['type'] !== 'submit' || $not_button_form); + + $tpl_ary['TYPE'] = $input_options['type']; + $tpl_ary['TITLE'] = $this->language->lang($input_options['label']); + $tpl_ary['KEY'] = $input_name; + $tpl_ary['S_EXPLAIN'] = false; + + if (isset($input_options['default'])) + { + $default = $input_options['default']; + $default = preg_replace_callback('#\{L_([A-Z0-9\-_]*)\}#s', array($this, 'lang_replace_callback'), $default); + $tpl_ary['DEFAULT'] = $default; + } + + if (isset($input_options['description'])) + { + $tpl_ary['TITLE_EXPLAIN'] = $this->language->lang($input_options['description']); + $tpl_ary['S_EXPLAIN'] = true; + } + + if (in_array($input_options['type'], array('select', 'radio'), true)) + { + for ($i = 0, $total = sizeof($input_options['options']); $i < $total; $i++) + { + if (isset($input_options['options'][$i]['label'])) + { + $input_options['options'][$i]['label'] = $this->language->lang($input_options['options'][$i]['label']); + } + } + + $tpl_ary['OPTIONS'] = $input_options['options']; + } + + $block_name = ($input_options['type'] === 'submit') ? 'submit_buttons' : 'options'; + $this->template->assign_block_vars($block_name, $tpl_ary); + } + + $this->template->assign_var('S_NOT_ONLY_BUTTON_FORM', $not_button_form); + + $this->template->set_filenames(array( + 'form_install' => 'installer_form.html', + )); + + return $this->template->assign_display('form_install'); + } + + /** + * {@inheritdoc} + */ + public function send_response($no_more_output = false) + { + $json_data_array = $this->prepare_json_array($no_more_output); + + if (empty($json_data_array)) + { + return; + } + + $json_data = json_encode($json_data_array); + + // Try to push content to the browser + print(str_pad(' ', 4096) . "\n"); + print($json_data . "\n\n"); + flush(); + } + + /** + * Prepares iohandler's data to be sent out to the client. + * + * @param bool $no_more_output Whether or not there will be more output in this response + * + * @return array + */ + protected function prepare_json_array($no_more_output = false) + { + $json_array = array(); + + if (!empty($this->errors)) + { + $json_array['errors'] = $this->errors; + $this->errors = array(); + } + + if (!empty($this->warnings)) + { + $json_array['warnings'] = $this->warnings; + $this->warnings = array(); + } + + if (!empty($this->logs)) + { + $json_array['logs'] = $this->logs; + $this->logs = array(); + } + + if (!empty($this->success)) + { + $json_array['success'] = $this->success; + $this->success = array(); + } + + if (!empty($this->download)) + { + $json_array['download'] = $this->download; + $this->download = array(); + } + + if (!empty($this->form)) + { + $json_array['form'] = $this->form; + $this->form = ''; + } + + if (!empty($this->file_status)) + { + $json_array['file_status'] = $this->file_status; + $this->file_status = ''; + } + + // If current task name is set, we push progress message to the client side + if (!empty($this->current_task_name)) + { + $json_array['progress'] = array( + 'task_name' => $this->current_task_name, + 'task_num' => $this->current_task_progress, + 'task_count' => $this->task_progress_count, + ); + + if ($this->restart_progress_bar) + { + $json_array['progress']['restart'] = 1; + $this->restart_progress_bar = false; + } + } + + if (!empty($this->nav_data)) + { + $json_array['nav'] = $this->nav_data; + $this->nav_data = array(); + } + + if ($this->request_client_refresh) + { + $json_array['refresh'] = true; + $this->request_client_refresh = false; + } + + if (!empty($this->cookies)) + { + $json_array['cookies'] = $this->cookies; + $this->cookies = array(); + } + + if (!empty($this->redirect_url)) + { + $json_array['redirect'] = $this->redirect_url; + $this->redirect_url = array(); + } + + if ($no_more_output) + { + $json_array['over'] = true; + } + + return $json_array; + } + + /** + * {@inheritdoc} + */ + public function set_progress($task_lang_key, $task_number) + { + parent::set_progress($task_lang_key, $task_number); + $this->send_response(); + } + + /** + * {@inheritdoc} + */ + public function request_refresh() + { + $this->request_client_refresh = true; + } + + /** + * {@inheritdoc} + */ + public function set_active_stage_menu($menu_path) + { + $this->nav_data['active'] = $menu_path[sizeof($menu_path) - 1]; + $this->send_response(); + } + + /** + * {@inheritdoc} + */ + public function set_finished_stage_menu($menu_path) + { + $this->nav_data['finished'][] = $menu_path[sizeof($menu_path) - 1]; + $this->send_response(); + } + + /** + * {@inheritdoc} + */ + public function set_cookie($cookie_name, $cookie_value) + { + $this->cookies[] = array( + 'name' => $cookie_name, + 'value' => $cookie_value + ); + } + + /** + * {@inheritdoc} + */ + public function add_download_link($route, $title, $msg = null) + { + $link_properties = array( + 'href' => $this->router->generate($route), + 'title' => $this->language->lang($title), + 'download' => $this->language->lang('DOWNLOAD'), + ); + + if ($msg !== null) + { + $link_properties['msg'] = htmlspecialchars_decode($this->language->lang($msg)); + } + + $this->download[] = $link_properties; + } + + /** + * {@inheritdoc} + */ + public function render_update_file_status($status_array) + { + $this->template->assign_vars(array( + 'T_IMAGE_PATH' => $this->path_helper->get_web_root_path() . 'adm/images/', + )); + + foreach ($status_array as $block => $list) + { + foreach ($list as $filename) + { + $dirname = dirname($filename); + + $this->template->assign_block_vars($block, array( + 'STATUS' => $block, + 'FILENAME' => $filename, + 'DIR_PART' => (!empty($dirname) && $dirname !== '.') ? dirname($filename) . '/' : false, + 'FILE_PART' => basename($filename), + )); + } + } + + $this->template->set_filenames(array( + 'file_status' => 'installer_update_file_status.html', + )); + + $this->file_status = $this->template->assign_display('file_status'); + } + + /** + * {@inheritdoc} + */ + public function redirect($url, $use_ajax = false) + { + $this->redirect_url = array('url' => $url, 'use_ajax' => $use_ajax); + $this->send_response(true); + } + + /** + * Acquires a file lock + */ + public function acquire_lock() + { + $lock_file = $this->phpbb_root_path . 'store/io_lock.lock'; + $this->file_lock_pointer = @fopen($lock_file, 'w+'); + + if ($this->file_lock_pointer) + { + flock($this->file_lock_pointer, LOCK_EX); + } + } + + /** + * Release file lock + */ + public function release_lock() + { + if ($this->file_lock_pointer) + { + fwrite($this->file_lock_pointer, 'ok'); + flock($this->file_lock_pointer, LOCK_UN); + fclose($this->file_lock_pointer); + } + } + + /** + * Callback function for language replacing + * + * @param array $matches + * @return string + */ + public function lang_replace_callback($matches) + { + if (!empty($matches[1])) + { + return $this->language->lang($matches[1]); + } + + return ''; + } +} diff --git a/phpBB/phpbb/install/helper/iohandler/cli_iohandler.php b/phpBB/phpbb/install/helper/iohandler/cli_iohandler.php new file mode 100644 index 0000000000..4117a3dfd3 --- /dev/null +++ b/phpBB/phpbb/install/helper/iohandler/cli_iohandler.php @@ -0,0 +1,323 @@ +<?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\install\helper\iohandler; + +use phpbb\install\exception\installer_exception; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\OutputStyle; + +/** + * Input-Output handler for the CLI frontend + */ +class cli_iohandler extends iohandler_base +{ + /** + * @var OutputInterface + */ + protected $output; + + /** + * @var OutputStyle + */ + protected $io; + + /** + * @var array + */ + protected $input_values = array(); + + /** + * @var \Symfony\Component\Console\Helper\ProgressBar + */ + protected $progress_bar; + + /** + * Set the style and output used to display feedback; + * + * @param OutputStyle $style + * @param OutputInterface $output + */ + public function set_style(OutputStyle $style, OutputInterface $output) + { + $this->io = $style; + $this->output = $output; + } + + /** + * {@inheritdoc} + */ + public function get_input($name, $default, $multibyte = false) + { + $result = $default; + + if (isset($this->input_values[$name])) + { + $result = $this->input_values[$name]; + } + + if ($multibyte) + { + return utf8_normalize_nfc($result); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function get_raw_input($name, $default) + { + return $this->get_input($name, $default, true); + } + + /** + * Set input variable + * + * @param string $name Name of input variable + * @param mixed $value Value of input variable + */ + public function set_input($name, $value) + { + $this->input_values[$name] = $value; + } + + /** + * {@inheritdoc} + */ + public function get_server_variable($name, $default = '') + { + return $default; + } + + /** + * {@inheritdoc} + */ + public function get_header_variable($name, $default = '') + { + return $default; + } + + /** + * {@inheritdoc} + */ + public function is_secure() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function add_user_form_group($title, $form) + { + throw new installer_exception('MISSING_DATA'); + } + + /** + * {@inheritdoc} + */ + public function send_response($no_more_output = false) + { + } + + /** + * {@inheritdoc + */ + public function add_error_message($error_title, $error_description = false) + { + $this->io->newLine(); + $message = $this->translate_message($error_title, $error_description); + $message_string = $message['title'] . (!empty($message['description']) ? "\n" . $message['description'] : ''); + + if (strpos($message_string, '<br />') !== false) + { + $message_string = strip_tags(str_replace('<br />', "\n", $message_string)); + } + + $this->io->error($message_string); + + if ($this->progress_bar !== null) + { + $this->io->newLine(2); + $this->progress_bar->display(); + } + } + + /** + * {@inheritdoc + */ + public function add_warning_message($warning_title, $warning_description = false) + { + $this->io->newLine(); + + $message = $this->translate_message($warning_title, $warning_description); + $message_string = $message['title'] . (!empty($message['description']) ? "\n" . $message['description'] : ''); + $this->io->warning($message_string); + + if ($this->progress_bar !== null) + { + $this->io->newLine(2); + $this->progress_bar->display(); + } + } + + /** + * {@inheritdoc + */ + public function add_log_message($log_title, $log_description = false) + { + if ($this->output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL) + { + $message = $this->translate_message($log_title, $log_description); + $this->output->writeln(sprintf('[%3d/%-3d] ---- %s', $this->current_task_progress, $this->task_progress_count, $message['title'])); + } + } + + /** + * {@inheritdoc + */ + public function add_success_message($error_title, $error_description = false) + { + $this->io->newLine(); + + $message = $this->translate_message($error_title, $error_description); + $message_string = $message['title'] . (!empty($message['description']) ? "\n" . $message['description'] : ''); + $this->io->success($message_string); + + if ($this->progress_bar !== null) + { + $this->io->newLine(2); + $this->progress_bar->display(); + } + } + + /** + * {@inheritdoc} + */ + public function set_task_count($task_count, $restart = false) + { + parent::set_task_count($task_count, $restart); + + if ($this->output->getVerbosity() === OutputInterface::VERBOSITY_NORMAL) + { + if ($this->progress_bar !== null) + { + // Symfony's ProgressBar is immutable regarding task_count, so delete the old and create a new one. + $this->progress_bar->clear(); + } + else + { + $this->io->newLine(2); + } + + $this->progress_bar = $this->io->createProgressBar($task_count); + $this->progress_bar->setFormat( + " %current:3s%/%max:-3s% %bar% %percent:3s%%\n" . + " %message%\n"); + $this->progress_bar->setBarWidth(60); + + if (!defined('PHP_WINDOWS_VERSION_BUILD')) + { + $this->progress_bar->setEmptyBarCharacter('â–‘'); // light shade character \u2591 + $this->progress_bar->setProgressCharacter(''); + $this->progress_bar->setBarCharacter('â–“'); // dark shade character \u2593 + } + + $this->progress_bar->setMessage(''); + $this->progress_bar->start(); + } + } + + /** + * {@inheritdoc} + */ + public function set_progress($task_lang_key, $task_number) + { + parent::set_progress($task_lang_key, $task_number); + + if ($this->progress_bar !== null) + { + $this->progress_bar->setProgress($this->current_task_progress); + $this->progress_bar->setMessage($this->current_task_name); + } + else + { + $this->output->writeln(sprintf('[%3d/%-3d] %s', $this->current_task_progress, $this->task_progress_count, $this->current_task_name)); + } + } + + /** + * {@inheritdoc} + */ + public function finish_progress($message_lang_key) + { + parent::finish_progress($message_lang_key); + + if ($this->progress_bar !== null) + { + $this->progress_bar->finish(); + $this->progress_bar = null; + } + } + + /** + * {@inheritdoc} + */ + public function request_refresh() + { + } + + /** + * {@inheritdoc} + */ + public function set_active_stage_menu($menu_path) + { + } + + /** + * {@inheritdoc} + */ + public function set_finished_stage_menu($menu_path) + { + } + + /** + * {@inheritdoc} + */ + public function set_cookie($cookie_name, $cookie_value) + { + } + + /** + * {@inheritdoc} + */ + public function add_download_link($route, $title, $msg = null) + { + } + + /** + * {@inheritdoc} + */ + public function render_update_file_status($status_array) + { + } + + /** + * {@inheritdoc} + */ + public function redirect($url, $use_ajax = false) + { + } +} diff --git a/phpBB/phpbb/install/helper/iohandler/exception/iohandler_not_implemented_exception.php b/phpBB/phpbb/install/helper/iohandler/exception/iohandler_not_implemented_exception.php new file mode 100644 index 0000000000..f2ddeda6f7 --- /dev/null +++ b/phpBB/phpbb/install/helper/iohandler/exception/iohandler_not_implemented_exception.php @@ -0,0 +1,19 @@ +<?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\install\helper\iohandler\exception; + +class iohandler_not_implemented_exception extends \Exception +{ + +} diff --git a/phpBB/phpbb/install/helper/iohandler/factory.php b/phpBB/phpbb/install/helper/iohandler/factory.php new file mode 100644 index 0000000000..1e8395760a --- /dev/null +++ b/phpBB/phpbb/install/helper/iohandler/factory.php @@ -0,0 +1,79 @@ +<?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\install\helper\iohandler; + +use phpbb\install\helper\iohandler\exception\iohandler_not_implemented_exception; + +/** + * Input-output handler factory + */ +class factory +{ + /** + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + protected $container; + + /** + * @var string + */ + protected $environment; + + /** + * Constructor + * + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container Dependency injection container + */ + public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container) + { + $this->container = $container; + $this->environment = null; + } + + /** + * @param string $environment The name of the input-output handler to use + */ + public function set_environment($environment) + { + $this->environment = $environment; + } + + /** + * Factory getter for iohandler + * + * @return \phpbb\install\helper\iohandler\iohandler_interface + * + * @throws \phpbb\install\helper\iohandler\exception\iohandler_not_implemented_exception + * When the specified iohandler_interface does not exists + */ + public function get() + { + switch ($this->environment) + { + case 'ajax': + return $this->container->get('installer.helper.iohandler_ajax'); + break; + case 'nojs': + // @todo replace this + return $this->container->get('installer.helper.iohandler_ajax'); + break; + case 'cli': + return $this->container->get('installer.helper.iohandler_cli'); + break; + default: + throw new iohandler_not_implemented_exception(); + break; + } + } +} diff --git a/phpBB/phpbb/install/helper/iohandler/iohandler_base.php b/phpBB/phpbb/install/helper/iohandler/iohandler_base.php new file mode 100644 index 0000000000..1797a6c9ad --- /dev/null +++ b/phpBB/phpbb/install/helper/iohandler/iohandler_base.php @@ -0,0 +1,209 @@ +<?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\install\helper\iohandler; + +/** + * Base class for installer input-output handlers + */ +abstract class iohandler_base implements iohandler_interface +{ + /** + * Array of errors + * + * Errors should be added, when the installation cannot continue without + * user interaction. If the aim is to notify the user about something, please + * use a warning instead. + * + * @var array + */ + protected $errors; + + /** + * Array of warnings + * + * @var array + */ + protected $warnings; + + /** + * Array of logs + * + * @var array + */ + protected $logs; + + /** + * Array of success messages + * + * @var array + */ + protected $success; + + /** + * @var \phpbb\language\language + */ + protected $language; + + /** + * @var int + */ + protected $task_progress_count; + + /** + * @var int + */ + protected $current_task_progress; + + /** + * @var string + */ + protected $current_task_name; + + /** + * @var bool + */ + protected $restart_progress_bar; + + /** + * Constructor + */ + public function __construct() + { + $this->errors = array(); + $this->warnings = array(); + $this->logs = array(); + $this->success = array(); + + $this->restart_progress_bar = false; + $this->task_progress_count = 0; + $this->current_task_progress = 0; + $this->current_task_name = ''; + } + + /** + * Set language service + * + * @param \phpbb\language\language $language + */ + public function set_language(\phpbb\language\language $language) + { + $this->language = $language; + } + + /** + * {@inheritdoc} + */ + public function add_error_message($error_title, $error_description = false) + { + if (!is_array($error_title) && strpos($error_title, '<br />') !== false) + { + $error_title = strip_tags(htmlspecialchars_decode($error_title)); + } + $this->errors[] = $this->translate_message($error_title, $error_description); + } + + /** + * {@inheritdoc} + */ + public function add_warning_message($warning_title, $warning_description = false) + { + $this->warnings[] = $this->translate_message($warning_title, $warning_description); + } + + /** + * {@inheritdoc} + */ + public function add_log_message($log_title, $log_description = false) + { + $this->logs[] = $this->translate_message($log_title, $log_description); + } + + /** + * {@inheritdoc} + */ + public function add_success_message($success_title, $success_description = false) + { + $this->success[] = $this->translate_message($success_title, $success_description); + } + + /** + * {@inheritdoc} + */ + public function set_task_count($task_count, $restart = false) + { + $this->task_progress_count = $task_count; + $this->restart_progress_bar = $restart; + } + + /** + * {@inheritdoc} + */ + public function set_progress($task_lang_key, $task_number) + { + $this->current_task_name = ''; + + if (!empty($task_lang_key)) + { + $this->current_task_name = $this->language->lang($task_lang_key); + } + + $this->current_task_progress = $task_number; + } + + /** + * {@inheritdoc} + */ + public function finish_progress($message_lang_key) + { + if (!empty($message_lang_key)) + { + $this->current_task_name = $this->language->lang($message_lang_key); + } + + $this->current_task_progress = $this->task_progress_count; + } + + /** + * {@inheritdoc} + */ + public function generate_form_render_data($title, $form) + { + return ''; + } + + /** + * Localize message. + * + * Note: When an array is passed into the parameters below, it will be + * resolved as printf($param[0], $param[1], ...). + * + * @param array|string $title Title of the message + * @param array|string|bool $description Description of the message + * + * @return array Localized message in an array + */ + protected function translate_message($title, $description) + { + $message_array = array(); + + $message_array['title'] = call_user_func_array(array($this->language, 'lang'), (array) $title); + + if ($description !== false) + { + $message_array['description'] = call_user_func_array(array($this->language, 'lang'), (array) $description); + } + + return $message_array; + } +} diff --git a/phpBB/phpbb/install/helper/iohandler/iohandler_interface.php b/phpBB/phpbb/install/helper/iohandler/iohandler_interface.php new file mode 100644 index 0000000000..440748901c --- /dev/null +++ b/phpBB/phpbb/install/helper/iohandler/iohandler_interface.php @@ -0,0 +1,222 @@ +<?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\install\helper\iohandler; + +/** + * Input-Output handler interface for the installer + */ +interface iohandler_interface +{ + /** + * Renders or returns response message + * + * @param bool $no_more_output Whether or not there will be more output in this output unit + */ + public function send_response($no_more_output = false); + + /** + * Returns input variable + * + * @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 + * 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 + */ + public function get_input($name, $default, $multibyte = false); + + /** + * Returns raw input variable + * + * @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. + * + * @return mixed Value of the raw input variable + */ + public function get_raw_input($name, $default); + + /** + * Returns server variable + * + * This function should work the same as request_interface::server(). + * + * @param string $name Name of the server variable + * @param mixed $default Default value to return when the requested variable does not exist + * + * @return mixed Value of the server variable + */ + public function get_server_variable($name, $default = ''); + + /** + * Wrapper function for request_interface::header() + * + * @param string $name Name of the request header variable + * @param mixed $default Default value to return when the requested variable does not exist + * + * @return mixed + */ + public function get_header_variable($name, $default = ''); + + /** + * Returns true if the connection is encrypted + * + * @return bool + */ + public function is_secure(); + + /** + * Adds an error message to the rendering queue + * + * Note: When an array is passed into the parameters below, it will be + * resolved as printf($param[0], $param[1], ...). + * + * @param string|array $error_title Title of the error message. + * @param string|bool|array $error_description Description of the error (and possibly guidelines to resolve it), + * or false if the error description is not available. + */ + public function add_error_message($error_title, $error_description = false); + + /** + * Adds a warning message to the rendering queue + * + * Note: When an array is passed into the parameters below, it will be + * resolved as printf($param[0], $param[1], ...). + * + * @param string|array $warning_title Title of the warning message + * @param string|bool|array $warning_description Description of the warning (and possibly guidelines to resolve it), + * or false if the warning description is not available + */ + public function add_warning_message($warning_title, $warning_description = false); + + /** + * Adds a log message to the rendering queue + * + * Note: When an array is passed into the parameters below, it will be + * resolved as printf($param[0], $param[1], ...). + * + * @param string|array $log_title Title of the log message + * @param string|bool|array $log_description Description of the log, + * or false if the log description is not available + */ + public function add_log_message($log_title, $log_description = false); + + /** + * Adds a success message to the rendering queue + * + * Note: When an array is passed into the parameters below, it will be + * resolved as printf($param[0], $param[1], ...). + * + * @param string|array $success_title Title of the success message + * @param string|bool|array $success_description Description of the success, + * or false if the success description is not available + * + * @return null + */ + public function add_success_message($success_title, $success_description = false); + + /** + * Adds a requested data group to the rendering queue + * + * @param string $title Language variable with the title of the form + * @param array $form An array describing the required data (options etc) + */ + public function add_user_form_group($title, $form); + + /** + * Returns the rendering information for the form + * + * @param string $title Language variable with the title of the form + * @param array $form An array describing the required data (options etc) + * + * @return string Information to render the form + */ + public function generate_form_render_data($title, $form); + + /** + * Sets the number of tasks belonging to the installer in the current mode. + * + * @param int $task_count Number of tasks + * @param bool $restart Whether or not to restart the progress bar, false by default + */ + public function set_task_count($task_count, $restart = false); + + /** + * Sets the progress information + * + * @param string $task_lang_key Language key for the name of the task + * @param int $task_number Position of the current task in the task queue + */ + public function set_progress($task_lang_key, $task_number); + + /** + * Sends refresh request to the client + */ + public function request_refresh(); + + /** + * Marks stage as active in the navigation bar + * + * @param array $menu_path Array to the navigation elem + */ + public function set_active_stage_menu($menu_path); + + /** + * Marks stage as completed in the navigation bar + * + * @param array $menu_path Array to the navigation elem + */ + public function set_finished_stage_menu($menu_path); + + /** + * Finish the progress bar + * + * @param string $message_lang_key Language key for the message + */ + public function finish_progress($message_lang_key); + + /** + * Adds a download link + * + * @param string $route Route for the link + * @param string $title Language key for the title + * @param string|null|array $msg Language key for the message + */ + public function add_download_link($route, $title, $msg = null); + + /** + * Redirects the user to a new page + * + * @param string $url URL to redirect to + * @param bool $use_ajax Whether or not to use AJAX redirect + */ + public function redirect($url, $use_ajax = false); + + /** + * Renders the status of update files + * + * @param array $status_array Array containing files in groups to render + */ + public function render_update_file_status($status_array); + + /** + * Sends and sets cookies + * + * @param string $cookie_name Name of the cookie to set + * @param string $cookie_value Value of the cookie to set + */ + public function set_cookie($cookie_name, $cookie_value); +} diff --git a/phpBB/phpbb/install/helper/navigation/convertor_navigation.php b/phpBB/phpbb/install/helper/navigation/convertor_navigation.php new file mode 100644 index 0000000000..54cab83b1d --- /dev/null +++ b/phpBB/phpbb/install/helper/navigation/convertor_navigation.php @@ -0,0 +1,78 @@ +<?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\install\helper\navigation; + +use phpbb\install\helper\install_helper; + +class convertor_navigation implements navigation_interface +{ + /** + * @var install_helper + */ + private $install_helper; + + /** + * Constructor + * + * @param install_helper $install_helper + */ + public function __construct(install_helper $install_helper) + { + $this->install_helper = $install_helper; + } + + /** + * {@inheritdoc} + */ + public function get() + { + if (!$this->install_helper->is_phpbb_installed()) + { + return array(); + } + + return array( + 'convert' => array( + 'label' => 'CONVERT', + 'route' => 'phpbb_convert_intro', + 'order' => 3, + array( + 'intro' => array( + 'label' => 'SUB_INTRO', + 'stage' => true, + 'order' => 0, + ), + 'settings' => array( + 'label' => 'STAGE_SETTINGS', + 'stage' => true, + 'route' => 'phpbb_convert_settings', + 'order' => 1, + ), + 'convert' => array( + 'label' => 'STAGE_IN_PROGRESS', + 'stage' => true, + 'route' => 'phpbb_convert_convert', + 'order' => 2, + ), + 'finish' => array( + 'label' => 'CONVERT_COMPLETE', + 'stage' => true, + 'route' => 'phpbb_convert_finish', + 'order' => 3, + ), + ), + ), + ); + } +} diff --git a/phpBB/phpbb/install/helper/navigation/install_navigation.php b/phpBB/phpbb/install/helper/navigation/install_navigation.php new file mode 100644 index 0000000000..f690f8de76 --- /dev/null +++ b/phpBB/phpbb/install/helper/navigation/install_navigation.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\install\helper\navigation; + +use phpbb\install\helper\install_helper; + +class install_navigation implements navigation_interface +{ + /** + * @var install_helper + */ + private $install_helper; + + /** + * Constructor + * + * @param install_helper $install_helper + */ + public function __construct(install_helper $install_helper) + { + $this->install_helper = $install_helper; + } + + /** + * {@inheritdoc} + */ + public function get() + { + if ($this->install_helper->is_phpbb_installed()) + { + return array(); + } + + return array( + 'install' => array( + 'label' => 'INSTALL', + 'route' => 'phpbb_installer_install', + 'order' => 1, + array( + 'introduction' => array( + 'label' => 'INTRODUCTION_TITLE', + 'stage' => true, + 'order' => 0, + ), + 'requirements' => array( + 'label' => 'STAGE_REQUIREMENTS', + 'stage' => true, + 'order' => 1, + ), + 'obtain_data' => array( + 'label' => 'STAGE_OBTAIN_DATA', + 'stage' => true, + 'order' => 2, + ), + 'install' => array( + 'label' => 'STAGE_INSTALL', + 'stage' => true, + 'order' => 3, + ), + ), + ), + ); + } +} diff --git a/phpBB/phpbb/install/helper/navigation/main_navigation.php b/phpBB/phpbb/install/helper/navigation/main_navigation.php new file mode 100644 index 0000000000..214bb04963 --- /dev/null +++ b/phpBB/phpbb/install/helper/navigation/main_navigation.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\install\helper\navigation; + +class main_navigation implements navigation_interface +{ + /** + * {@inheritdoc} + */ + public function get() + { + return array( + 'overview' => array( + 'label' => 'MENU_OVERVIEW', + 'route' => 'phpbb_installer_index', + 'order' => 0, + array( + 'introduction' => array( + 'label' => 'MENU_INTRO', + 'route' => 'phpbb_installer_index', + 'order' => 0, + ), + 'support' => array( + 'label' => 'MENU_SUPPORT', + 'route' => 'phpbb_installer_support', + 'order' => 1, + ), + 'license' => array( + 'label' => 'MENU_LICENSE', + 'route' => 'phpbb_installer_license', + 'order' => 2, + ), + ), + ), + ); + } +} diff --git a/phpBB/phpbb/install/helper/navigation/navigation_interface.php b/phpBB/phpbb/install/helper/navigation/navigation_interface.php new file mode 100644 index 0000000000..eebdbe923f --- /dev/null +++ b/phpBB/phpbb/install/helper/navigation/navigation_interface.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\install\helper\navigation; + +/** + * Interface for installer's navigation defining services + */ +interface navigation_interface +{ + /** + * Returns an array with the navigation items + * + * The returned array should have the following format: + * <code> + * array( + * 'parent_nav_name' => array( + * 'nav_name' => array( + * 'label' => 'MY_MENU', + * 'route' => 'phpbb_route_name', + * ) + * ) + * ) + * </code> + * + * Navigation item setting options: + * - label: The language variable name + * - route: Name of the route which it is belongs to + * + * @return array + */ + public function get(); +} diff --git a/phpBB/phpbb/install/helper/navigation/navigation_provider.php b/phpBB/phpbb/install/helper/navigation/navigation_provider.php new file mode 100644 index 0000000000..d52aec8999 --- /dev/null +++ b/phpBB/phpbb/install/helper/navigation/navigation_provider.php @@ -0,0 +1,121 @@ +<?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\install\helper\navigation; + +use phpbb\di\service_collection; + +/** + * Installers navigation provider + */ +class navigation_provider +{ + /** + * @var array + */ + private $menu_collection; + + /** + * Constructor + * + * @param service_collection $plugins + */ + public function __construct(service_collection $plugins) + { + $this->menu_collection = array(); + + foreach ($plugins as $plugin => $plugin_instance) + { + $this->register($plugin_instance); + } + } + + /** + * Returns navigation array + * + * @return array + */ + public function get() + { + return $this->menu_collection; + } + + /** + * Registers a navigation provider's navigation items + * + * @param navigation_interface $navigation + */ + public function register(navigation_interface $navigation) + { + $nav_arry = $navigation->get(); + $this->menu_collection = $this->merge($nav_arry, $this->menu_collection); + } + + /** + * Set a property in the navigation array + * + * @param array $nav_element Array to the navigation elem + * @param array $property_array Array with the properties to set + */ + public function set_nav_property($nav_element, $property_array) + { + $array_pointer = array(); + $array_root_pointer = &$array_pointer; + foreach ($nav_element as $array_path) + { + $array_pointer[$array_path] = array(); + $array_pointer = &$array_pointer[$array_path]; + } + + $array_pointer = $property_array; + + $this->menu_collection = $this->merge($array_root_pointer, $this->menu_collection); + } + + /** + * Recursive array merge + * + * This function is necessary to be able to replace the options of + * already set navigation items. + * + * @param array $array_to_merge + * @param array $array_to_merge_into + * + * @return array Merged array + */ + private function merge($array_to_merge, $array_to_merge_into) + { + $merged_array = $array_to_merge_into; + + foreach ($array_to_merge as $key => $value) + { + if (isset($array_to_merge_into[$key])) + { + if (is_array($array_to_merge_into[$key]) && is_array($value)) + { + $merged_array[$key] = $this->merge($value, $array_to_merge_into[$key]); + } + else + { + $merged_array[$key] = $value; + } + } + else + { + $merged_array[$key] = $value; + } + } + + return $merged_array; + } +} diff --git a/phpBB/phpbb/install/helper/navigation/update_navigation.php b/phpBB/phpbb/install/helper/navigation/update_navigation.php new file mode 100644 index 0000000000..3d239c3451 --- /dev/null +++ b/phpBB/phpbb/install/helper/navigation/update_navigation.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\install\helper\navigation; + +use phpbb\install\helper\install_helper; + +class update_navigation implements navigation_interface +{ + /** + * @var install_helper + */ + private $install_helper; + + /** + * Constructor + * + * @param install_helper $install_helper + */ + public function __construct(install_helper $install_helper) + { + $this->install_helper = $install_helper; + } + + /** + * {@inheritdoc} + */ + public function get() + { + if (!$this->install_helper->is_phpbb_installed()) + { + return array(); + } + + return array( + 'update' => array( + 'label' => 'UPDATE', + 'route' => 'phpbb_installer_update', + 'order' => 1, + array( + 'introduction' => array( + 'label' => 'INTRODUCTION_TITLE', + 'stage' => true, + 'order' => 0, + ), + 'requirements' => array( + 'label' => 'STAGE_REQUIREMENTS', + 'stage' => true, + 'order' => 1, + ), + 'obtain_data' => array( + 'label' => 'STAGE_OBTAIN_DATA', + 'stage' => true, + 'order' => 2, + ), + 'update_files' => array( + 'label' => 'STAGE_UPDATE_FILES', + 'stage' => true, + 'order' => 3, + ), + 'update_database' => array( + 'label' => 'STAGE_UPDATE_DATABASE', + 'stage' => true, + 'order' => 4, + ), + ), + ), + ); + } +} diff --git a/phpBB/phpbb/install/helper/update_helper.php b/phpBB/phpbb/install/helper/update_helper.php new file mode 100644 index 0000000000..a00731d317 --- /dev/null +++ b/phpBB/phpbb/install/helper/update_helper.php @@ -0,0 +1,113 @@ +<?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\install\helper; + +/** + * General helper functionality for the updater + */ +class update_helper +{ + /** + * @var string + */ + protected $path_to_new_files; + + /** + * @var string + */ + protected $path_to_old_files; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param string $phpbb_root_path + */ + public function __construct($phpbb_root_path) + { + $this->phpbb_root_path = $phpbb_root_path; + $this->path_to_new_files = $phpbb_root_path . 'install/update/new/'; + $this->path_to_old_files = $phpbb_root_path . 'install/update/old/'; + } + + /** + * Returns path to new update files + * + * @return string + */ + public function get_path_to_new_update_files() + { + return $this->path_to_new_files; + } + + /** + * Returns path to new update files + * + * @return string + */ + public function get_path_to_old_update_files() + { + return $this->path_to_old_files; + } + + /** + * Includes the updated file if available + * + * @param string $filename Path to the file relative to phpBB root path + */ + public function include_file($filename) + { + if (is_file($this->path_to_new_files . $filename)) + { + include_once($this->path_to_new_files . $filename); + } + else if (is_file($this->phpbb_root_path . $filename)) + { + include_once($this->phpbb_root_path . $filename); + } + } + + /** + * Customized version_compare() + * + * @param string $version_number1 + * @param string $version_number2 + * @param string|null $operator + * @return int|bool The returned value is identical to the PHP build-in function version_compare() + */ + public function phpbb_version_compare($version_number1, $version_number2, $operator = null) + { + if ($operator === null) + { + $result = version_compare( + str_replace('rc', 'RC', strtolower($version_number1)), + str_replace('rc', 'RC', strtolower($version_number2)) + ); + } + else + { + $result = version_compare( + str_replace('rc', 'RC', strtolower($version_number1)), + str_replace('rc', 'RC', strtolower($version_number2)), + $operator + ); + } + + return $result; + } +} diff --git a/phpBB/phpbb/install/installer.php b/phpBB/phpbb/install/installer.php new file mode 100644 index 0000000000..e04e233a76 --- /dev/null +++ b/phpBB/phpbb/install/installer.php @@ -0,0 +1,350 @@ +<?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\install; + +use phpbb\cache\driver\driver_interface; +use phpbb\di\ordered_service_collection; +use phpbb\install\exception\cannot_build_container_exception; +use phpbb\install\exception\installer_config_not_writable_exception; +use phpbb\install\exception\jump_to_restart_point_exception; +use phpbb\install\exception\resource_limit_reached_exception; +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\container_factory; +use phpbb\install\helper\iohandler\ajax_iohandler; +use phpbb\install\helper\iohandler\cli_iohandler; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\path_helper; + +class installer +{ + /** + * @var driver_interface + */ + protected $cache; + + /** + * @var container_factory + */ + protected $container_factory; + + /** + * @var config + */ + protected $install_config; + + /** + * @var ordered_service_collection + */ + protected $installer_modules; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** + * @var string + */ + protected $web_root; + + /** + * Stores the number of steps that a given module has + * + * @var array + */ + protected $module_step_count; + + /** + * @var bool + */ + protected $purge_cache_before; + + /** + * Constructor + * + * @param driver_interface $cache Cache service + * @param config $config Installer config handler + * @param path_helper $path_helper Path helper + * @param container_factory $container Container + */ + public function __construct(driver_interface $cache, config $config, path_helper $path_helper, container_factory $container) + { + $this->cache = $cache; + $this->install_config = $config; + $this->container_factory = $container; + $this->installer_modules = null; + $this->web_root = $path_helper->get_web_root_path(); + $this->purge_cache_before = false; + } + + /** + * Sets modules to execute + * + * Note: The installer will run modules in the order they are set in + * the array. + * + * @param ordered_service_collection $modules Service collection of module service names + */ + public function set_modules(ordered_service_collection $modules) + { + $this->installer_modules = $modules; + } + + /** + * Sets input-output handler objects + * + * @param iohandler_interface $iohandler + */ + public function set_iohandler(iohandler_interface $iohandler) + { + $this->iohandler = $iohandler; + } + + /** + * Sets whether to purge cache before the installation process + * + * @param bool $purge_cache_before + */ + public function set_purge_cache_before($purge_cache_before) + { + $this->purge_cache_before = $purge_cache_before; + } + + /** + * Run phpBB installer + */ + public function run() + { + if ($this->iohandler instanceof ajax_iohandler) + { + $this->iohandler->acquire_lock(); + } + + // Load install progress + $this->install_config->load_config(); + + if (!$this->install_config->get('cache_purged_before', false) && $this->purge_cache_before) + { + /** @var \phpbb\cache\driver\driver_interface $cache */ + $cache = $this->container_factory->get('cache.driver'); + $cache->purge(); + $this->install_config->set('cache_purged_before', true); + } + + // Recover install progress + $module_index = $this->recover_progress(); + + // Variable used to check if the install process have been finished + $install_finished = false; + $fail_cleanup = false; + $send_refresh = false; + + // We are installing something, so the introduction stage can go now... + $this->install_config->set_finished_navigation_stage(array('install', 0, 'introduction')); + $this->iohandler->set_finished_stage_menu(array('install', 0, 'introduction')); + + if ($this->install_config->get_task_progress_count() === 0) + { + // Count all tasks in the current installer modules + $step_count = 0; + + /** @var \phpbb\install\module_interface $module */ + foreach ($this->installer_modules as $name => $module) + { + $module_step_count = $module->get_step_count(); + $step_count += $module_step_count; + $this->module_step_count[$name] = $module_step_count; + } + + // Set task count + $this->install_config->set_task_progress_count($step_count); + } + + // Set up progress information + $this->iohandler->set_task_count( + $this->install_config->get_task_progress_count() + ); + + try + { + $iterator = $this->installer_modules->getIterator(); + + if ($module_index < $iterator->count()) + { + $iterator->seek($module_index); + } + else + { + $iterator->seek($module_index - 1); + $iterator->next(); + } + + while ($iterator->valid()) + { + $module = $iterator->current(); + $name = $iterator->key(); + + // Check if module should be executed + if (!$module->is_essential() && !$module->check_requirements()) + { + $this->install_config->set_finished_navigation_stage($module->get_navigation_stage_path()); + $this->iohandler->set_finished_stage_menu($module->get_navigation_stage_path()); + + $this->iohandler->add_log_message(array( + 'SKIP_MODULE', + $name, + )); + $this->install_config->increment_current_task_progress($this->module_step_count[$name]); + } + else + { + // Set the correct stage in the navigation bar + $this->install_config->set_active_navigation_stage($module->get_navigation_stage_path()); + $this->iohandler->set_active_stage_menu($module->get_navigation_stage_path()); + + $this->iohandler->send_response(); + + $module->run(); + + $this->install_config->set_finished_navigation_stage($module->get_navigation_stage_path()); + $this->iohandler->set_finished_stage_menu($module->get_navigation_stage_path()); + } + + $module_index++; + $iterator->next(); + + // Save progress + $this->install_config->set_active_module($name, $module_index); + + if ($iterator->valid() && ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0)) + { + throw new resource_limit_reached_exception(); + } + } + + // Installation finished + $install_finished = true; + + if ($this->iohandler instanceof cli_iohandler) + { + $this->iohandler->add_success_message('INSTALLER_FINISHED'); + } + else + { + // Start session if not installing and get user object + // to allow redirecting to ACP + $user = $this->container_factory->get('user'); + if (!isset($module) || !($module instanceof \phpbb\install\module\install_finish\module)) + { + $auth = $this->container_factory->get('auth'); + + $user->session_begin(); + $auth->acl($user->data); + $user->setup(); + } + + $phpbb_root_path = $this->container_factory->get_parameter('core.root_path'); + + $acp_url = append_sid($phpbb_root_path . 'adm/index.php', 'i=acp_help_phpbb&mode=help_phpbb', true, $user->session_id); + $this->iohandler->add_success_message('INSTALLER_FINISHED', array( + 'ACP_LINK', + $acp_url, + )); + } + } + catch (user_interaction_required_exception $e) + { + $this->iohandler->send_response(true); + } + catch (resource_limit_reached_exception $e) + { + $send_refresh = true; + } + catch (jump_to_restart_point_exception $e) + { + $this->install_config->jump_to_restart_point($e->get_restart_point_name()); + $send_refresh = true; + } + catch (\Exception $e) + { + $this->iohandler->add_error_message($e->getMessage()); + $this->iohandler->send_response(true); + $fail_cleanup = true; + } + + if ($this->iohandler instanceof ajax_iohandler) + { + $this->iohandler->release_lock(); + } + + if ($install_finished) + { + // Send install finished message + $this->iohandler->set_progress('INSTALLER_FINISHED', $this->install_config->get_task_progress_count()); + $this->iohandler->send_response(true); + } + else if ($send_refresh) + { + $this->iohandler->request_refresh(); + $this->iohandler->send_response(true); + } + + // Save install progress + try + { + if ($install_finished || $fail_cleanup) + { + $this->install_config->clean_up_config_file(); + $this->cache->purge(); + + try + { + /** @var \phpbb\cache\driver\driver_interface $cache */ + $cache = $this->container_factory->get('cache.driver'); + $cache->purge(); + } + catch (cannot_build_container_exception $e) + { + // Do not do anything, this just means there is no config.php yet + } + } + else + { + $this->install_config->save_config(); + } + } + catch (installer_config_not_writable_exception $e) + { + // It is allowed to fail this test during requirements testing + $progress_data = $this->install_config->get_progress_data(); + + if ($progress_data['last_task_module_name'] !== 'installer.module.requirements_install') + { + $this->iohandler->add_error_message('INSTALLER_CONFIG_NOT_WRITABLE'); + } + } + } + + /** + * Recover install progress + * + * @return string Index of the next installer module to execute + */ + protected function recover_progress() + { + $progress_array = $this->install_config->get_progress_data(); + return $progress_array['last_task_module_index']; + } +} diff --git a/phpBB/phpbb/install/installer_configuration.php b/phpBB/phpbb/install/installer_configuration.php new file mode 100644 index 0000000000..805140338c --- /dev/null +++ b/phpBB/phpbb/install/installer_configuration.php @@ -0,0 +1,147 @@ +<?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\install; + +use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; + +class installer_configuration implements ConfigurationInterface +{ + + /** + * Generates the configuration tree builder. + * + * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder + */ + public function getConfigTreeBuilder() + { + $treeBuilder = new TreeBuilder(); + $rootNode = $treeBuilder->root('installer'); + $rootNode + ->children() + ->arrayNode('admin') + ->children() + ->scalarNode('name')->defaultValue('admin')->cannotBeEmpty()->end() + ->scalarNode('password')->defaultValue('adminadmin')->cannotBeEmpty()->end() + ->scalarNode('email')->defaultValue('admin@example.org')->cannotBeEmpty()->end() + ->end() + ->end() + ->arrayNode('board') + ->children() + ->scalarNode('lang') + ->defaultValue('en') + ->cannotBeEmpty() + ->end() + ->scalarNode('name') + ->defaultValue('My Board') + ->cannotBeEmpty() + ->end() + ->scalarNode('description') + ->defaultValue('My amazing new phpBB board') + ->cannotBeEmpty() + ->end() + ->end() + ->end() + ->arrayNode('database') + ->children() + ->scalarNode('dbms') + ->defaultValue('sqlite3') + ->cannotBeEmpty() + ->isRequired() + ->end() + ->scalarNode('dbhost') + ->defaultValue(null) + ->end() + ->scalarNode('dbport') + ->defaultValue(null) + ->end() + ->scalarNode('dbuser') + ->defaultValue(null) + ->end() + ->scalarNode('dbpasswd') + ->defaultValue(null) + ->end() + ->scalarNode('dbname') + ->defaultValue(null) + ->end() + ->scalarNode('table_prefix') + ->defaultValue('phpbb_') + ->cannotBeEmpty() + ->isRequired() + ->end() + ->end() + ->end() + ->arrayNode('email') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->children() + ->booleanNode('smtp_delivery') + ->defaultValue(false) + ->treatNullLike(false) + ->end() + ->scalarNode('smtp_host') + ->defaultValue(null) + ->end() + ->scalarNode('smtp_port') + ->defaultValue(null) + ->end() + ->scalarNode('smtp_auth') + ->defaultValue(null) + ->end() + ->scalarNode('smtp_user') + ->defaultValue(null) + ->end() + ->scalarNode('smtp_pass') + ->defaultValue(null) + ->end() + ->end() + ->end() + ->arrayNode('server') + ->children() + ->booleanNode('cookie_secure') + ->defaultValue(false) + ->treatNullLike(false) + ->end() + ->scalarNode('server_protocol') + ->defaultValue('http://') + ->cannotBeEmpty() + ->end() + ->booleanNode('force_server_vars') + ->defaultValue(false) + ->treatNullLike(false) + ->end() + ->scalarNode('server_name') + ->defaultValue('localhost') + ->cannotBeEmpty() + ->end() + ->integerNode('server_port') + ->defaultValue(80) + ->min(1) + ->cannotBeEmpty() + ->end() + ->scalarNode('script_path') + ->defaultValue('/') + ->cannotBeEmpty() + ->end() + ->end() + ->end() + ->arrayNode('extensions') + ->prototype('scalar')->end() + ->defaultValue([]) + ->end() + ->end() + ; + return $treeBuilder; + } +} diff --git a/phpBB/phpbb/install/module/install_data/module.php b/phpBB/phpbb/install/module/install_data/module.php new file mode 100644 index 0000000000..77f1f73f1f --- /dev/null +++ b/phpBB/phpbb/install/module/install_data/module.php @@ -0,0 +1,28 @@ +<?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\install\module\install_data; + +/** + * Installer module for recovering and installing default data installation + */ +class module extends \phpbb\install\module_base +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('install', 0, 'install'); + } +} diff --git a/phpBB/phpbb/install/module/install_data/task/add_bots.php b/phpBB/phpbb/install/module/install_data/task/add_bots.php new file mode 100644 index 0000000000..1f1cecceb2 --- /dev/null +++ b/phpBB/phpbb/install/module/install_data/task/add_bots.php @@ -0,0 +1,263 @@ +<?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\install\module\install_data\task; + +use phpbb\install\exception\resource_limit_reached_exception; + +class add_bots extends \phpbb\install\task_base +{ + /** + * A list of the web-crawlers/bots we recognise by default + * + * Candidates but not included: + * 'Accoona [Bot]' 'Accoona-AI-Agent/' + * 'ASPseek [Crawler]' 'ASPseek/' + * 'Boitho [Crawler]' 'boitho.com-dc/' + * 'Bunnybot [Bot]' 'powered by www.buncat.de' + * 'Cosmix [Bot]' 'cfetch/' + * 'Crawler Search [Crawler]' '.Crawler-Search.de' + * 'Findexa [Crawler]' 'Findexa Crawler (' + * 'GBSpider [Spider]' 'GBSpider v' + * 'genie [Bot]' 'genieBot (' + * 'Hogsearch [Bot]' 'oegp v. 1.3.0' + * 'Insuranco [Bot]' 'InsurancoBot' + * 'IRLbot [Bot]' 'http://irl.cs.tamu.edu/crawler' + * 'ISC Systems [Bot]' 'ISC Systems iRc Search' + * 'Jyxobot [Bot]' 'Jyxobot/' + * 'Kraehe [Metasuche]' '-DIE-KRAEHE- META-SEARCH-ENGINE/' + * 'LinkWalker' 'LinkWalker' + * 'MMSBot [Bot]' 'http://www.mmsweb.at/bot.html' + * 'Naver [Bot]' 'nhnbot@naver.com)' + * 'NetResearchServer' 'NetResearchServer/' + * 'Nimble [Crawler]' 'NimbleCrawler' + * 'Ocelli [Bot]' 'Ocelli/' + * 'Onsearch [Bot]' 'onCHECK-Robot' + * 'Orange [Spider]' 'OrangeSpider' + * 'Sproose [Bot]' 'http://www.sproose.com/bot' + * 'Susie [Sync]' '!Susie (http://www.sync2it.com/susie)' + * 'Tbot [Bot]' 'Tbot/' + * 'Thumbshots [Capture]' 'thumbshots-de-Bot' + * 'Vagabondo [Crawler]' 'http://webagent.wise-guys.nl/' + * 'Walhello [Bot]' 'appie 1.1 (www.walhello.com)' + * 'WissenOnline [Bot]' 'WissenOnline-Bot' + * 'WWWeasel [Bot]' 'WWWeasel Robot v' + * 'Xaldon [Spider]' 'Xaldon WebSpider' + * + * @var array + */ + protected $bot_list = array( + 'AdsBot [Google]' => array('AdsBot-Google', ''), + 'Alexa [Bot]' => array('ia_archiver', ''), + 'Alta Vista [Bot]' => array('Scooter/', ''), + 'Ask Jeeves [Bot]' => array('Ask Jeeves', ''), + 'Baidu [Spider]' => array('Baiduspider', ''), + 'Bing [Bot]' => array('bingbot/', ''), + 'Exabot [Bot]' => array('Exabot', ''), + 'FAST Enterprise [Crawler]' => array('FAST Enterprise Crawler', ''), + 'FAST WebCrawler [Crawler]' => array('FAST-WebCrawler/', ''), + 'Francis [Bot]' => array('http://www.neomo.de/', ''), + 'Gigabot [Bot]' => array('Gigabot/', ''), + 'Google Adsense [Bot]' => array('Mediapartners-Google', ''), + 'Google Desktop' => array('Google Desktop', ''), + 'Google Feedfetcher' => array('Feedfetcher-Google', ''), + 'Google [Bot]' => array('Googlebot', ''), + 'Heise IT-Markt [Crawler]' => array('heise-IT-Markt-Crawler', ''), + 'Heritrix [Crawler]' => array('heritrix/1.', ''), + 'IBM Research [Bot]' => array('ibm.com/cs/crawler', ''), + 'ICCrawler - ICjobs' => array('ICCrawler - ICjobs', ''), + 'ichiro [Crawler]' => array('ichiro/', ''), + 'Majestic-12 [Bot]' => array('MJ12bot/', ''), + 'Metager [Bot]' => array('MetagerBot/', ''), + 'MSN NewsBlogs' => array('msnbot-NewsBlogs/', ''), + 'MSN [Bot]' => array('msnbot/', ''), + 'MSNbot Media' => array('msnbot-media/', ''), + 'Nutch [Bot]' => array('http://lucene.apache.org/nutch/', ''), + 'Online link [Validator]' => array('online link validator', ''), + 'psbot [Picsearch]' => array('psbot/0', ''), + 'Sensis [Crawler]' => array('Sensis Web Crawler', ''), + 'SEO Crawler' => array('SEO search Crawler/', ''), + 'Seoma [Crawler]' => array('Seoma [SEO Crawler]', ''), + 'SEOSearch [Crawler]' => array('SEOsearch/', ''), + 'Snappy [Bot]' => array('Snappy/1.1 ( http://www.urltrends.com/ )', ''), + 'Steeler [Crawler]' => array('http://www.tkl.iis.u-tokyo.ac.jp/~crawler/', ''), + 'Telekom [Bot]' => array('crawleradmin.t-info@telekom.de', ''), + 'TurnitinBot [Bot]' => array('TurnitinBot/', ''), + 'Voyager [Bot]' => array('voyager/', ''), + 'W3 [Sitesearch]' => array('W3 SiteSearch Crawler', ''), + 'W3C [Linkcheck]' => array('W3C-checklink/', ''), + 'W3C [Validator]' => array('W3C_Validator', ''), + 'YaCy [Bot]' => array('yacybot', ''), + 'Yahoo MMCrawler [Bot]' => array('Yahoo-MMCrawler/', ''), + 'Yahoo Slurp [Bot]' => array('Yahoo! DE Slurp', ''), + 'Yahoo [Bot]' => array('Yahoo! Slurp', ''), + 'YahooSeeker [Bot]' => array('YahooSeeker/', ''), + ); + + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $io_handler; + + /** + * @var \phpbb\language\language + */ + protected $language; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $install_config Installer's config + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Input-output handler for the installer + * @param \phpbb\install\helper\container_factory $container Installer's DI container + * @param \phpbb\language\language $language Language provider + * @param string $phpbb_root_path Relative path to phpBB root + * @param string $php_ext PHP extension + */ + public function __construct(\phpbb\install\helper\config $install_config, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler, + \phpbb\install\helper\container_factory $container, + \phpbb\language\language $language, + $phpbb_root_path, + $php_ext) + { + parent::__construct(true); + + $this->db = $container->get('dbal.conn'); + $this->install_config = $install_config; + $this->io_handler = $iohandler; + $this->language = $language; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->db->sql_return_on_error(true); + + $sql = 'SELECT group_id + FROM ' . GROUPS_TABLE . " + WHERE group_name = 'BOTS'"; + $result = $this->db->sql_query($sql); + $group_id = (int) $this->db->sql_fetchfield('group_id'); + $this->db->sql_freeresult($result); + + if (!$group_id) + { + // If we reach this point then something has gone very wrong + $this->io_handler->add_error_message('NO_GROUP'); + } + + $i = $this->install_config->get('add_bot_index', 0); + $bot_list = array_slice($this->bot_list, $i); + + foreach ($bot_list as $bot_name => $bot_ary) + { + $user_row = array( + 'user_type' => USER_IGNORE, + 'group_id' => $group_id, + 'username' => $bot_name, + 'user_regdate' => time(), + 'user_password' => '', + 'user_colour' => '9E8DA7', + 'user_email' => '', + 'user_lang' => $this->install_config->get('default_lang'), + 'user_style' => 1, + 'user_timezone' => 'UTC', + 'user_dateformat' => $this->language->lang('default_dateformat'), + 'user_allow_massemail' => 0, + 'user_allow_pm' => 0, + ); + + if (!function_exists('user_add')) + { + include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); + } + + $user_id = user_add($user_row); + + if (!$user_id) + { + // If we can't insert this user then continue to the next one to avoid inconsistent data + $this->io_handler->add_error_message('CONV_ERROR_INSERT_BOT'); + + $i++; + continue; + } + + $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $this->db->sql_build_array('INSERT', array( + 'bot_active' => 1, + 'bot_name' => (string) $bot_name, + 'user_id' => (int) $user_id, + 'bot_agent' => (string) $bot_ary[0], + 'bot_ip' => (string) $bot_ary[1], + )); + + $this->db->sql_query($sql); + + $i++; + + // Stop execution if resource limit is reached + if ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0) + { + break; + } + } + + $this->install_config->set('add_bot_index', $i); + + if ($i < sizeof($this->bot_list)) + { + throw new resource_limit_reached_exception(); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_ADD_BOTS'; + } +} diff --git a/phpBB/phpbb/install/module/install_data/task/add_languages.php b/phpBB/phpbb/install/module/install_data/task/add_languages.php new file mode 100644 index 0000000000..7ffdf4f276 --- /dev/null +++ b/phpBB/phpbb/install/module/install_data/task/add_languages.php @@ -0,0 +1,121 @@ +<?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\install\module\install_data\task; + +class add_languages extends \phpbb\install\task_base +{ + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var \phpbb\language\language_file_helper + */ + protected $language_helper; + + /** + * Constructor + * + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler + * @param \phpbb\install\helper\container_factory $container Installer's DI container + * @param \phpbb\language\language_file_helper $language_helper Language file helper service + */ + public function __construct(\phpbb\install\helper\iohandler\iohandler_interface $iohandler, + \phpbb\install\helper\container_factory $container, + \phpbb\language\language_file_helper $language_helper) + { + $this->db = $container->get('dbal.conn'); + $this->iohandler = $iohandler; + $this->language_helper = $language_helper; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->db->sql_return_on_error(true); + + $languages = $this->language_helper->get_available_languages(); + $installed_languages = array(); + + foreach ($languages as $lang_info) + { + $lang_pack = array( + 'lang_iso' => $lang_info['iso'], + 'lang_dir' => $lang_info['iso'], + 'lang_english_name' => htmlspecialchars($lang_info['name']), + 'lang_local_name' => htmlspecialchars($lang_info['local_name'], ENT_COMPAT, 'UTF-8'), + 'lang_author' => htmlspecialchars($lang_info['author'], ENT_COMPAT, 'UTF-8'), + ); + + $this->db->sql_query('INSERT INTO ' . LANG_TABLE . ' ' . $this->db->sql_build_array('INSERT', $lang_pack)); + + $installed_languages[] = (int) $this->db->sql_nextid(); + if ($this->db->get_sql_error_triggered()) + { + $error = $this->db->sql_error($this->db->get_sql_error_sql()); + $this->iohandler->add_error_message($error['message']); + } + } + + $sql = 'SELECT * FROM ' . PROFILE_FIELDS_TABLE; + $result = $this->db->sql_query($sql); + + $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, PROFILE_LANG_TABLE); + while ($row = $this->db->sql_fetchrow($result)) + { + foreach ($installed_languages as $lang_id) + { + $insert_buffer->insert(array( + 'field_id' => $row['field_id'], + 'lang_id' => $lang_id, + + // Remove phpbb_ from field name + 'lang_name' => strtoupper(substr($row['field_name'], 6)), + 'lang_explain' => '', + 'lang_default_value' => '', + )); + } + } + + $this->db->sql_freeresult($result); + + $insert_buffer->flush(); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_ADD_LANGUAGES'; + } +} diff --git a/phpBB/phpbb/install/module/install_data/task/add_modules.php b/phpBB/phpbb/install/module/install_data/task/add_modules.php new file mode 100644 index 0000000000..d21a5be823 --- /dev/null +++ b/phpBB/phpbb/install/module/install_data/task/add_modules.php @@ -0,0 +1,568 @@ +<?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\install\module\install_data\task; + +use phpbb\install\exception\resource_limit_reached_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\container_factory; +use phpbb\install\helper\iohandler\iohandler_interface; + +class add_modules extends \phpbb\install\task_base +{ + /** + * @var config + */ + protected $config; + + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + + /** + * @var \phpbb\extension\manager + */ + protected $extension_manager; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var \phpbb\module\module_manager + */ + protected $module_manager; + + /** + * Define the module structure so that we can populate the database without + * needing to hard-code module_id values + * + * @var array + */ + protected $module_categories = array( + 'acp' => array( + 'ACP_CAT_GENERAL' => array( + 'ACP_QUICK_ACCESS', + 'ACP_BOARD_CONFIGURATION', + 'ACP_CLIENT_COMMUNICATION', + 'ACP_SERVER_CONFIGURATION', + ), + 'ACP_CAT_FORUMS' => array( + 'ACP_MANAGE_FORUMS', + 'ACP_FORUM_BASED_PERMISSIONS', + ), + 'ACP_CAT_POSTING' => array( + 'ACP_MESSAGES', + 'ACP_ATTACHMENTS', + ), + 'ACP_CAT_USERGROUP' => array( + 'ACP_CAT_USERS', + 'ACP_GROUPS', + 'ACP_USER_SECURITY', + ), + 'ACP_CAT_PERMISSIONS' => array( + 'ACP_GLOBAL_PERMISSIONS', + 'ACP_FORUM_BASED_PERMISSIONS', + 'ACP_PERMISSION_ROLES', + 'ACP_PERMISSION_MASKS', + ), + 'ACP_CAT_CUSTOMISE' => array( + 'ACP_STYLE_MANAGEMENT', + 'ACP_EXTENSION_MANAGEMENT', + 'ACP_LANGUAGE', + ), + 'ACP_CAT_MAINTENANCE' => array( + 'ACP_FORUM_LOGS', + 'ACP_CAT_DATABASE', + ), + 'ACP_CAT_SYSTEM' => array( + 'ACP_AUTOMATION', + 'ACP_GENERAL_TASKS', + 'ACP_MODULE_MANAGEMENT', + ), + 'ACP_CAT_DOT_MODS' => null, + ), + 'mcp' => array( + 'MCP_MAIN' => null, + 'MCP_QUEUE' => null, + 'MCP_REPORTS' => null, + 'MCP_NOTES' => null, + 'MCP_WARN' => null, + 'MCP_LOGS' => null, + 'MCP_BAN' => null, + ), + 'ucp' => array( + 'UCP_MAIN' => null, + 'UCP_PROFILE' => null, + 'UCP_PREFS' => null, + 'UCP_PM' => null, + 'UCP_USERGROUPS' => null, + 'UCP_ZEBRA' => null, + ), + ); + + /** + * @var array + */ + protected $module_categories_basenames = array( + 'UCP_PM' => 'ucp_pm', + ); + + /** + * @var array + */ + protected $module_extras = array( + 'acp' => array( + 'ACP_QUICK_ACCESS' => array( + 'ACP_MANAGE_USERS', + 'ACP_GROUPS_MANAGE', + 'ACP_MANAGE_FORUMS', + 'ACP_MOD_LOGS', + 'ACP_BOTS', + 'ACP_PHP_INFO', + ), + 'ACP_FORUM_BASED_PERMISSIONS' => array( + 'ACP_FORUM_PERMISSIONS', + 'ACP_FORUM_PERMISSIONS_COPY', + 'ACP_FORUM_MODERATORS', + 'ACP_USERS_FORUM_PERMISSIONS', + 'ACP_GROUPS_FORUM_PERMISSIONS', + ), + ), + ); + + /** + * Constructor + * + * @parma config $config Installer's config + * @param iohandler_interface $iohandler Installer's input-output handler + * @param container_factory $container Installer's DI container + */ + public function __construct(config $config, iohandler_interface $iohandler, container_factory $container) + { + $this->config = $config; + $this->db = $container->get('dbal.conn'); + $this->extension_manager = $container->get('ext.manager'); + $this->iohandler = $iohandler; + $this->module_manager = $container->get('module.manager'); + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->db->sql_return_on_error(true); + + $module_classes = array('acp', 'mcp', 'ucp'); + $total = sizeof($module_classes); + $i = $this->config->get('module_class_index', 0); + $module_classes = array_slice($module_classes, $i); + + foreach ($module_classes as $module_class) + { + $categories = $this->config->get('module_categories_array', array()); + + $k = $this->config->get('module_categories_index', 0); + $module_categories = array_slice($this->module_categories[$module_class], $k); + $timed_out = false; + + foreach ($module_categories as $cat_name => $subs) + { + // Check if this sub-category has a basename. If it has, use it. + $basename = (isset($this->module_categories_basenames[$cat_name])) ? $this->module_categories_basenames[$cat_name] : ''; + + $module_data = array( + 'module_basename' => $basename, + 'module_enabled' => 1, + 'module_display' => 1, + 'parent_id' => 0, + 'module_class' => $module_class, + 'module_langname' => $cat_name, + 'module_mode' => '', + 'module_auth' => '', + ); + + $this->module_manager->update_module_data($module_data); + + // Check for last sql error happened + if ($this->db->get_sql_error_triggered()) + { + $error = $this->db->sql_error($this->db->get_sql_error_sql()); + $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); + } + + $categories[$cat_name]['id'] = (int) $module_data['module_id']; + $categories[$cat_name]['parent_id'] = 0; + + if (is_array($subs)) + { + foreach ($subs as $level2_name) + { + // Check if this sub-category has a basename. If it has, use it. + $basename = (isset($this->module_categories_basenames[$level2_name])) ? $this->module_categories_basenames[$level2_name] : ''; + + $module_data = array( + 'module_basename' => $basename, + 'module_enabled' => 1, + 'module_display' => 1, + 'parent_id' => (int) $categories[$cat_name]['id'], + 'module_class' => $module_class, + 'module_langname' => $level2_name, + 'module_mode' => '', + 'module_auth' => '', + ); + + $this->module_manager->update_module_data($module_data); + + // Check for last sql error happened + if ($this->db->get_sql_error_triggered()) + { + $error = $this->db->sql_error($this->db->get_sql_error_sql()); + $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); + } + + $categories[$level2_name]['id'] = (int) $module_data['module_id']; + $categories[$level2_name]['parent_id'] = (int) $categories[$cat_name]['id']; + } + } + + $k++; + + // Stop execution if resource limit is reached + if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0) + { + $timed_out = true; + break; + } + } + + $this->config->set('module_categories_array', $categories); + $this->config->set('module_categories_index', $k); + + if ($timed_out) + { + throw new resource_limit_reached_exception(); + } + + // Get the modules we want to add... returned sorted by name + $module_info = $this->module_manager->get_module_infos($module_class); + + $k = $this->config->get('module_info_index', 0); + $module_info = array_slice($module_info, $k); + + foreach ($module_info as $module_basename => $fileinfo) + { + foreach ($fileinfo['modes'] as $module_mode => $row) + { + foreach ($row['cat'] as $cat_name) + { + if (!isset($categories[$cat_name])) + { + continue; + } + + $module_data = array( + 'module_basename' => $module_basename, + 'module_enabled' => 1, + 'module_display' => (isset($row['display'])) ? (int) $row['display'] : 1, + 'parent_id' => (int) $categories[$cat_name]['id'], + 'module_class' => $module_class, + 'module_langname' => $row['title'], + 'module_mode' => $module_mode, + 'module_auth' => $row['auth'], + ); + + $this->module_manager->update_module_data($module_data); + + // Check for last sql error happened + if ($this->db->get_sql_error_triggered()) + { + $error = $this->db->sql_error($this->db->get_sql_error_sql()); + $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); + } + } + } + + $k++; + + // Stop execution if resource limit is reached + if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0) + { + $timed_out = true; + break; + } + } + + $this->config->set('module_info_index', $k); + + // Stop execution if resource limit is reached + if ($timed_out) + { + throw new resource_limit_reached_exception(); + } + + // Move some of the modules around since the code above will put them in the wrong place + if (!$this->config->get('modules_ordered', false)) + { + $this->order_modules($module_class); + $this->config->set('modules_ordered', true); + + // Stop execution if resource limit is reached + if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0) + { + throw new resource_limit_reached_exception(); + } + } + + // And now for the special ones + // (these are modules which appear in multiple categories and thus get added manually + // to some for more control) + if (isset($this->module_extras[$module_class])) + { + $this->add_module_extras($module_class); + } + + $this->module_manager->remove_cache_file($module_class); + + $i++; + + $this->config->set('module_class_index', $i); + $this->config->set('module_categories_index', 0); + $this->config->set('module_info_index', 0); + $this->config->set('added_extra_modules', false); + $this->config->set('modules_ordered', false); + $this->config->set('module_categories_array', array()); + + // Stop execution if resource limit is reached + if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0) + { + break; + } + } + + if ($i < $total) + { + throw new resource_limit_reached_exception(); + } + } + + /** + * Move modules to their correct place + * + * @param string $module_class + */ + protected function order_modules($module_class) + { + if ($module_class == 'acp') + { + // Move main module 4 up... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = 'acp_main' + AND module_class = 'acp' + AND module_mode = 'main'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'acp', 'move_up', 4); + + // Move permissions intro screen module 4 up... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = 'acp_permissions' + AND module_class = 'acp' + AND module_mode = 'intro'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'acp', 'move_up', 4); + + // Move manage users screen module 5 up... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = 'acp_users' + AND module_class = 'acp' + AND module_mode = 'overview'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'acp', 'move_up', 5); + + // Move extension management module 1 up... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_langname = 'ACP_EXTENSION_MANAGEMENT' + AND module_class = 'acp' + AND module_mode = '' + AND module_basename = ''"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'acp', 'move_up', 1); + } + + if ($module_class == 'mcp') + { + // Move pm report details module 3 down... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = 'mcp_pm_reports' + AND module_class = 'mcp' + AND module_mode = 'pm_report_details'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'mcp', 'move_down', 3); + + // Move closed pm reports module 3 down... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = 'mcp_pm_reports' + AND module_class = 'mcp' + AND module_mode = 'pm_reports_closed'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'mcp', 'move_down', 3); + + // Move open pm reports module 3 down... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = 'mcp_pm_reports' + AND module_class = 'mcp' + AND module_mode = 'pm_reports'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'mcp', 'move_down', 3); + } + + if ($module_class == 'ucp') + { + // Move attachment module 4 down... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = 'ucp_attachments' + AND module_class = 'ucp' + AND module_mode = 'attachments'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'ucp', 'move_down', 4); + + // Move notification options module 4 down... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = 'ucp_notifications' + AND module_class = 'ucp' + AND module_mode = 'notification_options'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'ucp', 'move_down', 4); + + // Move OAuth module 5 down... + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = 'ucp_auth_link' + AND module_class = 'ucp' + AND module_mode = 'auth_link'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $this->module_manager->move_module_by($row, 'ucp', 'move_down', 5); + } + } + + /** + * Add extra modules + * + * @param string $module_class + */ + protected function add_module_extras($module_class) + { + foreach ($this->module_extras[$module_class] as $cat_name => $mods) + { + $sql = 'SELECT module_id, left_id, right_id + FROM ' . MODULES_TABLE . " + WHERE module_langname = '" . $this->db->sql_escape($cat_name) . "' + AND module_class = '" . $this->db->sql_escape($module_class) . "'"; + $result = $this->db->sql_query_limit($sql, 1); + $row2 = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + foreach ($mods as $mod_name) + { + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_langname = '" . $this->db->sql_escape($mod_name) . "' + AND module_class = '" . $this->db->sql_escape($module_class) . "' + AND module_basename <> ''"; + $result = $this->db->sql_query_limit($sql, 1); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $module_data = array( + 'module_basename' => $row['module_basename'], + 'module_enabled' => (int) $row['module_enabled'], + 'module_display' => (int) $row['module_display'], + 'parent_id' => (int) $row2['module_id'], + 'module_class' => $row['module_class'], + 'module_langname' => $row['module_langname'], + 'module_mode' => $row['module_mode'], + 'module_auth' => $row['module_auth'], + ); + + $this->module_manager->update_module_data($module_data); + + // Check for last sql error happened + if ($this->db->get_sql_error_triggered()) + { + $error = $this->db->sql_error($this->db->get_sql_error_sql()); + $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); + } + } + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_ADD_MODULES'; + } +} diff --git a/phpBB/phpbb/install/module/install_data/task/create_search_index.php b/phpBB/phpbb/install/module/install_data/task/create_search_index.php new file mode 100644 index 0000000000..8a2f6aa1de --- /dev/null +++ b/phpBB/phpbb/install/module/install_data/task/create_search_index.php @@ -0,0 +1,134 @@ +<?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\install\module\install_data\task; + +use phpbb\auth\auth; +use phpbb\db\driver\driver_interface; +use phpbb\event\dispatcher; +use phpbb\config\config; +use phpbb\install\helper\container_factory; +use phpbb\language\language; +use phpbb\search\fulltext_native; +use phpbb\user; + +class create_search_index extends \phpbb\install\task_base +{ + /** + * @var auth + */ + protected $auth; + + /** + * @var config + */ + protected $config; + + /** + * @var driver_interface + */ + protected $db; + + /** + * @var dispatcher + */ + protected $phpbb_dispatcher; + + /** + * @var language + */ + protected $language; + + /** + * @var user + */ + protected $user; + + /** + * @var string phpBB root path + */ + protected $phpbb_root_path; + + /** + * @var string PHP file extension + */ + protected $php_ext; + + /** + * Constructor + * + * @param config $config phpBB config + * @param container_factory $container Installer's DI container + * @param string $phpbb_root_path phpBB root path + * @param string $php_ext PHP file extension + */ + public function __construct(config $config, container_factory $container, + $phpbb_root_path, $php_ext) + { + $this->auth = $container->get('auth'); + $this->config = $config; + $this->db = $container->get('dbal.conn'); + $this->language = $container->get('language'); + $this->phpbb_dispatcher = $container->get('dispatcher'); + $this->user = $container->get('user'); + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Make sure fulltext native load update is set + $this->config->set('fulltext_native_load_upd', 1); + + $error = false; + $search = new fulltext_native( + $error, + $this->phpbb_root_path, + $this->php_ext, + $this->auth, + $this->config, + $this->db, + $this->user, + $this->phpbb_dispatcher + ); + + $sql = 'SELECT post_id, post_subject, post_text, poster_id, forum_id + FROM ' . POSTS_TABLE; + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + $search->index('post', $row['post_id'], $row['post_text'], $row['post_subject'], $row['poster_id'], $row['forum_id']); + } + $this->db->sql_freeresult($result); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_CREATE_SEARCH_INDEX'; + } +} diff --git a/phpBB/phpbb/install/module/install_database/module.php b/phpBB/phpbb/install/module/install_database/module.php new file mode 100644 index 0000000000..0d8b33087f --- /dev/null +++ b/phpBB/phpbb/install/module/install_database/module.php @@ -0,0 +1,28 @@ +<?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\install\module\install_database; + +/** + * Installer module for database installation + */ +class module extends \phpbb\install\module_base +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('install', 0, 'install'); + } +} 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 new file mode 100644 index 0000000000..8002e3ed97 --- /dev/null +++ b/phpBB/phpbb/install/module/install_database/task/add_config_settings.php @@ -0,0 +1,372 @@ +<?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\install\module\install_database\task; + +use phpbb\install\exception\resource_limit_reached_exception; + +/** + * Create database schema + */ +class add_config_settings extends \phpbb\install\task_base +{ + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + + /** + * @var \phpbb\filesystem\filesystem_interface + */ + protected $filesystem; + + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var \phpbb\language\language + */ + protected $language; + + /** + * @var \phpbb\passwords\manager + */ + protected $password_manager; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $config_table; + + /** + * @var string + */ + protected $user_table; + + /** + * @var string + */ + protected $topics_table; + + /** + * @var string + */ + protected $forums_table; + + /** + * @var string + */ + protected $posts_table; + + /** + * @var string + */ + protected $moderator_cache_table; + + /** + * Constructor + * + * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem service + * @param \phpbb\install\helper\config $install_config Installer's config helper + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler + * @param \phpbb\install\helper\container_factory $container Installer's DI container + * @param \phpbb\language\language $language Language service + * @param string $phpbb_root_path Path to phpBB's root + */ + public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, + \phpbb\install\helper\config $install_config, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler, + \phpbb\install\helper\container_factory $container, + \phpbb\language\language $language, + $phpbb_root_path) + { + $this->db = $container->get('dbal.conn'); + $this->filesystem = $filesystem; + $this->install_config = $install_config; + $this->iohandler = $iohandler; + $this->language = $language; + $this->password_manager = $container->get('passwords.manager'); + $this->phpbb_root_path = $phpbb_root_path; + + // Table names + $this->config_table = $container->get_parameter('tables.config'); + $this->forums_table = $container->get_parameter('tables.forums'); + $this->topics_table = $container->get_parameter('tables.topics'); + $this->user_table = $container->get_parameter('tables.users'); + $this->moderator_cache_table = $container->get_parameter('tables.moderator_cache'); + $this->posts_table = $container->get_parameter('tables.posts'); + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->db->sql_return_on_error(true); + + $server_name = $this->install_config->get('server_name'); + $current_time = time(); + $user_ip = phpbb_ip_normalise($this->iohandler->get_server_variable('REMOTE_ADDR')); + $user_ip = ($user_ip === false) ? '' : $user_ip; + $referer = $this->iohandler->get_server_variable('REFERER'); + + // Calculate cookie domain + $cookie_domain = $server_name; + + if (strpos($cookie_domain, 'www.') === 0) + { + $cookie_domain = substr($cookie_domain, 3); + } + + // Set default config and post data, this applies to all DB's + $sql_ary = array( + 'INSERT INTO ' . $this->config_table . " (config_name, config_value) + VALUES ('board_startdate', '$current_time')", + + 'INSERT INTO ' . $this->config_table . " (config_name, config_value) + VALUES ('default_lang', '" . $this->db->sql_escape($this->install_config->get('default_lang')) . "')", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('img_imagick')) . "' + WHERE config_name = 'img_imagick'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('server_name')) . "' + WHERE config_name = 'server_name'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('server_port')) . "' + WHERE config_name = 'server_port'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('board_email')) . "' + WHERE config_name = 'board_email'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('board_email')) . "' + WHERE config_name = 'board_contact'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($cookie_domain) . "' + WHERE config_name = 'cookie_domain'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->language->lang('default_dateformat')) . "' + WHERE config_name = 'default_dateformat'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('email_enable')) . "' + WHERE config_name = 'email_enable'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_delivery')) . "' + WHERE config_name = 'smtp_delivery'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_host')) . "' + WHERE config_name = 'smtp_host'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_port')) . "' + WHERE config_name = 'smtp_port'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_auth')) . "' + WHERE config_name = 'smtp_auth_method'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_user')) . "' + WHERE config_name = 'smtp_username'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_pass')) . "' + WHERE config_name = 'smtp_password'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('cookie_secure')) . "' + WHERE config_name = 'cookie_secure'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('force_server_vars')) . "' + WHERE config_name = 'force_server_vars'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('script_path')) . "' + WHERE config_name = 'script_path'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('server_protocol')) . "' + WHERE config_name = 'server_protocol'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "' + WHERE config_name = 'newest_username'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . md5(mt_rand()) . "' + WHERE config_name = 'avatar_salt'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . md5(mt_rand()) . "' + WHERE config_name = 'plupload_salt'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('board_name')) . "' + WHERE config_name = 'sitename'", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->install_config->get('board_description')) . "' + WHERE config_name = 'site_desc'", + + 'UPDATE ' . $this->user_table . " + SET username = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "', + user_password='" . $this->password_manager->hash($this->install_config->get('admin_passwd')) . "', + user_ip = '" . $this->db->sql_escape($user_ip) . "', + 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'", + + 'UPDATE ' . $this->moderator_cache_table . " + SET username = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "' + WHERE username = 'Admin'", + + 'UPDATE ' . $this->forums_table . " + SET forum_last_poster_name = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "' + WHERE forum_last_poster_name = 'Admin'", + + 'UPDATE ' . $this->topics_table . " + SET topic_first_poster_name = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "', + topic_last_poster_name = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "' + WHERE topic_first_poster_name = 'Admin' + OR topic_last_poster_name = 'Admin'", + + 'UPDATE ' . $this->user_table . " + SET user_regdate = $current_time", + + 'UPDATE ' . $this->posts_table . " + SET post_time = $current_time, poster_ip = '" . $this->db->sql_escape($user_ip) . "'", + + 'UPDATE ' . $this->topics_table . " + SET topic_time = $current_time, topic_last_post_time = $current_time", + + 'UPDATE ' . $this->forums_table . " + SET forum_last_post_time = $current_time", + + 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($this->db->sql_server_info(true)) . "' + WHERE config_name = 'dbms_version'", + ); + + if (@extension_loaded('gd')) + { + $sql_ary[] = 'UPDATE ' . $this->config_table . " + SET config_value = 'core.captcha.plugins.gd' + WHERE config_name = 'captcha_plugin'"; + + $sql_ary[] = 'UPDATE ' . $this->config_table . " + SET config_value = '1' + WHERE config_name = 'captcha_gd'"; + } + + $ref = substr($referer, strpos($referer, '://') + 3); + if (!(stripos($ref, $server_name) === 0)) + { + $sql_ary[] = 'UPDATE ' . $this->config_table . " + SET config_value = '0' + WHERE config_name = 'referer_validation'"; + } + + // We set a (semi-)unique cookie name to bypass login issues related to the cookie name. + $cookie_name = 'phpbb3_'; + $rand_str = md5(mt_rand()); + $rand_str = str_replace('0', 'z', base_convert($rand_str, 16, 35)); + $rand_str = substr($rand_str, 0, 5); + $cookie_name .= strtolower($rand_str); + + $sql_ary[] = 'UPDATE ' . $this->config_table . " + SET config_value = '" . $this->db->sql_escape($cookie_name) . "' + WHERE config_name = 'cookie_name'"; + + // Disable avatars if upload directory is not writable + if (!$this->filesystem->is_writable($this->phpbb_root_path . 'images/avatars/upload/')) + { + $sql_ary[] = 'UPDATE ' . $this->config_table . " + SET config_value = '0' + WHERE config_name = 'allow_avatar'"; + + $sql_ary[] = 'UPDATE ' . $this->config_table . " + SET config_value = '0' + WHERE config_name = 'allow_avatar_upload'"; + } + + $i = $this->install_config->get('add_config_settings_index', 0); + $total = sizeof($sql_ary); + $sql_ary = array_slice($sql_ary, $i); + + foreach ($sql_ary as $sql) + { + if (!$this->db->sql_query($sql)) + { + $error = $this->db->sql_error($this->db->get_sql_error_sql()); + $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); + } + + $i++; + + // Stop execution if resource limit is reached + if ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0) + { + break; + } + } + + if ($i < $total) + { + $this->install_config->set('add_config_settings_index', $i); + throw new resource_limit_reached_exception(); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_ADD_CONFIG_SETTINGS'; + } +} diff --git a/phpBB/phpbb/install/module/install_database/task/add_default_data.php b/phpBB/phpbb/install/module/install_database/task/add_default_data.php new file mode 100644 index 0000000000..e32101a3f7 --- /dev/null +++ b/phpBB/phpbb/install/module/install_database/task/add_default_data.php @@ -0,0 +1,184 @@ +<?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\install\module\install_database\task; + +use phpbb\install\exception\resource_limit_reached_exception; + +/** + * Create database schema + */ +class add_default_data extends \phpbb\install\task_base +{ + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + + /** + * @var \phpbb\install\helper\database + */ + protected $database_helper; + + /** + * @var \phpbb\install\helper\config + */ + protected $config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var \phpbb\language\language + */ + protected $language; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param \phpbb\install\helper\database $db_helper Installer's database helper + * @param \phpbb\install\helper\config $config Installer config + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler + * @param \phpbb\install\helper\container_factory $container Installer's DI container + * @param \phpbb\language\language $language Language service + * @param string $root_path Root path of phpBB + */ + public function __construct(\phpbb\install\helper\database $db_helper, + \phpbb\install\helper\config $config, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler, + \phpbb\install\helper\container_factory $container, + \phpbb\language\language $language, + $root_path) + { + $this->db = $container->get('dbal.conn.driver'); + $this->database_helper = $db_helper; + $this->config = $config; + $this->iohandler = $iohandler; + $this->language = $language; + $this->phpbb_root_path = $root_path; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->db->sql_return_on_error(true); + + $table_prefix = $this->config->get('table_prefix'); + $dbms = $this->config->get('dbms'); + $dbms_info = $this->database_helper->get_available_dbms($dbms); + + // Get schema data from file + $sql_query = @file_get_contents($this->phpbb_root_path . 'install/schemas/schema_data.sql'); + + // Clean up SQL + $sql_query = $this->replace_dbms_specific_sql($sql_query); + $sql_query = preg_replace('# phpbb_([^\s]*) #i', ' ' . $table_prefix . '\1 ', $sql_query); + $sql_query = preg_replace_callback('#\{L_([A-Z0-9\-_]*)\}#s', array($this, 'lang_replace_callback'), $sql_query); + $sql_query = $this->database_helper->remove_comments($sql_query); + $sql_query = $this->database_helper->split_sql_file($sql_query, $dbms_info[$dbms]['DELIM']); + + $i = $this->config->get('add_default_data_index', 0); + $total = sizeof($sql_query); + $sql_query = array_slice($sql_query, $i); + + foreach ($sql_query as $sql) + { + if (!$this->db->sql_query($sql)) + { + $error = $this->db->sql_error($this->db->get_sql_error_sql()); + $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); + } + + $i++; + + // Stop execution if resource limit is reached + if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0) + { + break; + } + } + + $this->config->set('add_default_data_index', $i); + + if ($i < $total) + { + throw new resource_limit_reached_exception(); + } + } + + /** + * Process DB specific SQL + * + * @return string + */ + protected function replace_dbms_specific_sql($query) + { + if ($this->db instanceof \phpbb\db\driver\mssql_base) + { + $query = preg_replace('#\# MSSQL IDENTITY (phpbb_[a-z_]+) (ON|OFF) \##s', 'SET IDENTITY_INSERT \1 \2;', $query); + } + else if ($this->db instanceof \phpbb\db\driver\postgres) + { + $query = preg_replace('#\# POSTGRES (BEGIN|COMMIT) \##s', '\1; ', $query); + } + else if ($this->db instanceof \phpbb\db\driver\mysql_base) + { + $query = str_replace('\\', '\\\\', $query); + } + + return $query; + } + + /** + * Callback function for language replacing + * + * @param array $matches + * @return string + */ + public function lang_replace_callback($matches) + { + if (!empty($matches[1])) + { + return $this->db->sql_escape($this->language->lang($matches[1])); + } + + return ''; + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_ADD_DEFAULT_DATA'; + } +} diff --git a/phpBB/phpbb/install/module/install_database/task/add_tables.php b/phpBB/phpbb/install/module/install_database/task/add_tables.php new file mode 100644 index 0000000000..f344f91582 --- /dev/null +++ b/phpBB/phpbb/install/module/install_database/task/add_tables.php @@ -0,0 +1,151 @@ +<?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\install\module\install_database\task; + +use phpbb\install\exception\resource_limit_reached_exception; + +/** + * Create tables + */ +class add_tables extends \phpbb\install\task_base +{ + /** + * @var \phpbb\install\helper\config + */ + protected $config; + + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + + /** + * @var \phpbb\db\tools\tools_interface + */ + protected $db_tools; + + /** + * @var \phpbb\filesystem\filesystem_interface + */ + protected $filesystem; + + /** + * @var string + */ + protected $schema_file_path; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $config + * @param \phpbb\install\helper\database $db_helper + * @param \phpbb\filesystem\filesystem_interface $filesystem + * @param string $phpbb_root_path + */ + public function __construct(\phpbb\install\helper\config $config, + \phpbb\install\helper\database $db_helper, + \phpbb\filesystem\filesystem_interface $filesystem, + $phpbb_root_path) + { + $dbms = $db_helper->get_available_dbms($config->get('dbms')); + $dbms = $dbms[$config->get('dbms')]['DRIVER']; + $factory = new \phpbb\db\tools\factory(); + + $this->db = new $dbms(); + $this->db->sql_connect( + $config->get('dbhost'), + $config->get('dbuser'), + $config->get('dbpasswd'), + $config->get('dbname'), + $config->get('dbport'), + false, + false + ); + + $this->config = $config; + $this->db_tools = $factory->get($this->db); + $this->filesystem = $filesystem; + $this->schema_file_path = $phpbb_root_path . 'store/schema.json'; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->db->sql_return_on_error(true); + + $table_prefix = $this->config->get('table_prefix'); + $change_prefix = $this->config->get('change_table_prefix', true); + + if (!defined('CONFIG_TABLE')) + { + // CONFIG_TABLE is required by sql_create_index() to check the + // length of index names. However table_prefix is not defined + // here yet, so we need to create the constant ourselves. + define('CONFIG_TABLE', $table_prefix . 'config'); + } + + $db_table_schema = @file_get_contents($this->schema_file_path); + $db_table_schema = json_decode($db_table_schema, true); + $total = sizeof($db_table_schema); + $i = $this->config->get('add_table_index', 0); + $db_table_schema = array_slice($db_table_schema, $i); + + foreach ($db_table_schema as $table_name => $table_data) + { + $i++; + + $this->db_tools->sql_create_table( + ( ($change_prefix) ? ($table_prefix . substr($table_name, 6)) : $table_name ), + $table_data + ); + + // Stop execution if resource limit is reached + if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0) + { + break; + } + } + + $this->config->set('add_table_index', $i); + + if ($i < $total) + { + throw new resource_limit_reached_exception(); + } + else + { + @unlink($this->schema_file_path); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_CREATE_TABLES'; + } +} diff --git a/phpBB/phpbb/install/module/install_database/task/create_schema.php b/phpBB/phpbb/install/module/install_database/task/create_schema.php new file mode 100644 index 0000000000..a5635d5dbe --- /dev/null +++ b/phpBB/phpbb/install/module/install_database/task/create_schema.php @@ -0,0 +1,234 @@ +<?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\install\module\install_database\task; + +use phpbb\install\exception\resource_limit_reached_exception; + +/** + * Create database schema + */ +class create_schema extends \phpbb\install\task_base +{ + /** + * @var \phpbb\install\helper\config + */ + protected $config; + + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + + /** + * @var \phpbb\db\tools\tools_interface + */ + protected $db_tools; + + /** + * @var \phpbb\install\helper\database + */ + protected $database_helper; + + /** + * @var \phpbb\filesystem\filesystem_interface + */ + protected $filesystem; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $config Installer's config provider + * @param \phpbb\install\helper\database $db_helper Installer's database helper + * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem service + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler + * @param string $phpbb_root_path Path phpBB's root + * @param string $php_ext Extension of PHP files + */ + public function __construct(\phpbb\install\helper\config $config, + \phpbb\install\helper\database $db_helper, + \phpbb\filesystem\filesystem_interface $filesystem, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler, + $phpbb_root_path, + $php_ext) + { + $dbms = $db_helper->get_available_dbms($config->get('dbms')); + $dbms = $dbms[$config->get('dbms')]['DRIVER']; + $factory = new \phpbb\db\tools\factory(); + + $this->db = new $dbms(); + $this->db->sql_connect( + $config->get('dbhost'), + $config->get('dbuser'), + $config->get('dbpasswd'), + $config->get('dbname'), + $config->get('dbport'), + false, + false + ); + + $this->config = $config; + $this->db_tools = $factory->get($this->db); + $this->database_helper = $db_helper; + $this->filesystem = $filesystem; + $this->iohandler = $iohandler; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // As this task may take a large amount of time to complete refreshing the page might be necessary for some + // server configurations with limited resources + if (!$this->config->get('pre_schema_forced_refresh')) + { + if ($this->config->get_time_remaining() < 5) + { + $this->config->set('pre_schema_forced_refresh', true); + throw new resource_limit_reached_exception(); + } + } + + $this->db->sql_return_on_error(true); + + $dbms = $this->config->get('dbms'); + $dbms_info = $this->database_helper->get_available_dbms($dbms); + $schema_name = $dbms_info[$dbms]['SCHEMA']; + $delimiter = $dbms_info[$dbms]['DELIM']; + $table_prefix = $this->config->get('table_prefix'); + + if ($dbms === 'mysql') + { + if (version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) + { + $schema_name .= '_41'; + } + else + { + $schema_name .= '_40'; + } + } + + $db_schema_path = $this->phpbb_root_path . 'install/schemas/' . $schema_name . '_schema.sql'; + + // Load database vendor specific code if there is any + if ($this->filesystem->exists($db_schema_path)) + { + $sql_query = @file_get_contents($db_schema_path); + $sql_query = preg_replace('#phpbb_#i', $table_prefix, $sql_query); + $sql_query = $this->database_helper->remove_comments($sql_query); + $sql_query = $this->database_helper->split_sql_file($sql_query, $delimiter); + + foreach ($sql_query as $sql) + { + if (!$this->db->sql_query($sql)) + { + $error = $this->db->sql_error($this->db->get_sql_error_sql()); + $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); + } + } + + unset($sql_query); + } + + $change_prefix = false; + + // Generate database schema + if ($this->filesystem->exists($this->phpbb_root_path . 'install/schemas/schema.json')) + { + $db_table_schema = @file_get_contents($this->phpbb_root_path . 'install/schemas/schema.json'); + $db_table_schema = json_decode($db_table_schema, true); + $change_prefix = true; + } + else + { + global $table_prefix; + + $table_prefix = $this->config->get('table_prefix'); + + if (!defined('CONFIG_TABLE')) + { + // We need to include the constants file for the table constants + // when we generate the schema from the migration files. + include ($this->phpbb_root_path . 'includes/constants.' . $this->php_ext); + } + + $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, null, $this->php_ext); + $migrator_classes = $finder->core_path('phpbb/db/migration/data/')->get_classes(); + $factory = new \phpbb\db\tools\factory(); + $db_tools = $factory->get($this->db, true); + $schema_generator = new \phpbb\db\migration\schema_generator( + $migrator_classes, + new \phpbb\config\config(array()), + $this->db, + $db_tools, + $this->phpbb_root_path, + $this->php_ext, + $table_prefix + ); + $db_table_schema = $schema_generator->get_schema(); + } + + if (!defined('CONFIG_TABLE')) + { + // CONFIG_TABLE is required by sql_create_index() to check the + // length of index names. However table_prefix is not defined + // here yet, so we need to create the constant ourselves. + define('CONFIG_TABLE', $table_prefix . 'config'); + } + + foreach ($db_table_schema as $table_name => $table_data) + { + $this->db_tools->sql_create_table( + ( ($change_prefix) ? ($table_prefix . substr($table_name, 6)) : $table_name ), + $table_data + ); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_CREATE_DATABASE_SCHEMA'; + } +} diff --git a/phpBB/phpbb/install/module/install_database/task/create_schema_file.php b/phpBB/phpbb/install/module/install_database/task/create_schema_file.php new file mode 100644 index 0000000000..b6d6ece17f --- /dev/null +++ b/phpBB/phpbb/install/module/install_database/task/create_schema_file.php @@ -0,0 +1,164 @@ +<?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\install\module\install_database\task; + +use phpbb\install\exception\resource_limit_reached_exception; + +/** + * Create database schema + */ +class create_schema_file extends \phpbb\install\task_base +{ + /** + * @var \phpbb\install\helper\config + */ + protected $config; + + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + + /** + * @var \phpbb\filesystem\filesystem_interface + */ + protected $filesystem; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $config Installer's config provider + * @param \phpbb\install\helper\database $db_helper Installer's database helper + * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem service + * @param string $phpbb_root_path Path phpBB's root + * @param string $php_ext Extension of PHP files + */ + public function __construct(\phpbb\install\helper\config $config, + \phpbb\install\helper\database $db_helper, + \phpbb\filesystem\filesystem_interface $filesystem, + $phpbb_root_path, + $php_ext) + { + $dbms = $db_helper->get_available_dbms($config->get('dbms')); + $dbms = $dbms[$config->get('dbms')]['DRIVER']; + + $this->db = new $dbms(); + $this->db->sql_connect( + $config->get('dbhost'), + $config->get('dbuser'), + $config->get('dbpasswd'), + $config->get('dbname'), + $config->get('dbport'), + false, + false + ); + + $this->config = $config; + $this->filesystem = $filesystem; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Generate database schema + if ($this->filesystem->exists($this->phpbb_root_path . 'install/schemas/schema.json')) + { + $db_table_schema = @file_get_contents($this->phpbb_root_path . 'install/schemas/schema.json'); + $this->config->set('change_table_prefix', true); + } + else + { + global $table_prefix; + + // As this task may take a large amount of time to complete refreshing the page might be necessary for some + // server configurations with limited resources + if (!$this->config->get('pre_schema_forced_refresh', false)) + { + if ($this->config->get_time_remaining() < 5) + { + $this->config->set('pre_schema_forced_refresh', true); + throw new resource_limit_reached_exception(); + } + } + + $table_prefix = $this->config->get('table_prefix'); + + if (!defined('CONFIG_TABLE')) + { + // We need to include the constants file for the table constants + // when we generate the schema from the migration files. + include ($this->phpbb_root_path . 'includes/constants.' . $this->php_ext); + } + + $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, null, $this->php_ext); + $migrator_classes = $finder->core_path('phpbb/db/migration/data/')->get_classes(); + $factory = new \phpbb\db\tools\factory(); + $db_tools = $factory->get($this->db, true); + $schema_generator = new \phpbb\db\migration\schema_generator( + $migrator_classes, + new \phpbb\config\config(array()), + $this->db, + $db_tools, + $this->phpbb_root_path, + $this->php_ext, + $table_prefix + ); + $db_table_schema = $schema_generator->get_schema(); + $db_table_schema = json_encode($db_table_schema, JSON_PRETTY_PRINT); + + $this->config->set('change_table_prefix', false); + } + + $fp = @fopen($this->phpbb_root_path . 'store/schema.json', 'wb'); + if (!$fp) + { + throw new \Exception('INST_SCHEMA_FILE_NOT_WRITABLE'); + } + + fwrite($fp, $db_table_schema); + fclose($fp); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_CREATE_DATABASE_SCHEMA_FILE'; + } +} 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 new file mode 100644 index 0000000000..49c8ea23ad --- /dev/null +++ b/phpBB/phpbb/install/module/install_database/task/set_up_database.php @@ -0,0 +1,164 @@ +<?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\install\module\install_database\task; + +/** + * Set up database for table generation + */ +class set_up_database extends \phpbb\install\task_base +{ + /** + * @var \phpbb\install\helper\config + */ + protected $config; + + /** + * @var \phpbb\db\driver\driver_interface + */ + protected $db; + + /** + * @var \phpbb\install\helper\database + */ + protected $database_helper; + + /** + * @var \phpbb\filesystem\filesystem_interface + */ + protected $filesystem; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var string + */ + protected $schema_file_path; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $config + * @param \phpbb\install\helper\database $db_helper + * @param \phpbb\filesystem\filesystem_interface $filesystem + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler + * @param string $phpbb_root_path + */ + public function __construct(\phpbb\install\helper\config $config, + \phpbb\install\helper\database $db_helper, + \phpbb\filesystem\filesystem_interface $filesystem, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler, + $phpbb_root_path) + { + $dbms = $db_helper->get_available_dbms($config->get('dbms')); + $dbms = $dbms[$config->get('dbms')]['DRIVER']; + + $this->db = new $dbms(); + $this->db->sql_connect( + $config->get('dbhost'), + $config->get('dbuser'), + $config->get('dbpasswd'), + $config->get('dbname'), + $config->get('dbport'), + false, + false + ); + + $this->config = $config; + $this->database_helper = $db_helper; + $this->filesystem = $filesystem; + $this->iohandler = $iohandler; + $this->phpbb_root_path = $phpbb_root_path; + + parent::__construct(false); + } + + /** + * {@inheritdoc} + */ + public function check_requirements() + { + $dbms = $this->config->get('dbms'); + $dbms_info = $this->database_helper->get_available_dbms($dbms); + $schema_name = $dbms_info[$dbms]['SCHEMA']; + + if ($dbms === 'mysql') + { + if (version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) + { + $schema_name .= '_41'; + } + else + { + $schema_name .= '_40'; + } + } + + $this->schema_file_path = $this->phpbb_root_path . 'install/schemas/' . $schema_name . '_schema.sql'; + + return $this->filesystem->exists($this->schema_file_path); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->db->sql_return_on_error(true); + + $dbms = $this->config->get('dbms'); + $dbms_info = $this->database_helper->get_available_dbms($dbms); + $delimiter = $dbms_info[$dbms]['DELIM']; + $table_prefix = $this->config->get('table_prefix'); + + $sql_query = @file_get_contents($this->schema_file_path); + $sql_query = preg_replace('#phpbb_#i', $table_prefix, $sql_query); + $sql_query = $this->database_helper->remove_comments($sql_query); + $sql_query = $this->database_helper->split_sql_file($sql_query, $delimiter); + + foreach ($sql_query as $sql) + { + if (!$this->db->sql_query($sql)) + { + $error = $this->db->sql_error($this->db->get_sql_error_sql()); + $this->iohandler->add_error_message('INST_ERR_DB', $error['message']); + } + } + + unset($sql_query); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_SETUP_DATABASE'; + } +} diff --git a/phpBB/phpbb/install/module/install_filesystem/module.php b/phpBB/phpbb/install/module/install_filesystem/module.php new file mode 100644 index 0000000000..7215449664 --- /dev/null +++ b/phpBB/phpbb/install/module/install_filesystem/module.php @@ -0,0 +1,28 @@ +<?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\install\module\install_filesystem; + +/** + * Installer module for filesystem installation + */ +class module extends \phpbb\install\module_base +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('install', 0, 'install'); + } +} 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 new file mode 100644 index 0000000000..5bc425b929 --- /dev/null +++ b/phpBB/phpbb/install/module/install_filesystem/task/create_config_file.php @@ -0,0 +1,244 @@ +<?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\install\module\install_filesystem\task; + +use phpbb\install\exception\user_interaction_required_exception; + +/** + * Dumps config file + */ +class create_config_file extends \phpbb\install\task_base +{ + /** + * @var \phpbb\filesystem\filesystem_interface + */ + protected $filesystem; + + /** + * @var \phpbb\install\helper\database + */ + protected $db_helper; + + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * @var array + */ + protected $options; + + /** + * Constructor + * + * @param \phpbb\filesystem\filesystem_interface $filesystem + * @param \phpbb\install\helper\config $install_config + * @param \phpbb\install\helper\database $db_helper + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler + * @param string $phpbb_root_path + * @param string $php_ext + * @param array $options + */ + public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, + \phpbb\install\helper\config $install_config, + \phpbb\install\helper\database $db_helper, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler, + $phpbb_root_path, + $php_ext, + $options = array()) + { + $this->install_config = $install_config; + $this->db_helper = $db_helper; + $this->filesystem = $filesystem; + $this->iohandler = $iohandler; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + $this->options = array_merge(array( + 'debug' => false, + 'debug_container' => false, + 'environment' => null, + ), $options); + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $config_written = true; + + // Create config.php + $path_to_config = $this->phpbb_root_path . 'config.' . $this->php_ext; + + $fp = @fopen($path_to_config, 'w'); + if (!$fp) + { + $config_written = false; + } + + $config_content = $this->get_config_data($this->options['debug'], $this->options['debug_container'], $this->options['environment']); + + if (!@fwrite($fp, $config_content)) + { + $config_written = false; + } + + @fclose($fp); + + // chmod config.php to be only readable + if ($config_written) + { + try + { + $this->filesystem->phpbb_chmod($path_to_config, \phpbb\filesystem\filesystem_interface::CHMOD_READ); + } + catch (\phpbb\filesystem\exception\filesystem_exception $e) + { + // Do nothing, the user will get a notice later + } + } + else + { + $this->iohandler->add_error_message('UNABLE_TO_WRITE_CONFIG_FILE'); + throw new user_interaction_required_exception(); + } + + // Create a lock file to indicate that there is an install in progress + $fp = @fopen($this->phpbb_root_path . 'cache/install_lock', 'wb'); + if ($fp === false) + { + // We were unable to create the lock file - abort + $this->iohandler->add_error_message('UNABLE_TO_WRITE_LOCK'); + throw new user_interaction_required_exception(); + } + @fclose($fp); + + try + { + $this->filesystem->phpbb_chmod($this->phpbb_root_path . 'cache/install_lock', 0777); + } + catch (\phpbb\filesystem\exception\filesystem_exception $e) + { + // Do nothing, the user will get a notice later + } + } + + /** + * Returns the content which should be dumped to config.php + * + * @param bool $debug If the debug constants should be enabled by default or not + * @param bool $debug_container If the container should be compiled on + * every page load or not + * @param string $environment The environment to use + * + * @return string content to be written to the config file + */ + 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"; + + $dbms = $this->install_config->get('dbms'); + $db_driver = $this->db_helper->get_available_dbms($dbms); + $db_driver = $db_driver[$dbms]['DRIVER']; + + $config_data_array = array( + 'dbms' => $db_driver, + 'dbhost' => $this->install_config->get('dbhost'), + 'dbport' => $this->install_config->get('dbport'), + 'dbname' => $this->install_config->get('dbname'), + 'dbuser' => $this->install_config->get('dbuser'), + 'dbpasswd' => $this->install_config->get('dbpasswd'), + 'table_prefix' => $this->install_config->get('table_prefix'), + + 'phpbb_adm_relative_path' => 'adm/', + + 'acm_type' => 'phpbb\cache\driver\file', + ); + + foreach ($config_data_array as $key => $value) + { + $config_content .= "\${$key} = '" . str_replace("'", "\\'", str_replace('\\', '\\\\', $value)) . "';\n"; + } + + $config_content .= "\n@define('PHPBB_INSTALLED', true);\n"; + $config_content .= "// @define('PHPBB_DISPLAY_LOAD_TIME', true);\n"; + + if ($environment) + { + $config_content .= "@define('PHPBB_ENVIRONMENT', 'test');\n"; + } + else if ($debug) + { + $config_content .= "@define('PHPBB_ENVIRONMENT', 'development');\n"; + } + else + { + $config_content .= "@define('PHPBB_ENVIRONMENT', 'production');\n"; + } + + if ($debug_container) + { + $config_content .= "@define('DEBUG_CONTAINER', true);\n"; + } + else + { + $config_content .= "// @define('DEBUG_CONTAINER', true);\n"; + } + + if ($environment === 'test') + { + $config_content .= "@define('DEBUG_TEST', true);\n"; + + // Mandatory for the functional tests, will be removed by PHPBB3-12623 + $config_content .= "@define('DEBUG', true);\n"; + } + + return $config_content; + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_CREATE_CONFIG_FILE'; + } +} diff --git a/phpBB/phpbb/install/module/install_finish/module.php b/phpBB/phpbb/install/module/install_finish/module.php new file mode 100644 index 0000000000..3a7544b84f --- /dev/null +++ b/phpBB/phpbb/install/module/install_finish/module.php @@ -0,0 +1,28 @@ +<?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\install\module\install_finish; + +/** + * Installer module for filesystem installation + */ +class module extends \phpbb\install\module_base +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('install', 0, 'install'); + } +} diff --git a/phpBB/phpbb/install/module/install_finish/task/install_extensions.php b/phpBB/phpbb/install/module/install_finish/task/install_extensions.php new file mode 100644 index 0000000000..553a30ea28 --- /dev/null +++ b/phpBB/phpbb/install/module/install_finish/task/install_extensions.php @@ -0,0 +1,199 @@ +<?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\install\module\install_finish\task; + +use phpbb\install\exception\resource_limit_reached_exception; + +/** + * Installs extensions that exist in ext folder upon install + */ +class install_extensions extends \phpbb\install\task_base +{ + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var \phpbb\config\db + */ + protected $config; + + /** + * @var \phpbb\log\log_interface + */ + protected $log; + + /** + * @var \phpbb\user + */ + protected $user; + + /** @var \phpbb\extension\manager */ + protected $extension_manager; + + /** @var \Symfony\Component\Finder\Finder */ + protected $finder; + + /** @var string Extension table */ + protected $extension_table; + + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + /** + * Constructor + * + * @param \phpbb\install\helper\container_factory $container + * @param \phpbb\install\helper\config $install_config + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler + * @param string $phpbb_root_path phpBB root path + */ + public function __construct(\phpbb\install\helper\container_factory $container, \phpbb\install\helper\config $install_config, \phpbb\install\helper\iohandler\iohandler_interface $iohandler, $phpbb_root_path) + { + $this->install_config = $install_config; + $this->iohandler = $iohandler; + $this->extension_table = $container->get_parameter('tables.ext'); + + $this->log = $container->get('log'); + $this->user = $container->get('user'); + $this->extension_manager = $container->get('ext.manager'); + $this->config = $container->get('config'); + $this->db = $container->get('dbal.conn'); + $this->finder = new \Symfony\Component\Finder\Finder(); + $this->finder->in($phpbb_root_path . 'ext/') + ->ignoreUnreadableDirs() + ->depth('< 3') + ->files() + ->name('composer.json'); + + // Make sure asset version exists in config. Otherwise we might try to + // insert the assets_version setting into the database and cause a + // duplicate entry error. + if (!isset($this->config['assets_version'])) + { + $this->config['assets_version'] = 0; + } + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->user->session_begin(); + $this->user->setup(array('common', 'acp/common', 'cli')); + + $install_extensions = $this->iohandler->get_input('install-extensions', array()); + + $all_available_extensions = $this->extension_manager->all_available(); + $i = $this->install_config->get('install_extensions_index', 0); + $available_extensions = array_slice($all_available_extensions, $i); + + // Install extensions + foreach ($available_extensions as $ext_name => $ext_path) + { + if (!empty($install_extensions) && $install_extensions !== ['all'] && !in_array($ext_name, $install_extensions)) + { + continue; + } + + try + { + $this->extension_manager->enable($ext_name); + $extensions = $this->get_extensions(); + + if (isset($extensions[$ext_name]) && $extensions[$ext_name]['ext_active']) + { + // Create log + $this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_ENABLE', time(), array($ext_name)); + $this->iohandler->add_success_message(array('CLI_EXTENSION_ENABLE_SUCCESS', $ext_name)); + } + else + { + $this->iohandler->add_log_message(array('CLI_EXTENSION_ENABLE_FAILURE', $ext_name)); + } + } + catch (\Exception $e) + { + // Add fail log and continue + $this->iohandler->add_log_message(array('CLI_EXTENSION_ENABLE_FAILURE', $ext_name)); + } + + $i++; + + // Stop execution if resource limit is reached + if ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0) + { + break; + } + } + + $this->install_config->set('install_extensions_index', $i); + + if ($i < sizeof($all_available_extensions)) + { + throw new resource_limit_reached_exception(); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_INSTALL_EXTENSIONS'; + } + + /** + * Get extensions from database + * + * @return array List of extensions + */ + private function get_extensions() + { + $sql = 'SELECT * + FROM ' . $this->extension_table; + + $result = $this->db->sql_query($sql); + $extensions_row = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + $extensions = array(); + + foreach ($extensions_row as $extension) + { + $extensions[$extension['ext_name']] = $extension; + } + + ksort($extensions); + + return $extensions; + } +} diff --git a/phpBB/phpbb/install/module/install_finish/task/notify_user.php b/phpBB/phpbb/install/module/install_finish/task/notify_user.php new file mode 100644 index 0000000000..292be57f5f --- /dev/null +++ b/phpBB/phpbb/install/module/install_finish/task/notify_user.php @@ -0,0 +1,174 @@ +<?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\install\module\install_finish\task; + +use phpbb\config\db; + +/** + * Logs installation and sends an email to the admin + */ +class notify_user extends \phpbb\install\task_base +{ + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var \phpbb\auth\auth + */ + protected $auth; + + /** + * @var \phpbb\config\db + */ + protected $config; + + /** + * @var \phpbb\language\language + */ + protected $language; + + /** + * @var \phpbb\log\log_interface + */ + protected $log; + + /** + * @var \phpbb\user + */ + protected $user; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * Constructor + * + * @param \phpbb\install\helper\container_factory $container + * @param \phpbb\install\helper\config $install_config + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler + * @param string $phpbb_root_path + * @param string $php_ext + */ + public function __construct(\phpbb\install\helper\container_factory $container, \phpbb\install\helper\config $install_config, \phpbb\install\helper\iohandler\iohandler_interface $iohandler, $phpbb_root_path, $php_ext) + { + $this->install_config = $install_config; + $this->iohandler = $iohandler; + + $this->auth = $container->get('auth'); + $this->language = $container->get('language'); + $this->log = $container->get('log'); + $this->user = $container->get('user'); + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + + // We need to reload config for cases when it doesn't have all values + /** @var \phpbb\cache\driver\driver_interface $cache */ + $cache = $container->get('cache.driver'); + $cache->destroy('config'); + + $this->config = new db( + $container->get('dbal.conn'), + $cache, + $container->get_parameter('tables.config') + ); + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->user->session_begin(); + $this->user->setup('common'); + + if ($this->config['email_enable']) + { + include ($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext); + + // functions_messenger.php uses config to determine language paths + // Remove when able + global $config; + $config = $this->config; + + $messenger = new \messenger(false); + $messenger->template('installed', $this->install_config->get('user_language', 'en')); + $messenger->to($this->config['board_email'], $this->install_config->get('admin_name')); + $messenger->anti_abuse_headers($this->config, $this->user); + $messenger->assign_vars(array( + 'USERNAME' => htmlspecialchars_decode($this->install_config->get('admin_name')), + 'PASSWORD' => htmlspecialchars_decode($this->install_config->get('admin_passwd'))) + ); + $messenger->send(NOTIFY_EMAIL); + } + + // Login admin + // Ugly but works + $this->auth->login( + $this->install_config->get('admin_name'), + $this->install_config->get('admin_passwd'), + false, + true, + true + ); + + $this->iohandler->set_cookie($this->config['cookie_name'] . '_sid', $this->user->session_id); + $this->iohandler->set_cookie($this->config['cookie_name'] . '_u', $this->user->cookie_data['u']); + $this->iohandler->set_cookie($this->config['cookie_name'] . '_k', $this->user->cookie_data['k']); + + // Create log + $this->log->add( + 'admin', + $this->user->data['user_id'], + $this->user->ip, + 'LOG_INSTALL_INSTALLED', + false, + array($this->config['version']) + ); + + // Remove install_lock + @unlink($this->phpbb_root_path . 'cache/install_lock'); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_NOTIFY_USER'; + } +} diff --git a/phpBB/phpbb/install/module/install_finish/task/populate_migrations.php b/phpBB/phpbb/install/module/install_finish/task/populate_migrations.php new file mode 100644 index 0000000000..cebf0f425f --- /dev/null +++ b/phpBB/phpbb/install/module/install_finish/task/populate_migrations.php @@ -0,0 +1,93 @@ +<?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\install\module\install_finish\task; + +use phpbb\install\exception\resource_limit_reached_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\container_factory; + +/** + * Populates migrations + */ +class populate_migrations extends \phpbb\install\task_base +{ + /** + * @var config + */ + protected $config; + + /** + * @var \phpbb\extension\manager + */ + protected $extension_manager; + + /** + * @var \phpbb\db\migrator + */ + protected $migrator; + + /** + * Constructor + * + * @param config $config Installer's config + * @param container_factory $container phpBB's DI contianer + */ + public function __construct(config $config, container_factory $container) + { + $this->config = $config; + $this->extension_manager = $container->get('ext.manager'); + $this->migrator = $container->get('migrator'); + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!$this->config->get('populate_migration_refresh_before', false)) + { + if ($this->config->get_time_remaining() < 1) + { + $this->config->set('populate_migration_refresh_before', true); + throw new resource_limit_reached_exception(); + } + } + + $finder = $this->extension_manager->get_finder(); + + $migrations = $finder + ->core_path('phpbb/db/migration/data/') + ->set_extensions(array()) + ->get_classes(); + $this->migrator->populate_migrations($migrations); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_POPULATE_MIGRATIONS'; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/install_module.php b/phpBB/phpbb/install/module/obtain_data/install_module.php new file mode 100644 index 0000000000..deb4be90d8 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/install_module.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\install\module\obtain_data; + +class install_module extends \phpbb\install\module_base +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('install', 0, 'obtain_data'); + } + + /** + * {@inheritdoc} + */ + public function get_step_count() + { + return 0; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php new file mode 100644 index 0000000000..d1f1af6b83 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php @@ -0,0 +1,218 @@ +<?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\install\module\obtain_data\task; + +use phpbb\install\exception\user_interaction_required_exception; + +/** + * This class requests and validates admin account data from the user + */ +class obtain_admin_data extends \phpbb\install\task_base implements \phpbb\install\task_interface +{ + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $io_handler; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $install_config Installer's config helper + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler + */ + public function __construct(\phpbb\install\helper\config $install_config, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler) + { + $this->install_config = $install_config; + $this->io_handler = $iohandler; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Check if data is sent + if ($this->io_handler->get_input('submit_admin', false)) + { + $this->process_form(); + } + else + { + $this->request_form_data(); + } + } + + /** + * Process form data + */ + protected function process_form() + { + // Admin data + $admin_name = $this->io_handler->get_input('admin_name', '', true); + $admin_pass1 = $this->io_handler->get_input('admin_pass1', '', true); + $admin_pass2 = $this->io_handler->get_input('admin_pass2', '', true); + $board_email = $this->io_handler->get_input('board_email', '', true); + + $admin_data_valid = $this->check_admin_data($admin_name, $admin_pass1, $admin_pass2, $board_email); + + if ($admin_data_valid) + { + $this->install_config->set('admin_name', $admin_name); + $this->install_config->set('admin_passwd', $admin_pass1); + $this->install_config->set('board_email', $board_email); + } + else + { + $this->request_form_data(true); + } + } + + /** + * Request data from the user + * + * @param bool $use_request_data Whether to use submited data + * + * @throws \phpbb\install\exception\user_interaction_required_exception When the user is required to provide data + */ + protected function request_form_data($use_request_data = false) + { + if ($use_request_data) + { + $admin_username = $this->io_handler->get_input('admin_name', '', true); + $admin_email = $this->io_handler->get_input('board_email', '', true); + } + else + { + $admin_username = ''; + $admin_email = ''; + } + + $admin_form = array( + 'admin_name' => array( + 'label' => 'ADMIN_USERNAME', + 'description' => 'ADMIN_USERNAME_EXPLAIN', + 'type' => 'text', + 'default' => $admin_username, + ), + 'board_email' => array( + 'label' => 'CONTACT_EMAIL', + 'type' => 'email', + 'default' => $admin_email, + ), + 'admin_pass1' => array( + 'label' => 'ADMIN_PASSWORD', + 'description' => 'ADMIN_PASSWORD_EXPLAIN', + 'type' => 'password', + ), + 'admin_pass2' => array( + 'label' => 'ADMIN_PASSWORD_CONFIRM', + 'type' => 'password', + ), + 'submit_admin' => array( + 'label' => 'SUBMIT', + 'type' => 'submit', + ), + ); + + $this->io_handler->add_user_form_group('ADMIN_CONFIG', $admin_form); + + // Require user interaction + throw new user_interaction_required_exception(); + } + + /** + * Check admin data + * + * @param string $username Admin username + * @param string $pass1 Admin password + * @param string $pass2 Admin password confirmation + * @param string $email Admin e-mail address + * + * @return bool True if data is valid, false otherwise + */ + protected function check_admin_data($username, $pass1, $pass2, $email) + { + $data_valid = true; + + // Check if none of admin data is empty + if (in_array('', array($username, $pass1, $pass2, $email), true)) + { + $this->io_handler->add_error_message('INST_ERR_MISSING_DATA'); + $data_valid = false; + } + + if (utf8_strlen($username) < 3) + { + $this->io_handler->add_error_message('INST_ERR_USER_TOO_SHORT'); + $data_valid = false; + } + + if (utf8_strlen($username) > 20) + { + $this->io_handler->add_error_message('INST_ERR_USER_TOO_LONG'); + $data_valid = false; + } + + if ($pass1 !== $pass2 && $pass1 !== '') + { + $this->io_handler->add_error_message('INST_ERR_PASSWORD_MISMATCH'); + $data_valid = false; + } + + // Test against the default password rules + if (utf8_strlen($pass1) < 6) + { + $this->io_handler->add_error_message('INST_ERR_PASSWORD_TOO_SHORT'); + $data_valid = false; + } + + if (utf8_strlen($pass1) > 30) + { + $this->io_handler->add_error_message('INST_ERR_PASSWORD_TOO_LONG'); + $data_valid = false; + } + + if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email)) + { + $this->io_handler->add_error_message('INST_ERR_EMAIL_INVALID'); + $data_valid = false; + } + + return $data_valid; + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_board_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_board_data.php new file mode 100644 index 0000000000..ff2a0a2f86 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_board_data.php @@ -0,0 +1,185 @@ +<?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\install\module\obtain_data\task; + +use phpbb\install\exception\user_interaction_required_exception; + +/** + * This class obtains default data from the user related to board (Board name, Board descritpion, etc...) + */ +class obtain_board_data extends \phpbb\install\task_base implements \phpbb\install\task_interface +{ + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $io_handler; + + /** + * @var \phpbb\language\language_file_helper + */ + protected $language_helper; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $config Installer's config + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler + * @param \phpbb\language\language_file_helper $lang_helper Language file helper + */ + public function __construct(\phpbb\install\helper\config $config, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler, + \phpbb\language\language_file_helper $lang_helper) + { + $this->install_config = $config; + $this->io_handler = $iohandler; + $this->language_helper = $lang_helper; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Check if data is sent + if ($this->io_handler->get_input('submit_board', false)) + { + $this->process_form(); + } + else + { + $this->request_form_data(); + } + } + + /** + * Process form data + */ + protected function process_form() + { + // Board data + $default_lang = $this->io_handler->get_input('default_lang', ''); + $board_name = $this->io_handler->get_input('board_name', '', true); + $board_desc = $this->io_handler->get_input('board_description', '', true); + + // Check default lang + $langs = $this->language_helper->get_available_languages(); + $lang_valid = false; + + foreach ($langs as $lang) + { + if ($lang['iso'] === $default_lang) + { + $lang_valid = true; + break; + } + } + + $this->install_config->set('board_name', $board_name); + $this->install_config->set('board_description', $board_desc); + + if ($lang_valid) + { + $this->install_config->set('default_lang', $default_lang); + } + else + { + $this->request_form_data(true); + } + } + + /** + * Request data from the user + * + * @param bool $use_request_data Whether to use submited data + * + * @throws \phpbb\install\exception\user_interaction_required_exception When the user is required to provide data + */ + protected function request_form_data($use_request_data = false) + { + if ($use_request_data) + { + $board_name = $this->io_handler->get_input('board_name', '', true); + $board_desc = $this->io_handler->get_input('board_description', '', true); + } + else + { + $board_name = '{L_CONFIG_SITENAME}'; + $board_desc = '{L_CONFIG_SITE_DESC}'; + } + + // Use language because we only check this to be valid + $default_lang = $this->install_config->get('user_language', 'en'); + + $langs = $this->language_helper->get_available_languages(); + $lang_options = array(); + + foreach ($langs as $lang) + { + $lang_options[] = array( + 'value' => $lang['iso'], + 'label' => $lang['local_name'], + 'selected' => ($default_lang === $lang['iso']), + ); + } + + $board_form = array( + 'default_lang' => array( + 'label' => 'DEFAULT_LANGUAGE', + 'type' => 'select', + 'options' => $lang_options, + ), + 'board_name' => array( + 'label' => 'BOARD_NAME', + 'type' => 'text', + 'default' => $board_name, + ), + 'board_description' => array( + 'label' => 'BOARD_DESCRIPTION', + 'type' => 'text', + 'default' => $board_desc, + ), + 'submit_board' => array( + 'label' => 'SUBMIT', + 'type' => 'submit', + ), + ); + + $this->io_handler->add_user_form_group('BOARD_CONFIG', $board_form); + + throw new user_interaction_required_exception(); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_database_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_database_data.php new file mode 100644 index 0000000000..dc7b060746 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_database_data.php @@ -0,0 +1,270 @@ +<?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\install\module\obtain_data\task; + +use phpbb\install\exception\user_interaction_required_exception; + +/** + * This class requests and validates database information from the user + */ +class obtain_database_data extends \phpbb\install\task_base implements \phpbb\install\task_interface +{ + /** + * @var \phpbb\install\helper\database + */ + protected $database_helper; + + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $io_handler; + + /** + * Constructor + * + * @param \phpbb\install\helper\database $database_helper Installer's database helper + * @param \phpbb\install\helper\config $install_config Installer's config helper + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler + */ + public function __construct(\phpbb\install\helper\database $database_helper, + \phpbb\install\helper\config $install_config, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler) + { + $this->database_helper = $database_helper; + $this->install_config = $install_config; + $this->io_handler = $iohandler; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Check if data is sent + if ($this->io_handler->get_input('submit_database', false)) + { + $this->process_form(); + } + else + { + $this->request_form_data(); + } + } + + /** + * Process form data + */ + protected function process_form() + { + // Collect database data + $dbms = $this->io_handler->get_input('dbms', ''); + $dbhost = $this->io_handler->get_input('dbhost', '', true); + $dbport = $this->io_handler->get_input('dbport', ''); + $dbuser = $this->io_handler->get_input('dbuser', ''); + $dbpasswd = $this->io_handler->get_raw_input('dbpasswd', ''); + $dbname = $this->io_handler->get_input('dbname', ''); + $table_prefix = $this->io_handler->get_input('table_prefix', ''); + + // Check database data + $user_data_vaild = $this->check_database_data($dbms, $dbhost, $dbport, $dbuser, $dbpasswd, $dbname, $table_prefix); + + // Save database data if it is correct + if ($user_data_vaild) + { + $this->install_config->set('dbms', $dbms); + $this->install_config->set('dbhost', $dbhost); + $this->install_config->set('dbport', $dbport); + $this->install_config->set('dbuser', $dbuser); + $this->install_config->set('dbpasswd', $dbpasswd); + $this->install_config->set('dbname', $dbname); + $this->install_config->set('table_prefix', $table_prefix); + } + else + { + $this->request_form_data(true); + } + } + + /** + * Request data from the user + * + * @param bool $use_request_data Whether to use submited data + * + * @throws \phpbb\install\exception\user_interaction_required_exception When the user is required to provide data + */ + protected function request_form_data($use_request_data = false) + { + if ($use_request_data) + { + $dbms = $this->io_handler->get_input('dbms', ''); + $dbhost = $this->io_handler->get_input('dbhost', '', true); + $dbport = $this->io_handler->get_input('dbport', ''); + $dbuser = $this->io_handler->get_input('dbuser', ''); + $dbname = $this->io_handler->get_input('dbname', ''); + $table_prefix = $this->io_handler->get_input('table_prefix', 'phpbb_'); + } + else + { + $dbms = ''; + $dbhost = ''; + $dbport = ''; + $dbuser = ''; + $dbname = ''; + $table_prefix = 'phpbb_'; + } + + $dbms_select = array(); + foreach ($this->database_helper->get_available_dbms() as $dbms_key => $dbms_array) + { + $dbms_select[] = array( + 'value' => $dbms_key, + 'label' => 'DB_OPTION_' . strtoupper($dbms_key), + 'selected' => ($dbms_key === $dbms), + ); + } + + $database_form = array( + 'dbms' => array( + 'label' => 'DBMS', + 'type' => 'select', + 'options' => $dbms_select, + ), + 'dbhost' => array( + 'label' => 'DB_HOST', + 'description' => 'DB_HOST_EXPLAIN', + 'type' => 'text', + 'default' => $dbhost, + ), + 'dbport' => array( + 'label' => 'DB_PORT', + 'description' => 'DB_PORT_EXPLAIN', + 'type' => 'text', + 'default' => $dbport, + ), + 'dbuser' => array( + 'label' => 'DB_USERNAME', + 'type' => 'text', + 'default' => $dbuser, + ), + 'dbpasswd' => array( + 'label' => 'DB_PASSWORD', + 'type' => 'password', + ), + 'dbname' => array( + 'label' => 'DB_NAME', + 'type' => 'text', + 'default' => $dbname, + ), + 'table_prefix' => array( + 'label' => 'TABLE_PREFIX', + 'description' => 'TABLE_PREFIX_EXPLAIN', + 'type' => 'text', + 'default' => $table_prefix, + ), + 'submit_database' => array( + 'label' => 'SUBMIT', + 'type' => 'submit', + ), + ); + + $this->io_handler->add_user_form_group('DB_CONFIG', $database_form); + + // Require user interaction + throw new user_interaction_required_exception(); + } + + /** + * Check database data + * + * @param string $dbms Selected database type + * @param string $dbhost Database host address + * @param int $dbport Database port number + * @param string $dbuser Database username + * @param string $dbpass Database password + * @param string $dbname Database name + * @param string $table_prefix Database table prefix + * + * @return bool True if database data is correct, false otherwise + */ + protected function check_database_data($dbms, $dbhost, $dbport, $dbuser, $dbpass, $dbname, $table_prefix) + { + $available_dbms = $this->database_helper->get_available_dbms(); + $data_valid = true; + + // Check if PHP has the database extensions for the specified DBMS + if (!isset($available_dbms[$dbms])) + { + $this->io_handler->add_error_message('INST_ERR_NO_DB'); + $data_valid = false; + } + + // Validate table prefix + $prefix_valid = $this->database_helper->validate_table_prefix($dbms, $table_prefix); + if (is_array($prefix_valid)) + { + foreach ($prefix_valid as $error) + { + $this->io_handler->add_error_message( + $error['title'], + (isset($error['description'])) ? $error['description'] : false + ); + } + + $data_valid = false; + } + + // Try to connect to database if all provided data is valid + if ($data_valid) + { + $connect_test = $this->database_helper->check_database_connection($dbms, $dbhost, $dbport, $dbuser, $dbpass, $dbname, $table_prefix); + if (is_array($connect_test)) + { + foreach ($connect_test as $error) + { + $this->io_handler->add_error_message( + $error['title'], + (isset($error['description'])) ? $error['description'] : false + ); + } + + $data_valid = false; + } + } + + return $data_valid; + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php new file mode 100644 index 0000000000..e8a9c971b7 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php @@ -0,0 +1,173 @@ +<?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\install\module\obtain_data\task; + +use phpbb\install\exception\user_interaction_required_exception; + +class obtain_email_data extends \phpbb\install\task_base implements \phpbb\install\task_interface +{ + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $io_handler; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $config Installer's config + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler + */ + public function __construct(\phpbb\install\helper\config $config, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler) + { + $this->install_config = $config; + $this->io_handler = $iohandler; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // E-mail data + $email_enable = $this->io_handler->get_input('email_enable', true); + $smtp_delivery = $this->io_handler->get_input('smtp_delivery', ''); + $smtp_host = $this->io_handler->get_input('smtp_host', ''); + $smtp_port = $this->io_handler->get_input('smtp_port', ''); + $smtp_auth = $this->io_handler->get_input('smtp_auth', ''); + $smtp_user = $this->io_handler->get_input('smtp_user', ''); + $smtp_passwd = $this->io_handler->get_input('smtp_pass', ''); + + $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5', 'POP-BEFORE-SMTP'); + + // Check if data is sent + if ($this->io_handler->get_input('submit_email', false)) + { + $this->install_config->set('email_enable', $email_enable); + $this->install_config->set('smtp_delivery', $smtp_delivery); + $this->install_config->set('smtp_host', $smtp_host); + $this->install_config->set('smtp_port', $smtp_port); + $this->install_config->set('smtp_auth', $smtp_auth); + $this->install_config->set('smtp_user', $smtp_user); + $this->install_config->set('smtp_pass', $smtp_passwd); + } + else + { + $auth_options = array(); + foreach ($auth_methods as $method) + { + $auth_options[] = array( + 'value' => $method, + 'label' => 'SMTP_' . str_replace('-', '_', $method), + 'selected' => false, + ); + } + + $email_form = array( + 'email_enable' => array( + 'label' => 'ENABLE_EMAIL', + 'description' => 'ENABLE_EMAIL_EXPLAIN', + 'type' => 'radio', + 'options' => array( + array( + 'value' => 1, + 'label' => 'ENABLE', + 'selected' => true, + ), + array( + 'value' => 0, + 'label' => 'DISABLE', + 'selected' => false, + ), + ), + ), + 'smtp_delivery' => array( + 'label' => 'USE_SMTP', + 'description' => 'USE_SMTP_EXPLAIN', + 'type' => 'radio', + 'options' => array( + array( + 'value' => 0, + 'label' => 'NO', + 'selected' => true, + ), + array( + 'value' => 1, + 'label' => 'YES', + 'selected' => false, + ), + ), + ), + 'smtp_host' => array( + 'label' => 'SMTP_SERVER', + 'type' => 'text', + 'default' => $smtp_host, + ), + 'smtp_port' => array( + 'label' => 'SMTP_PORT', + 'type' => 'text', + 'default' => $smtp_port, + ), + 'smtp_auth' => array( + 'label' => 'SMTP_AUTH_METHOD', + 'description' => 'SMTP_AUTH_METHOD_EXPLAIN', + 'type' => 'select', + 'options' => $auth_options, + ), + 'smtp_user' => array( + 'label' => 'SMTP_USERNAME', + 'description' => 'SMTP_USERNAME_EXPLAIN', + 'type' => 'text', + 'default' => $smtp_user, + ), + 'smtp_pass' => array( + 'label' => 'SMTP_PASSWORD', + 'description' => 'SMTP_PASSWORD_EXPLAIN', + 'type' => 'password', + ), + 'submit_email' => array( + 'label' => 'SUBMIT', + 'type' => 'submit', + ), + ); + + $this->io_handler->add_user_form_group('EMAIL_CONFIG', $email_form); + + throw new user_interaction_required_exception(); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_file_updater_method.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_file_updater_method.php new file mode 100644 index 0000000000..d5a8855c37 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_file_updater_method.php @@ -0,0 +1,167 @@ +<?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\install\module\obtain_data\task; + +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\task_base; + +class obtain_file_updater_method extends task_base +{ + /** + * @var array Supported compression methods + * + * Note: .tar is assumed to be supported, but not in the list + */ + protected $available_methods; + + /** + * @var \phpbb\install\helper\config + */ + protected $installer_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * Constructor + * + * @param config $installer_config + * @param iohandler_interface $iohandler + */ + public function __construct(config $installer_config, iohandler_interface $iohandler) + { + $this->installer_config = $installer_config; + $this->iohandler = $iohandler; + + $this->available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib'); + + parent::__construct(false); + } + + /** + * {@inheritdoc} + */ + public function check_requirements() + { + return $this->installer_config->get('do_update_files', false); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Check if data is sent + if ($this->iohandler->get_input('submit_update_file', false)) + { + $supported_methods = array('compression', 'ftp', 'direct_file'); + $method = $this->iohandler->get_input('method', 'compression'); + $update_method = (in_array($method, $supported_methods, true)) ? $method : 'compression'; + $this->installer_config->set('file_update_method', $update_method); + + $compression = $this->iohandler->get_input('compression_method', '.zip'); + $supported_methods = array_keys($this->available_methods); + $supported_methods[] = '.tar'; + $compression = (in_array($compression, $supported_methods, true)) ? $compression : '.zip'; + $this->installer_config->set('file_update_compression', $compression); + } + else + { + $this->iohandler->add_user_form_group('UPDATE_FILE_METHOD_TITLE', array( + 'method' => array( + 'label' => 'UPDATE_FILE_METHOD', + 'type' => 'select', + 'options' => array( + array( + 'value' => 'compression', + 'label' => 'UPDATE_FILE_METHOD_DOWNLOAD', + 'selected' => true, + ), + array( + 'value' => 'ftp', + 'label' => 'UPDATE_FILE_METHOD_FTP', + 'selected' => false, + ), + array( + 'value' => 'direct_file', + 'label' => 'UPDATE_FILE_METHOD_FILESYSTEM', + 'selected' => false, + ), + ), + ), + 'compression_method' => array( + 'label' => 'SELECT_DOWNLOAD_FORMAT', + 'type' => 'select', + 'options' => $this->get_available_compression_methods(), + ), + 'submit_update_file' => array( + 'label' => 'SUBMIT', + 'type' => 'submit', + ), + )); + + throw new user_interaction_required_exception(); + } + } + + /** + * Returns form elements in an array of available compression methods + * + * @return array + */ + protected function get_available_compression_methods() + { + $methods[] = array( + 'value' => '.tar', + 'label' => '.tar', + 'selected' => true, + ); + + foreach ($this->available_methods as $type => $module) + { + if (!@extension_loaded($module)) + { + continue; + } + + $methods[] = array( + 'value' => $type, + 'label' => $type, + 'selected' => false, + ); + } + + return $methods; + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_imagick_path.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_imagick_path.php new file mode 100644 index 0000000000..377d96ed1a --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_imagick_path.php @@ -0,0 +1,89 @@ +<?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\install\module\obtain_data\task; + +class obtain_imagick_path extends \phpbb\install\task_base implements \phpbb\install\task_interface +{ + /** + * @var \phpbb\install\helper\config + */ + protected $config; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $config Installer's config + */ + public function __construct(\phpbb\install\helper\config $config) + { + $this->config = $config; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Can we find ImageMagick anywhere on the system? + $exe = (DIRECTORY_SEPARATOR == '\\') ? '.exe' : ''; + + $magic_home = getenv('MAGICK_HOME'); + $img_imagick = ''; + if (empty($magic_home)) + { + $locations = array('C:/WINDOWS/', 'C:/WINNT/', 'C:/WINDOWS/SYSTEM/', 'C:/WINNT/SYSTEM/', 'C:/WINDOWS/SYSTEM32/', 'C:/WINNT/SYSTEM32/', '/usr/bin/', '/usr/sbin/', '/usr/local/bin/', '/usr/local/sbin/', '/opt/', '/usr/imagemagick/', '/usr/bin/imagemagick/'); + $path_locations = str_replace('\\', '/', (explode(($exe) ? ';' : ':', getenv('PATH')))); + + $locations = array_merge($path_locations, $locations); + foreach ($locations as $location) + { + // The path might not end properly, fudge it + if (substr($location, -1, 1) !== '/') + { + $location .= '/'; + } + + if (@file_exists($location) && @is_readable($location . 'mogrify' . $exe) && @filesize($location . 'mogrify' . $exe) > 3000) + { + $img_imagick = str_replace('\\', '/', $location); + continue; + } + } + } + else + { + $img_imagick = str_replace('\\', '/', $magic_home); + } + + $this->config->set('img_imagick', $img_imagick); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_server_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_server_data.php new file mode 100644 index 0000000000..1ef70eae08 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_server_data.php @@ -0,0 +1,202 @@ +<?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\install\module\obtain_data\task; + +use phpbb\install\exception\user_interaction_required_exception; + +/** + * This class requests and saves some information about the server + */ +class obtain_server_data extends \phpbb\install\task_base implements \phpbb\install\task_interface +{ + /** + * @var \phpbb\install\helper\config + */ + protected $install_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $io_handler; + + /** + * Constructor + * + * @param \phpbb\install\helper\config $config Installer's config + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler + */ + public function __construct(\phpbb\install\helper\config $config, + \phpbb\install\helper\iohandler\iohandler_interface $iohandler) + { + $this->install_config = $config; + $this->io_handler = $iohandler; + + parent::__construct(true); + } + /** + * {@inheritdoc} + */ + public function run() + { + $cookie_secure = $this->io_handler->is_secure(); + $server_protocol = ($this->io_handler->is_secure()) ? 'https://' : 'http://'; + $server_port = $this->io_handler->get_server_variable('SERVER_PORT', 0); + + // HTTP_HOST is having the correct browser url in most cases... + $server_name = strtolower(htmlspecialchars_decode($this->io_handler->get_header_variable( + 'Host', + $this->io_handler->get_server_variable('SERVER_NAME') + ))); + + // HTTP HOST can carry a port number... + if (strpos($server_name, ':') !== false) + { + $server_name = substr($server_name, 0, strpos($server_name, ':')); + } + + $script_path = htmlspecialchars_decode($this->io_handler->get_server_variable('PHP_SELF')); + + if (!$script_path) + { + $script_path = htmlspecialchars_decode($this->io_handler->get_server_variable('REQUEST_URI')); + } + + $script_path = str_replace(array('\\', '//'), '/', $script_path); + $script_path = trim(dirname(dirname(dirname($script_path)))); // Because we are in install/app.php/route_name + + // Server data + $cookie_secure = $this->io_handler->get_input('cookie_secure', $cookie_secure); + $server_protocol = $this->io_handler->get_input('server_protocol', $server_protocol); + $force_server_vars = $this->io_handler->get_input('force_server_vars', 0); + $server_name = $this->io_handler->get_input('server_name', $server_name); + $server_port = $this->io_handler->get_input('server_port', $server_port); + $script_path = $this->io_handler->get_input('script_path', $script_path); + + // Clean up script path + if ($script_path !== '/') + { + // Adjust destination path (no trailing slash) + if (substr($script_path, -1) === '/') + { + $script_path = substr($script_path, 0, -1); + } + + $script_path = str_replace(array('../', './'), '', $script_path); + + if ($script_path[0] !== '/') + { + $script_path = '/' . $script_path; + } + } + + // Check if data is sent + if ($this->io_handler->get_input('submit_server', false)) + { + $this->install_config->set('cookie_secure', $cookie_secure); + $this->install_config->set('server_protocol', $server_protocol); + $this->install_config->set('force_server_vars', $force_server_vars); + $this->install_config->set('server_name', $server_name); + $this->install_config->set('server_port', $server_port); + $this->install_config->set('script_path', $script_path); + } + else + { + // Render form + $server_form = array( + 'cookie_secure' => array( + 'label' => 'COOKIE_SECURE', + 'description' => 'COOKIE_SECURE_EXPLAIN', + 'type' => 'radio', + 'options' => array( + array( + 'value' => 0, + 'label' => 'NO', + 'selected' => (!$cookie_secure), + ), + array( + 'value' => 1, + 'label' => 'YES', + 'selected' => ($cookie_secure), + ), + ), + ), + 'force_server_vars' => array( + 'label' => 'FORCE_SERVER_VARS', + 'description' => 'FORCE_SERVER_VARS_EXPLAIN', + 'type' => 'radio', + 'options' => array( + array( + 'value' => 0, + 'label' => 'NO', + 'selected' => true, + ), + array( + 'value' => 1, + 'label' => 'YES', + 'selected' => false, + ), + ), + ), + 'server_protocol' => array( + 'label' => 'SERVER_PROTOCOL', + 'description' => 'SERVER_PROTOCOL_EXPLAIN', + 'type' => 'text', + 'default' => $server_protocol, + ), + 'server_name' => array( + 'label' => 'SERVER_NAME', + 'description' => 'SERVER_NAME_EXPLAIN', + 'type' => 'text', + 'default' => $server_name, + ), + 'server_port' => array( + 'label' => 'SERVER_PORT', + 'description' => 'SERVER_PORT_EXPLAIN', + 'type' => 'text', + 'default' => $server_port, + ), + 'script_path' => array( + 'label' => 'SCRIPT_PATH', + 'description' => 'SCRIPT_PATH_EXPLAIN', + 'type' => 'text', + 'default' => $script_path, + ), + 'submit_server' => array( + 'label' => 'SUBMIT', + 'type' => 'submit', + ) + ); + + $this->io_handler->add_user_form_group('SERVER_CONFIG', $server_form); + + throw new user_interaction_required_exception(); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_update_files.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_files.php new file mode 100644 index 0000000000..0cb809154e --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_files.php @@ -0,0 +1,113 @@ +<?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\install\module\obtain_data\task; + +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\task_base; + +class obtain_update_files extends task_base +{ + /** + * @var config + */ + protected $installer_config; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * Constructor + * + * @param config $config + * @param iohandler_interface $iohandler + * @param string $phpbb_root_path + * @param string $php_ext + */ + public function __construct(config $config, iohandler_interface $iohandler, $phpbb_root_path, $php_ext) + { + $this->installer_config = $config; + $this->iohandler = $iohandler; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + + parent::__construct(false); + } + + /** + * {@inheritdoc} + */ + public function check_requirements() + { + return $this->installer_config->get('do_update_files', false); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Load update info file + // The file should be checked in the requirements, so we assume that it exists + $update_info_file = $this->phpbb_root_path . 'install/update/index.' . $this->php_ext; + include($update_info_file); + $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info; + + // If the file is invalid, abort mission + if (!$info) + { + $this->iohandler->add_error_message('WRONG_INFO_FILE_FORMAT'); + throw new user_interaction_required_exception(); + } + + // Replace .php with $this->php_ext if needed + if ($this->php_ext !== 'php') + { + $custom_extension = '.' . $this->php_ext; + $info['files'] = preg_replace('#\.php$#i', $custom_extension, $info['files']); + } + + // Save update info + $this->installer_config->set('update_info_unprocessed', $info); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_update_ftp_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_ftp_data.php new file mode 100644 index 0000000000..f31472fc58 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_ftp_data.php @@ -0,0 +1,163 @@ +<?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\install\module\obtain_data\task; + +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\helper\update_helper; +use phpbb\install\task_base; + +class obtain_update_ftp_data extends task_base +{ + /** + * @var \phpbb\install\helper\config + */ + protected $installer_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var update_helper + */ + protected $update_helper; + + /** + * @var string + */ + protected $php_ext; + + /** + * Constructor + * + * @param config $installer_config + * @param iohandler_interface $iohandler + * @param update_helper $update_helper + * @param string $php_ext + */ + public function __construct(config $installer_config, iohandler_interface $iohandler, update_helper $update_helper, $php_ext) + { + $this->installer_config = $installer_config; + $this->iohandler = $iohandler; + $this->update_helper = $update_helper; + $this->php_ext = $php_ext; + + parent::__construct(false); + } + + /** + * {@inheritdoc} + */ + public function check_requirements() + { + return ($this->installer_config->get('do_update_files', false) && + ($this->installer_config->get('file_update_method', '') === 'ftp') + ); + } + + /** + * {@inheritdoc} + */ + public function run() + { + if ($this->iohandler->get_input('submit_ftp', false)) + { + $this->update_helper->include_file('includes/functions_transfer.' . $this->php_ext); + + $method = 'ftp'; + $methods = \transfer::methods(); + if (!in_array($method, $methods, true)) + { + $method = $methods[0]; + } + + $ftp_host = $this->iohandler->get_input('ftp_host', ''); + $ftp_user = $this->iohandler->get_input('ftp_user', ''); + $ftp_pass = htmlspecialchars_decode($this->iohandler->get_input('ftp_pass', '')); + $ftp_path = $this->iohandler->get_input('ftp_path', ''); + $ftp_port = $this->iohandler->get_input('ftp_port', 21); + $ftp_time = $this->iohandler->get_input('ftp_timeout', 10); + + $this->installer_config->set('ftp_host', $ftp_host); + $this->installer_config->set('ftp_user', $ftp_user); + $this->installer_config->set('ftp_pass', $ftp_pass); + $this->installer_config->set('ftp_path', $ftp_path); + $this->installer_config->set('ftp_port', (int) $ftp_port); + $this->installer_config->set('ftp_timeout', (int) $ftp_time); + $this->installer_config->set('ftp_method', $method); + } + else + { + $this->iohandler->add_user_form_group('FTP_SETTINGS', array( + 'ftp_host' => array( + 'label' => 'FTP_HOST', + 'description' => 'FTP_HOST_EXPLAIN', + 'type' => 'text', + ), + 'ftp_user' => array( + 'label' => 'FTP_USERNAME', + 'description' => 'FTP_USERNAME_EXPLAIN', + 'type' => 'text', + ), + 'ftp_pass' => array( + 'label' => 'FTP_PASSWORD', + 'description' => 'FTP_PASSWORD_EXPLAIN', + 'type' => 'password', + ), + 'ftp_path' => array( + 'label' => 'FTP_ROOT_PATH', + 'description' => 'FTP_ROOT_PATH_EXPLAIN', + 'type' => 'text', + ), + 'ftp_port' => array( + 'label' => 'FTP_PORT', + 'description' => 'FTP_PORT_EXPLAIN', + 'type' => 'text', + 'default' => 21, + ), + 'ftp_timeout' => array( + 'label' => 'FTP_TIMEOUT', + 'description' => 'FTP_TIMEOUT_EXPLAIN', + 'type' => 'text', + 'default' => 10, + ), + 'submit_ftp' => array( + 'label' => 'SUBMIT', + 'type' => 'submit', + ), + )); + + throw new user_interaction_required_exception(); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_update_settings.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_settings.php new file mode 100644 index 0000000000..3b24e8ba40 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_settings.php @@ -0,0 +1,123 @@ +<?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\install\module\obtain_data\task; + +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\task_base; + +class obtain_update_settings extends task_base +{ + /** + * @var \phpbb\install\helper\config + */ + protected $installer_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * Constructor + * + * @param config $installer_config + * @param iohandler_interface $iohandler + */ + public function __construct(config $installer_config, iohandler_interface $iohandler) + { + $this->installer_config = $installer_config; + $this->iohandler = $iohandler; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Check if data is sent + if ($this->iohandler->get_input('submit_update', false)) + { + $update_files = $this->iohandler->get_input('update_type', 'all') === 'all'; + + if ($this->installer_config->get('disable_filesystem_update', false) && $update_files) + { + $this->iohandler->add_error_message('UPDATE_FILES_NOT_FOUND'); + + throw new user_interaction_required_exception(); + } + + $this->installer_config->set('do_update_files', $update_files); + } + else + { + if ($this->installer_config->get('disable_filesystem_update', false)) + { + $options[] = array( + 'value' => 'db_only', + 'label' => 'UPDATE_TYPE_DB_ONLY', + 'selected' => true, + ); + } + else + { + $options = array( + array( + 'value' => 'all', + 'label' => 'UPDATE_TYPE_ALL', + 'selected' => true, + ), + array( + 'value' => 'db_only', + 'label' => 'UPDATE_TYPE_DB_ONLY', + 'selected' => false, + ), + ); + } + + $this->iohandler->add_user_form_group('UPDATE_TYPE', array( + 'update_type' => array( + 'label' => 'UPDATE_TYPE', + 'type' => 'radio', + 'options' => $options, + ), + 'submit_update' => array( + 'label' => 'SUBMIT', + 'type' => 'submit', + ), + )); + + throw new user_interaction_required_exception(); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/obtain_data/update_module.php b/phpBB/phpbb/install/module/obtain_data/update_module.php new file mode 100644 index 0000000000..c2f9019d34 --- /dev/null +++ b/phpBB/phpbb/install/module/obtain_data/update_module.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\install\module\obtain_data; + +class update_module extends \phpbb\install\module_base +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('update', 0, 'obtain_data'); + } + + /** + * {@inheritdoc} + */ + public function get_step_count() + { + return 0; + } +} diff --git a/phpBB/phpbb/install/module/requirements/abstract_requirements_module.php b/phpBB/phpbb/install/module/requirements/abstract_requirements_module.php new file mode 100644 index 0000000000..121b4ff4e5 --- /dev/null +++ b/phpBB/phpbb/install/module/requirements/abstract_requirements_module.php @@ -0,0 +1,71 @@ +<?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\install\module\requirements; + +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\module_base; + +/** + * Base class for requirements installer module + */ +abstract class abstract_requirements_module extends module_base +{ + public function run() + { + $tests_passed = true; + foreach ($this->task_collection as $name => $task) + { + // Check if we can run the task + if (!$task->is_essential() && !$task->check_requirements()) + { + continue; + } + + if ($this->allow_progress_bar) + { + $this->install_config->increment_current_task_progress(); + } + + $test_result = $task->run(); + $tests_passed = ($tests_passed) ? $test_result : false; + } + + // Module finished, so clear task progress + $this->install_config->set_finished_task(0); + + // Check if tests have failed + if (!$tests_passed) + { + // If requirements are not met, exit form installer + // Set up UI for retesting + $this->iohandler->add_user_form_group('', array( + 'install' => array( + 'label' => 'RETEST_REQUIREMENTS', + 'type' => 'submit', + ), + )); + + // Send the response and quit + throw new user_interaction_required_exception(); + } + } + + /** + * {@inheritdoc} + */ + public function get_step_count() + { + return 0; + } +} diff --git a/phpBB/phpbb/install/module/requirements/install_module.php b/phpBB/phpbb/install/module/requirements/install_module.php new file mode 100644 index 0000000000..ed0c5fbd94 --- /dev/null +++ b/phpBB/phpbb/install/module/requirements/install_module.php @@ -0,0 +1,25 @@ +<?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\install\module\requirements; + +class install_module extends abstract_requirements_module +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('install', 0, 'requirements'); + } +} diff --git a/phpBB/phpbb/install/module/requirements/task/check_filesystem.php b/phpBB/phpbb/install/module/requirements/task/check_filesystem.php new file mode 100644 index 0000000000..868af39433 --- /dev/null +++ b/phpBB/phpbb/install/module/requirements/task/check_filesystem.php @@ -0,0 +1,279 @@ +<?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\install\module\requirements\task; + +/** + * Checks filesystem requirements + */ +class check_filesystem extends \phpbb\install\task_base +{ + /** + * @var \phpbb\filesystem\filesystem_interface + */ + protected $filesystem; + + /** + * @var array + */ + protected $files_to_check; + + /** + * @var bool + */ + protected $tests_passed; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $response; + + /** + * Constructor + * + * @param \phpbb\filesystem\filesystem_interface $filesystem filesystem handler + * @param \phpbb\install\helper\iohandler\iohandler_interface $response response helper + * @param string $phpbb_root_path relative path to phpBB's root + * @param string $php_ext extension of php files + * @param bool $check_config_php Whether or not to check if config.php is writable + */ + public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, \phpbb\install\helper\iohandler\iohandler_interface $response, $phpbb_root_path, $php_ext, $check_config_php = true) + { + parent::__construct(true); + + $this->filesystem = $filesystem; + $this->response = $response; + $this->phpbb_root_path = $phpbb_root_path; + + $this->tests_passed = false; + + // Files/Directories to check + // All file/directory names must be relative to phpBB's root path + $this->files_to_check = array( + array( + 'path' => 'cache/', + 'failable' => false, + 'is_file' => false, + ), + array( + 'path' => 'store/', + 'failable' => false, + 'is_file' => false, + ), + array( + 'path' => 'files/', + 'failable' => false, + 'is_file' => false, + ), + array( + 'path' => 'images/avatars/upload/', + 'failable' => true, + 'is_file' => false, + ), + ); + + if ($check_config_php) + { + $this->files_to_check[] = array( + 'path' => "config.$php_ext", + 'failable' => false, + 'is_file' => true, + ); + } + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->tests_passed = true; + + // Check files/directories to be writable + foreach ($this->files_to_check as $file) + { + if ($file['is_file']) + { + $this->check_file($file['path'], $file['failable']); + } + else + { + $this->check_dir($file['path'], $file['failable']); + } + } + + return $this->tests_passed; + } + + /** + * Sets $this->tests_passed + * + * @param bool $is_passed + */ + protected function set_test_passed($is_passed) + { + // If one test failed, tests_passed should be false + $this->tests_passed = (!$this->tests_passed) ? false : $is_passed; + } + + /** + * Check if a file is readable and writable + * + * @param string $file Filename + * @param bool $failable Whether failing test should interrupt installation process + */ + protected function check_file($file, $failable = false) + { + $path = $this->phpbb_root_path . $file; + $exists = $writable = true; + + // Try to create file if it does not exists + if (!file_exists($path)) + { + $fp = @fopen($path, 'w'); + @fclose($fp); + try + { + $this->filesystem->phpbb_chmod($path, + \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE + ); + $exists = true; + } + catch (\phpbb\filesystem\exception\filesystem_exception $e) + { + // Do nothing + } + } + + if (file_exists($path)) + { + if (!$this->filesystem->is_writable($path)) + { + $writable = false; + } + } + else + { + $exists = $writable = false; + } + + $this->set_test_passed(($exists && $writable) || $failable); + + if (!($exists && $writable)) + { + $title = ($exists) ? 'FILE_NOT_WRITABLE' : 'FILE_NOT_EXISTS'; + $lang_suffix = '_EXPLAIN'; + $lang_suffix .= ($failable) ? '_OPTIONAL' : ''; + $description = array($title . $lang_suffix, $file); + + if ($failable) + { + $this->response->add_warning_message($title, $description); + } + else + { + $this->response->add_error_message($title, $description); + } + } + } + + /** + * Check if a directory is readable and writable + * + * @param string $dir Filename + * @param bool $failable Whether failing test should abort the installation process + */ + protected function check_dir($dir, $failable = false) + { + $path = $this->phpbb_root_path . $dir; + $exists = $writable = false; + + // Try to create the directory if it does not exist + if (!file_exists($path)) + { + try + { + $this->filesystem->mkdir($path, 0777); + $this->filesystem->phpbb_chmod($path, + \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE + ); + $exists = true; + } + catch (\phpbb\filesystem\exception\filesystem_exception $e) + { + // Do nothing + } + } + + // Now really check + if (file_exists($path) && is_dir($path)) + { + try + { + $exists = true; + $this->filesystem->phpbb_chmod($path, + \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE + ); + } + catch (\phpbb\filesystem\exception\filesystem_exception $e) + { + // Do nothing + } + } + + if ($this->filesystem->is_writable($path)) + { + $writable = true; + } + + $this->set_test_passed(($exists && $writable) || $failable); + + if (!($exists && $writable)) + { + $title = ($exists) ? 'DIRECTORY_NOT_WRITABLE' : 'DIRECTORY_NOT_EXISTS'; + $lang_suffix = '_EXPLAIN'; + $lang_suffix .= ($failable) ? '_OPTIONAL' : ''; + $description = array($title . $lang_suffix, $dir); + + if ($failable) + { + $this->response->add_warning_message($title, $description); + } + else + { + $this->response->add_error_message($title, $description); + } + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/requirements/task/check_server_environment.php b/phpBB/phpbb/install/module/requirements/task/check_server_environment.php new file mode 100644 index 0000000000..29f9777747 --- /dev/null +++ b/phpBB/phpbb/install/module/requirements/task/check_server_environment.php @@ -0,0 +1,209 @@ +<?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\install\module\requirements\task; + +/** + * Installer task that checks if the server meats phpBB requirements + */ +class check_server_environment extends \phpbb\install\task_base +{ + /** + * @var \phpbb\install\helper\database + */ + protected $database_helper; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $response_helper; + + /** + * @var bool + */ + protected $tests_passed; + + /** + * Constructor + * + * @param \phpbb\install\helper\database $database_helper + * @param \phpbb\install\helper\iohandler\iohandler_interface $response + */ + public function __construct(\phpbb\install\helper\database $database_helper, + \phpbb\install\helper\iohandler\iohandler_interface $response) + { + $this->database_helper = $database_helper; + $this->response_helper = $response; + $this->tests_passed = true; + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + // + // Check requirements + // The error messages should be set in the check_ functions + // + + // Check PHP version + $this->check_php_version(); + + // Check for getimagesize() + $this->check_image_size(); + + // Check for PCRE support + $this->check_pcre(); + + // Check for JSON support + $this->check_json(); + + // XML extension support check + $this->check_xml(); + + // Check for dbms support + $this->check_available_dbms(); + + return $this->tests_passed; + } + + /** + * Sets $this->tests_passed + * + * @param bool $is_passed + */ + protected function set_test_passed($is_passed) + { + // If one test failed, tests_passed should be false + $this->tests_passed = (!$this->tests_passed) ? false : $is_passed; + } + + /** + * Check if the requirements for PHP version is met + */ + protected function check_php_version() + { + $php_version = PHP_VERSION; + + if (version_compare($php_version, '5.4') < 0) + { + $this->response_helper->add_error_message('PHP_VERSION_REQD', 'PHP_VERSION_REQD_EXPLAIN'); + + $this->set_test_passed(false); + return; + } + + $this->set_test_passed(true); + } + + /** + * Checks if the installed PHP has getimagesize() available + */ + protected function check_image_size() + { + if (!@function_exists('getimagesize')) + { + $this->response_helper->add_error_message('PHP_GETIMAGESIZE_SUPPORT', 'PHP_GETIMAGESIZE_SUPPORT_EXPLAIN'); + + $this->set_test_passed(false); + return; + } + + $this->set_test_passed(true); + } + + /** + * Checks if the installed PHP supports PCRE + */ + protected function check_pcre() + { + if (@preg_match('//u', '')) + { + $this->set_test_passed(true); + return; + } + + $this->response_helper->add_error_message('PCRE_UTF_SUPPORT', 'PCRE_UTF_SUPPORT_EXPLAIN'); + + $this->set_test_passed(false); + } + + /** + * Checks whether PHP's JSON extension is available or not + */ + protected function check_json() + { + if (@extension_loaded('json')) + { + $this->set_test_passed(true); + return; + } + + $this->response_helper->add_error_message('PHP_JSON_SUPPORT', 'PHP_JSON_SUPPORT_EXPLAIN'); + + $this->set_test_passed(false); + } + + /** + * Checks whether or not the XML PHP extension is available (Required by the text formatter) + */ + protected function check_xml() + { + if (class_exists('DOMDocument')) + { + $this->set_test_passed(true); + return; + } + + $this->response_helper->add_error_message('PHP_XML_SUPPORT', 'PHP_XML_SUPPORT_EXPLAIN'); + + $this->set_test_passed(false); + } + + /** + * Check if any supported DBMS is available + */ + protected function check_available_dbms() + { + $available_dbms = $this->database_helper->get_available_dbms(false, true); + + if ($available_dbms['ANY_DB_SUPPORT']) + { + $this->set_test_passed(true); + return; + } + + $this->response_helper->add_error_message('PHP_SUPPORTED_DB', 'PHP_SUPPORTED_DB_EXPLAIN'); + + $this->set_test_passed(false); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/requirements/task/check_update.php b/phpBB/phpbb/install/module/requirements/task/check_update.php new file mode 100644 index 0000000000..cd66ffc8f9 --- /dev/null +++ b/phpBB/phpbb/install/module/requirements/task/check_update.php @@ -0,0 +1,195 @@ +<?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\install\module\requirements\task; + +use phpbb\filesystem\filesystem; +use phpbb\install\helper\config; +use phpbb\install\helper\container_factory; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\helper\update_helper; +use phpbb\install\task_base; + +/** + * Check the availability of updater files and update version + */ +class check_update extends task_base +{ + /** + * @var \phpbb\config\db + */ + protected $config; + + /** + * @var filesystem + */ + protected $filesystem; + + /** + * @var config + */ + protected $installer_config; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** + * @var update_helper + */ + protected $update_helper; + + /** + * @var \phpbb\version_helper + */ + protected $version_helper; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * @var bool + */ + protected $tests_passed; + + /** + * Constructor + * + * @param container_factory $container + * @param filesystem $filesystem + * @param config $config + * @param iohandler_interface $iohandler + * @param update_helper $update_helper + * @param string $phpbb_root_path + * @param string $php_ext + */ + public function __construct(container_factory $container, filesystem $filesystem, config $config, iohandler_interface $iohandler, update_helper $update_helper, $phpbb_root_path, $php_ext) + { + $this->filesystem = $filesystem; + $this->installer_config = $config; + $this->iohandler = $iohandler; + $this->update_helper = $update_helper; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + $this->tests_passed = true; + + $this->config = $container->get('config'); + $this->version_helper = $container->get('version_helper'); + + parent::__construct(true); + } + + /** + * Sets $this->tests_passed + * + * @param bool $is_passed + */ + protected function set_test_passed($is_passed) + { + // If one test failed, tests_passed should be false + $this->tests_passed = $this->tests_passed && $is_passed; + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Array of update files + $update_files = array( + $this->phpbb_root_path . 'install/update', + $this->phpbb_root_path . 'install/update/index.' . $this->php_ext, + ); + + // Check for a valid update directory + if (!$this->filesystem->exists($update_files) || !$this->filesystem->is_readable($update_files)) + { + $this->iohandler->add_warning_message('UPDATE_FILES_NOT_FOUND'); + $this->set_test_passed(false); + + // If there are no update files, we can't check the version etc + // However, we can let the users run migrations if they really want to... + $this->installer_config->set('disable_filesystem_update', true); + return true; + } + + // Recover version numbers + $update_info = array(); + @include($this->phpbb_root_path . 'install/update/index.' . $this->php_ext); + $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info; + $update_version = false; + + if ($info !== false) + { + $update_version = (!empty($info['version']['to'])) ? trim($info['version']['to']) : false; + } + + // Get current and latest version + try + { + $latest_version = $this->version_helper->get_latest_on_current_branch(true); + } + catch (\RuntimeException $e) + { + $latest_version = $update_version; + } + + $current_version = (!empty($this->config['version_update_from'])) ? $this->config['version_update_from'] : $this->config['version']; + + // Check if the update package + if (!$this->update_helper->phpbb_version_compare($current_version, $update_version, '<')) + { + $this->iohandler->add_error_message('NO_UPDATE_FILES_UP_TO_DATE'); + $this->tests_passed = false; + } + + // Check if the update package works with the installed version + if (empty($info['version']['from']) || $info['version']['from'] !== $current_version) + { + $this->iohandler->add_error_message(array('INCOMPATIBLE_UPDATE_FILES', $current_version, $info['version']['from'], $update_version)); + $this->tests_passed = false; + } + + // check if this is the latest update package + if ($this->update_helper->phpbb_version_compare($update_version, $latest_version, '<')) + { + $this->iohandler->add_warning_message(array('OLD_UPDATE_FILES', $info['version']['from'], $update_version, $latest_version)); + } + + return $this->tests_passed; + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/requirements/update_module.php b/phpBB/phpbb/install/module/requirements/update_module.php new file mode 100644 index 0000000000..223d12faf3 --- /dev/null +++ b/phpBB/phpbb/install/module/requirements/update_module.php @@ -0,0 +1,25 @@ +<?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\install\module\requirements; + +class update_module extends abstract_requirements_module +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('update', 0, 'requirements'); + } +} diff --git a/phpBB/phpbb/install/module/update_database/module.php b/phpBB/phpbb/install/module/update_database/module.php new file mode 100644 index 0000000000..ee38afe17d --- /dev/null +++ b/phpBB/phpbb/install/module/update_database/module.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\install\module\update_database; + +class module extends \phpbb\install\module_base +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('update', 0, 'update_database'); + } + + /** + * {@inheritdoc} + */ + public function get_step_count() + { + return 0; + } +} diff --git a/phpBB/phpbb/install/module/update_database/task/update.php b/phpBB/phpbb/install/module/update_database/task/update.php new file mode 100644 index 0000000000..fb9eb44e6a --- /dev/null +++ b/phpBB/phpbb/install/module/update_database/task/update.php @@ -0,0 +1,234 @@ +<?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\install\module\update_database\task; + +use phpbb\db\migration\exception; +use phpbb\db\output_handler\installer_migrator_output_handler; +use phpbb\db\output_handler\log_wrapper_migrator_output_handler; +use phpbb\install\exception\resource_limit_reached_exception; +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\task_base; + +/** + * Database updater task + */ +class update extends task_base +{ + /** + * @var \phpbb\cache\driver\driver_interface + */ + protected $cache; + + /** + * @var \phpbb\config\config + */ + protected $config; + + /** + * @var \phpbb\extension\manager + */ + protected $extension_manager; + + /** + * @var \phpbb\filesystem\filesystem + */ + protected $filesystem; + + /** + * @var \phpbb\install\helper\config + */ + protected $installer_config; + + /** + * @var \phpbb\install\helper\iohandler\iohandler_interface + */ + protected $iohandler; + + /** + * @var \phpbb\language\language + */ + protected $language; + + /** + * @var \phpbb\log\log + */ + protected $log; + + /** + * @var \phpbb\db\migrator + */ + protected $migrator; + + /** + * @var \phpbb\user + */ + protected $user; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param \phpbb\install\helper\container_factory $container + * @param \phpbb\filesystem\filesystem $filesystem + * @param \phpbb\install\helper\config $installer_config + * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler + * @param \phpbb\language\language $language + * @param string $phpbb_root_path + */ + public function __construct(\phpbb\install\helper\container_factory $container, \phpbb\filesystem\filesystem $filesystem, \phpbb\install\helper\config $installer_config, \phpbb\install\helper\iohandler\iohandler_interface $iohandler, \phpbb\language\language $language, $phpbb_root_path) + { + $this->filesystem = $filesystem; + $this->installer_config = $installer_config; + $this->iohandler = $iohandler; + $this->language = $language; + $this->phpbb_root_path = $phpbb_root_path; + + $this->cache = $container->get('cache.driver'); + $this->config = $container->get('config'); + $this->extension_manager = $container->get('ext.manager'); + $this->log = $container->get('log'); + $this->migrator = $container->get('migrator'); + $this->user = $container->get('user'); + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->language->add_lang('migrator'); + + if (!isset($this->config['version_update_from'])) + { + $this->config->set('version_update_from', $this->config['version']); + } + + $original_version = $this->config['version_update_from']; + + $this->migrator->set_output_handler( + new log_wrapper_migrator_output_handler( + $this->language, + new installer_migrator_output_handler($this->iohandler), + $this->phpbb_root_path . 'store/migrations_' . time() . '.log', + $this->filesystem + ) + ); + + $this->migrator->create_migrations_table(); + + $migrations = $this->extension_manager + ->get_finder() + ->core_path('phpbb/db/migration/data/') + ->extension_directory('/migrations') + ->get_classes(); + + $this->migrator->set_migrations($migrations); + + $migration_step_count = $this->installer_config->get('database_update_migration_steps', -1); + if ($migration_step_count < 0) + { + $migration_step_count = count($this->migrator->get_installable_migrations()) * 2; + $this->installer_config->set('database_update_migration_steps', $migration_step_count); + } + + $progress_count = $this->installer_config->get('database_update_count', 0); + $restart_progress_bar = ($progress_count === 0); // Only "restart" when the update runs for the first time + $this->iohandler->set_task_count($migration_step_count, $restart_progress_bar); + $this->installer_config->set_task_progress_count($migration_step_count); + + while (!$this->migrator->finished()) + { + try + { + $this->migrator->update(); + $progress_count++; + + $last_run_migration = $this->migrator->get_last_run_migration(); + if (isset($last_run_migration['effectively_installed']) && $last_run_migration['effectively_installed']) + { + // We skipped two step, so increment $progress_count by another one + $progress_count++; + } + else if (($last_run_migration['task'] === 'process_schema_step' && !$last_run_migration['state']['migration_schema_done']) || + ($last_run_migration['task'] === 'process_data_step' && !$last_run_migration['state']['migration_data_done'])) + { + // We just run a step that wasn't counted yet so make it count + $migration_step_count++; + } + + $this->iohandler->set_task_count($migration_step_count); + $this->installer_config->set_task_progress_count($migration_step_count); + $this->iohandler->set_progress('STAGE_UPDATE_DATABASE', $progress_count); + } + catch (exception $e) + { + $msg = $e->getParameters(); + array_unshift($msg, $e->getMessage()); + + $this->iohandler->add_error_message($msg); + throw new user_interaction_required_exception(); + } + + if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0) + { + $this->installer_config->set('database_update_count', $progress_count); + $this->installer_config->set('database_update_migration_steps', $migration_step_count); + throw new resource_limit_reached_exception(); + } + } + + if ($original_version !== $this->config['version']) + { + $this->log->add( + 'admin', + (isset($this->user->data['user_id'])) ? $this->user->data['user_id'] : ANONYMOUS, + $this->user->ip, + 'LOG_UPDATE_DATABASE', + false, + array( + $original_version, + $this->config['version'] + ) + ); + } + + $this->iohandler->add_success_message('INLINE_UPDATE_SUCCESSFUL'); + + $this->cache->purge(); + + $this->config->increment('assets_version', 1); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/update_database/task/update_extensions.php b/phpBB/phpbb/install/module/update_database/task/update_extensions.php new file mode 100644 index 0000000000..b66847b243 --- /dev/null +++ b/phpBB/phpbb/install/module/update_database/task/update_extensions.php @@ -0,0 +1,263 @@ +<?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\install\module\update_database\task; + +use phpbb\install\exception\resource_limit_reached_exception; +use phpbb\install\helper\container_factory; +use phpbb\install\helper\config; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\helper\update_helper; +use phpbb\install\task_base; +use Symfony\Component\Finder\Finder; + +/** + * Installs extensions that exist in ext folder upon install + */ +class update_extensions extends task_base +{ + /** + * @var \phpbb\cache\driver\driver_interface + */ + protected $cache; + + /** + * @var config + */ + protected $install_config; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** @var update_helper */ + protected $update_helper; + + /** + * @var \phpbb\config\db + */ + protected $config; + + /** + * @var \phpbb\log\log_interface + */ + protected $log; + + /** + * @var \phpbb\user + */ + protected $user; + + /** @var \phpbb\extension\manager */ + protected $extension_manager; + + /** @var Finder */ + protected $finder; + + /** @var string Extension table */ + protected $extension_table; + + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + /** + * @var array List of default extensions to update, grouped by version + * they were added + */ + static public $default_extensions_update = [ + '3.2.0-RC2' => ['phpbb/viglink'] + ]; + + /** + * Constructor + * + * @param container_factory $container + * @param config $install_config + * @param iohandler_interface $iohandler + * @param $update_helper $update_helper + * @param string $phpbb_root_path phpBB root path + */ + public function __construct(container_factory $container, config $install_config, iohandler_interface $iohandler, update_helper $update_helper, $phpbb_root_path) + { + $this->install_config = $install_config; + $this->iohandler = $iohandler; + $this->extension_table = $container->get_parameter('tables.ext'); + + $this->log = $container->get('log'); + $this->user = $container->get('user'); + $this->extension_manager = $container->get('ext.manager'); + $this->cache = $container->get('cache.driver'); + $this->config = $container->get('config'); + $this->db = $container->get('dbal.conn'); + $this->update_helper = $update_helper; + $this->finder = new Finder(); + $this->finder->in($phpbb_root_path . 'ext/') + ->ignoreUnreadableDirs() + ->depth('< 3') + ->files() + ->name('composer.json'); + + // Make sure asset version exists in config. Otherwise we might try to + // insert the assets_version setting into the database and cause a + // duplicate entry error. + if (!isset($this->config['assets_version'])) + { + $this->config['assets_version'] = 0; + } + + parent::__construct(true); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $this->user->session_begin(); + $this->user->setup(array('common', 'acp/common', 'cli')); + + $update_info = $this->install_config->get('update_info_unprocessed', []); + $version_from = !empty($update_info) ? $update_info['version']['from'] : $this->config['version_update_from']; + + if (!empty($version_from)) + { + $update_extensions = $this->iohandler->get_input('update-extensions', []); + + // Create list of default extensions that need to be enabled in update + $default_update_extensions = []; + foreach (self::$default_extensions_update as $version => $extensions) + { + if ($this->update_helper->phpbb_version_compare($version_from, $version, '<')) + { + $default_update_extensions = array_merge($default_update_extensions, $extensions); + } + } + + $all_available_extensions = $this->extension_manager->all_available(); + $i = $this->install_config->get('update_extensions_index', 0); + $available_extensions = array_slice($all_available_extensions, $i); + + // Update available extensions + foreach ($available_extensions as $ext_name => $ext_path) + { + // Update extensions if: + // 1) Extension is currently enabled + // 2) Extension was implicitly defined as needing an update + // 3) Extension was newly added as default phpBB extension in + // this update and should be enabled by default. + if ($this->extension_manager->is_enabled($ext_name) || + in_array($ext_name, $update_extensions) || + in_array($ext_name, $default_update_extensions) + ) + { + try + { + $extension_enabled = $this->extension_manager->is_enabled($ext_name); + if ($extension_enabled) + { + $this->extension_manager->disable($ext_name); + } + $this->extension_manager->enable($ext_name); + $extensions = $this->get_extensions(); + + if (isset($extensions[$ext_name]) && $extensions[$ext_name]['ext_active']) + { + // Create log + $this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_UPDATE', time(), array($ext_name)); + $this->iohandler->add_success_message(array('CLI_EXTENSION_UPDATE_SUCCESS', $ext_name)); + } + else + { + $this->iohandler->add_log_message('CLI_EXTENSION_UPDATE_FAILURE', array($ext_name)); + } + + // Disable extensions if it was disabled by the admin before + if (!$extension_enabled && !in_array($ext_name, $default_update_extensions)) + { + $this->extension_manager->disable($ext_name); + } + } + catch (\Exception $e) + { + // Add fail log and continue + $this->iohandler->add_log_message('CLI_EXTENSION_UPDATE_FAILURE', array($ext_name)); + } + } + + $i++; + + // Stop execution if resource limit is reached + if ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0) + { + break; + } + } + + $this->install_config->set('update_extensions_index', $i); + + if ($i < sizeof($all_available_extensions)) + { + throw new resource_limit_reached_exception(); + } + } + + $this->config->delete('version_update_from'); + + $this->cache->purge(); + + $this->config->increment('assets_version', 1); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 1; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return 'TASK_UPDATE_EXTENSIONS'; + } + + /** + * Get extensions from database + * + * @return array List of extensions + */ + private function get_extensions() + { + $sql = 'SELECT * + FROM ' . $this->extension_table; + + $result = $this->db->sql_query($sql); + $extensions_row = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + $extensions = array(); + + foreach ($extensions_row as $extension) + { + $extensions[$extension['ext_name']] = $extension; + } + + ksort($extensions); + + return $extensions; + } +} diff --git a/phpBB/phpbb/install/module/update_filesystem/module.php b/phpBB/phpbb/install/module/update_filesystem/module.php new file mode 100644 index 0000000000..157c78a1ac --- /dev/null +++ b/phpBB/phpbb/install/module/update_filesystem/module.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\install\module\update_filesystem; + +class module extends \phpbb\install\module_base +{ + /** + * {@inheritdoc} + */ + public function get_navigation_stage_path() + { + return array('update', 0, 'update_files'); + } + + /** + * {@inheritdoc} + */ + public function get_step_count() + { + return 0; + } +} diff --git a/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php b/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php new file mode 100644 index 0000000000..1792a3b723 --- /dev/null +++ b/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php @@ -0,0 +1,226 @@ +<?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\install\module\update_filesystem\task; + +use phpbb\install\exception\resource_limit_reached_exception; +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\container_factory; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\helper\update_helper; +use phpbb\install\task_base; + +/** + * Merges user made changes into the files + */ +class diff_files extends task_base +{ + /** + * @var \phpbb\cache\driver\driver_interface + */ + protected $cache; + + /** + * @var config + */ + protected $installer_config; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * @var string + */ + protected $php_ext; + + /** + * @var update_helper + */ + protected $update_helper; + + /** + * Constructor + * + * @param container_factory $container + * @param config $config + * @param iohandler_interface $iohandler + * @param update_helper $update_helper + * @param string $phpbb_root_path + * @param string $php_ext + */ + public function __construct(container_factory $container, config $config, iohandler_interface $iohandler, update_helper $update_helper, $phpbb_root_path, $php_ext) + { + $this->installer_config = $config; + $this->iohandler = $iohandler; + $this->update_helper = $update_helper; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + + $this->cache = $container->get('cache.driver'); + + parent::__construct(false); + } + + /** + * {@inheritdoc} + */ + public function check_requirements() + { + $files_to_diff = $this->installer_config->get('update_files', array()); + $files_to_diff = (isset($files_to_diff['update_with_diff'])) ? $files_to_diff['update_with_diff'] : array(); + + return $this->installer_config->get('do_update_files', false) && count($files_to_diff) > 0; + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Include diff engine + $this->update_helper->include_file('includes/diff/diff.' . $this->php_ext); + $this->update_helper->include_file('includes/diff/engine.' . $this->php_ext); + + // Set up basic vars + $old_path = $this->update_helper->get_path_to_old_update_files(); + $new_path = $this->update_helper->get_path_to_new_update_files(); + + $files_to_diff = $this->installer_config->get('update_files', array()); + $files_to_diff = $files_to_diff['update_with_diff']; + + // Set progress bar + $this->iohandler->set_task_count(count($files_to_diff), true); + $this->iohandler->set_progress('UPDATE_FILE_DIFF', 0); + $progress_count = $this->installer_config->get('file_diff_update_count', 0); + + // Recover progress + $progress_key = $this->installer_config->get('differ_progress_key', -1); + $progress_recovered = ($progress_key === -1); + $merge_conflicts = $this->installer_config->get('merge_conflict_list', array()); + + foreach ($files_to_diff as $key => $filename) + { + if ($progress_recovered === false) + { + if ($progress_key === $key) + { + $progress_recovered = true; + } + + continue; + } + + // Read in files' content + $file_contents = array(); + + // Handle the special case when user created a file with the filename that is now new in the core + if (file_exists($old_path . $filename)) + { + $file_contents[0] = file_get_contents($old_path . $filename); + + $filenames = array( + $this->phpbb_root_path . $filename, + $new_path . $filename + ); + + foreach ($filenames as $file_to_diff) + { + $file_contents[] = file_get_contents($file_to_diff); + + if ($file_contents[sizeof($file_contents) - 1] === false) + { + $this->iohandler->add_error_message(array('FILE_DIFFER_ERROR_FILE_CANNOT_BE_READ', $files_to_diff)); + unset($file_contents); + throw new user_interaction_required_exception(); + } + } + + $diff = new \diff3($file_contents[0], $file_contents[1], $file_contents[2]); + unset($file_contents); + + // Handle conflicts + if ($diff->get_num_conflicts() !== 0) + { + $merge_conflicts[] = $filename; + } + + // Save merged output + $this->cache->put( + '_file_' . md5($filename), + base64_encode(implode("\n", $diff->merged_output())) + ); + + unset($diff); + } + else + { + $new_file_content = file_get_contents($new_path . $filename); + + if ($new_file_content === false) + { + $this->iohandler->add_error_message(array('FILE_DIFFER_ERROR_FILE_CANNOT_BE_READ', $files_to_diff)); + unset($new_file_content ); + throw new user_interaction_required_exception(); + } + + // Save new file content to cache + $this->cache->put( + '_file_' . md5($filename), + base64_encode($new_file_content) + ); + unset($new_file_content); + } + + $progress_count++; + $this->iohandler->set_progress('UPDATE_FILE_DIFF', $progress_count); + + if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0) + { + // Save differ progress + $this->installer_config->set('differ_progress_key', $key); + $this->installer_config->set('merge_conflict_list', $merge_conflicts); + $this->installer_config->set('file_diff_update_count', $progress_count); + + // Request refresh + throw new resource_limit_reached_exception(); + } + } + + $this->iohandler->finish_progress('ALL_FILES_DIFFED'); + $this->installer_config->set('merge_conflict_list', $merge_conflicts); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php b/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php new file mode 100644 index 0000000000..f911b7ac62 --- /dev/null +++ b/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php @@ -0,0 +1,123 @@ +<?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\install\module\update_filesystem\task; + +use phpbb\filesystem\filesystem; +use phpbb\install\exception\jump_to_restart_point_exception; +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\task_base; + +class download_updated_files extends task_base +{ + /** + * @var config + */ + protected $installer_config; + + /** + * @var filesystem + */ + protected $filesystem; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** + * Constructor + * + * @param config $config + * @param iohandler_interface $iohandler + * @param filesystem $filesystem + */ + public function __construct(config $config, iohandler_interface $iohandler, filesystem $filesystem) + { + $this->installer_config = $config; + $this->iohandler = $iohandler; + $this->filesystem = $filesystem; + + parent::__construct(false); + } + + /** + * {@inheritdoc} + */ + public function check_requirements() + { + return $this->installer_config->get('do_update_files', false) + && $this->installer_config->get('file_update_method', '') === 'compression'; + } + + /** + * {@inheritdoc} + */ + public function run() + { + if ($this->iohandler->get_input('database_update_submit', false)) + { + // Remove archive + $this->filesystem->remove( + $this->installer_config->get('update_file_archive', null) + ); + + $this->installer_config->set('update_file_archive', null); + } + else if ($this->iohandler->get_input('update_recheck_files_submit', false)) + { + throw new jump_to_restart_point_exception('check_update_files'); + } + else + { + // Render download box + $this->iohandler->add_download_link( + 'phpbb_installer_update_file_download', + 'DOWNLOAD_UPDATE_METHOD', + 'DOWNLOAD_UPDATE_METHOD_EXPLAIN' + ); + + // Add form to continue update + $this->iohandler->add_user_form_group('UPDATE_CONTINUE_UPDATE_PROCESS', array( + 'update_recheck_files_submit' => array( + 'label' => 'UPDATE_RECHECK_UPDATE_FILES', + 'type' => 'submit', + ), + 'database_update_submit' => array( + 'label' => 'UPDATE_CONTINUE_UPDATE_PROCESS', + 'type' => 'submit', + ), + )); + + throw new user_interaction_required_exception(); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/update_filesystem/task/file_check.php b/phpBB/phpbb/install/module/update_filesystem/task/file_check.php new file mode 100644 index 0000000000..47a71eb844 --- /dev/null +++ b/phpBB/phpbb/install/module/update_filesystem/task/file_check.php @@ -0,0 +1,219 @@ +<?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\install\module\update_filesystem\task; + +use phpbb\filesystem\filesystem; +use phpbb\install\exception\resource_limit_reached_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\helper\update_helper; +use phpbb\install\task_base; + +/** + * Updater task performing file checking + */ +class file_check extends task_base +{ + /** + * @var filesystem + */ + protected $filesystem; + + /** + * @var config + */ + protected $installer_config; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** + * @var update_helper + */ + protected $update_helper; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Construct + * + * @param filesystem $filesystem + * @param config $config + * @param iohandler_interface $iohandler + * @param update_helper $update_helper + * @param string $phpbb_root_path + */ + public function __construct(filesystem $filesystem, config $config, iohandler_interface $iohandler, update_helper $update_helper, $phpbb_root_path) + { + $this->filesystem = $filesystem; + $this->installer_config = $config; + $this->iohandler = $iohandler; + $this->update_helper = $update_helper; + $this->phpbb_root_path = $phpbb_root_path; + + parent::__construct(false); + } + + /** + * {@inheritdoc} + */ + public function check_requirements() + { + return $this->installer_config->get('do_update_files', false); + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!$this->installer_config->has_restart_point('check_update_files')) + { + $this->installer_config->create_progress_restart_point('check_update_files'); + } + + $old_path = $this->update_helper->get_path_to_old_update_files(); + $new_path = $this->update_helper->get_path_to_new_update_files(); + + $update_info = $this->installer_config->get('update_info', array()); + $file_update_info = $this->installer_config->get('update_files', array()); + + if (empty($update_info)) + { + $root_path = $this->phpbb_root_path; + + $update_info = $this->installer_config->get('update_info_unprocessed', array()); + + $file_update_info = array(); + $file_update_info['update_without_diff'] = array_diff($update_info['binary'], $update_info['deleted']); + + // Filter out files that are already deleted + $file_update_info['delete'] = array_filter( + $update_info['deleted'], + function ($filename) use ($root_path) + { + return file_exists($root_path . $filename); + } + ); + } + + $progress_count = $this->installer_config->get('file_check_progress_count', 0); + $task_count = count($update_info['files']); + $this->iohandler->set_task_count($task_count); + $this->iohandler->set_progress('UPDATE_CHECK_FILES', 0); + + // Create list of default extensions that should have been added prior + // to this update + $default_update_extensions = []; + foreach (\phpbb\install\module\update_database\task\update_extensions::$default_extensions_update as $version => $extensions) + { + if ($this->update_helper->phpbb_version_compare($update_info['version']['from'], $version, '>=')) + { + $default_update_extensions = array_merge($default_update_extensions, $extensions); + } + } + + foreach ($update_info['files'] as $key => $filename) + { + $old_file = $old_path . $filename; + $new_file = $new_path . $filename; + $file = $this->phpbb_root_path . $filename; + + if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0) + { + // Save progress + $this->installer_config->set('update_info', $update_info); + $this->installer_config->set('file_check_progress_count', $progress_count); + $this->installer_config->set('update_files', $file_update_info); + + // Request refresh + throw new resource_limit_reached_exception(); + } + + $progress_count++; + $this->iohandler->set_progress('UPDATE_CHECK_FILES', $progress_count); + + // Do not copy default extension again if the previous version was + // packaged with it but it does not exist (e.g. deleted by admin) + if (strpos($file, $this->phpbb_root_path . 'ext/') !== false) + { + $skip_file = false; + foreach ($default_update_extensions as $ext_name) + { + if (strpos($file, $this->phpbb_root_path . 'ext/' . $ext_name) !== false && + !$this->filesystem->exists($this->phpbb_root_path . 'ext/' . $ext_name . '/composer.json')) + { + $skip_file = true; + break; + } + } + + if ($skip_file) + { + continue; + } + } + + if (!$this->filesystem->exists($file)) + { + $file_update_info['new'][] = $filename; + } + else + { + $file_checksum = md5_file($file); + + if ($file_checksum === md5_file($new_file)) + { + // File already up to date + continue; + } + else if ($this->filesystem->exists($old_file) && $file_checksum === md5_file($old_file)) + { + // No need to diff the file + $file_update_info['update_without_diff'][] = $filename; + } + else + { + $file_update_info['update_with_diff'][] = $filename; + } + } + + unset($update_info['files'][$key]); + } + + $this->installer_config->set('update_files', $file_update_info); + $this->installer_config->set('update_info', array()); + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/update_filesystem/task/show_file_status.php b/phpBB/phpbb/install/module/update_filesystem/task/show_file_status.php new file mode 100644 index 0000000000..cf1e4cf4ac --- /dev/null +++ b/phpBB/phpbb/install/module/update_filesystem/task/show_file_status.php @@ -0,0 +1,170 @@ +<?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\install\module\update_filesystem\task; + +use phpbb\filesystem\filesystem; +use phpbb\install\exception\user_interaction_required_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\container_factory; +use phpbb\install\helper\file_updater\factory; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\task_base; + +class show_file_status extends task_base +{ + /** + * @var \phpbb\cache\driver\driver_interface + */ + protected $cache; + + /** + * @var filesystem + */ + protected $filesystem; + + /** + * @var config + */ + protected $installer_config; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** + * @var \phpbb\install\helper\file_updater\compression_file_updater + */ + protected $file_updater; + + /** + * Constructor + * + * @param container_factory $container + * @param config $config + * @param iohandler_interface $iohandler + * @param filesystem $filesystem + * @param factory $file_updater_factory + */ + public function __construct(container_factory $container, config $config, iohandler_interface $iohandler, filesystem $filesystem, factory $file_updater_factory) + { + $this->installer_config = $config; + $this->iohandler = $iohandler; + $this->filesystem = $filesystem; + + $this->cache = $container->get('cache.driver'); + + // Initialize compression file updater + $this->file_updater = $file_updater_factory->get('compression'); + + parent::__construct(false); + } + + /** + * {@inheritdoc} + */ + public function check_requirements() + { + return $this->installer_config->get('do_update_files', false); + } + + /** + * {@inheritdoc} + */ + public function run() + { + if (!$this->iohandler->get_input('submit_continue_file_update', false)) + { + // Handle merge conflicts + $merge_conflicts = $this->installer_config->get('merge_conflict_list', array()); + + // Create archive for merge conflicts + if (!empty($merge_conflicts)) + { + $compression_method = $this->installer_config->get('file_update_compression', ''); + $conflict_archive = $this->file_updater->init($compression_method); + $this->installer_config->set('update_file_conflict_archive', $conflict_archive); + + foreach ($merge_conflicts as $filename) + { + $this->file_updater->create_new_file( + $filename, + base64_decode($this->cache->get('_file_' . md5($filename))), + true + ); + } + + // Render download box + $this->iohandler->add_download_link( + 'phpbb_installer_update_conflict_download', + 'DOWNLOAD_CONFLICTS', + 'DOWNLOAD_CONFLICTS_EXPLAIN' + ); + + $this->file_updater->close(); + } + + // Render update file statuses + $file_update_info = $this->installer_config->get('update_files', array()); + $file_status = array( + 'deleted' => (!isset($file_update_info['delete'])) ? array() : $file_update_info['delete'], + 'new' => (!isset($file_update_info['new'])) ? array() : $file_update_info['new'], + 'conflict' => $this->installer_config->get('merge_conflict_list', array()), + 'modified' => (!isset($file_update_info['update_with_diff'])) ? array() : $file_update_info['update_with_diff'], + 'not_modified' => (!isset($file_update_info['update_without_diff'])) ? array() : $file_update_info['update_without_diff'], + ); + + $this->iohandler->render_update_file_status($file_status); + + // Add form to continue update + $this->iohandler->add_user_form_group('UPDATE_CONTINUE_FILE_UPDATE', array( + 'submit_continue_file_update' => array( + 'label' => 'UPDATE_CONTINUE_FILE_UPDATE', + 'type' => 'submit', + ), + )); + + // Show results to the user + throw new user_interaction_required_exception(); + } + else + { + $conflict_archive_path = $this->installer_config->get('update_file_conflict_archive', null); + + // Remove archive + if ($conflict_archive_path !== null && $this->filesystem->exists($conflict_archive_path)) + { + $this->filesystem->remove($conflict_archive_path); + } + + $this->installer_config->set('update_file_conflict_archive', null); + } + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module/update_filesystem/task/update_files.php b/phpBB/phpbb/install/module/update_filesystem/task/update_files.php new file mode 100644 index 0000000000..fbb465cc66 --- /dev/null +++ b/phpBB/phpbb/install/module/update_filesystem/task/update_files.php @@ -0,0 +1,294 @@ +<?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\install\module\update_filesystem\task; + +use phpbb\exception\runtime_exception; +use phpbb\install\exception\resource_limit_reached_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\container_factory; +use phpbb\install\helper\file_updater\factory; +use phpbb\install\helper\file_updater\file_updater_interface; +use phpbb\install\helper\iohandler\iohandler_interface; +use phpbb\install\helper\update_helper; +use phpbb\install\task_base; + +/** + * File updater task + */ +class update_files extends task_base +{ + /** + * @var \phpbb\cache\driver\driver_interface + */ + protected $cache; + + /** + * @var config + */ + protected $installer_config; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** + * @var factory + */ + protected $factory; + + /** + * @var file_updater_interface + */ + protected $file_updater; + + /** + * @var update_helper + */ + protected $update_helper; + + /** + * @var string + */ + protected $phpbb_root_path; + + /** + * Constructor + * + * @param container_factory $container + * @param config $config + * @param iohandler_interface $iohandler + * @param factory $file_updater_factory + * @param update_helper $update_helper + * @param string $phpbb_root_path + */ + public function __construct(container_factory $container, config $config, iohandler_interface $iohandler, factory $file_updater_factory, update_helper $update_helper, $phpbb_root_path) + { + $this->factory = $file_updater_factory; + $this->installer_config = $config; + $this->iohandler = $iohandler; + $this->update_helper = $update_helper; + $this->phpbb_root_path = $phpbb_root_path; + + $this->cache = $container->get('cache.driver'); + $this->file_updater = null; + + parent::__construct(false); + } + + /** + * {@inheritdoc} + */ + public function check_requirements() + { + return $this->installer_config->get('do_update_files', false); + } + + /** + * {@inheritdoc} + */ + public function run() + { + $new_path = $this->update_helper->get_path_to_new_update_files(); + + $file_update_info = $this->installer_config->get('update_files', array()); + + $update_type_progress = $this->installer_config->get('file_updater_type_progress', ''); + $update_elem_progress = $this->installer_config->get('file_updater_elem_progress', ''); + $type_progress_found = false; + $elem_progress_found = false; + + // Progress bar + $task_count = 0; + foreach ($file_update_info as $sub_array) + { + $task_count += count($sub_array); + } + + // Everything is up to date, so just continue + if ($task_count === 0) + { + return; + } + + $progress_count = $this->installer_config->get('file_update_progress_count', 0); + $this->iohandler->set_task_count($task_count, true); + $this->iohandler->set_progress('UPDATE_UPDATING_FILES', 0); + + $this->file_updater = $this->get_file_updater(); + + // File updater fallback logic + try + { + // Update files + foreach ($file_update_info as $type => $file_update_vector) + { + if (!$type_progress_found) + { + if ($type === $update_type_progress || empty($update_elem_progress)) + { + $type_progress_found = true; + } + else + { + continue; + } + } + + foreach ($file_update_vector as $path) + { + if (!$elem_progress_found) + { + if ($path === $update_elem_progress || empty($update_elem_progress)) + { + $elem_progress_found = true; + } + else + { + continue; + } + } + + switch ($type) + { + case 'delete': + $this->file_updater->delete_file($path); + break; + case 'new': + $this->file_updater->create_new_file($path, $new_path . $path); + break; + case 'update_without_diff': + $this->file_updater->update_file($path, $new_path . $path); + break; + case 'update_with_diff': + $this->file_updater->update_file( + $path, + base64_decode($this->cache->get('_file_' . md5($path))), + true + ); + break; + } + + // Save progress + $this->installer_config->set('file_updater_type_progress', $type); + $this->installer_config->set('file_updater_elem_progress', $path); + $progress_count++; + $this->iohandler->set_progress('UPDATE_UPDATING_FILES', $progress_count); + + if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0) + { + // Request refresh + throw new resource_limit_reached_exception(); + } + } + } + + $this->iohandler->finish_progress('UPDATE_UPDATING_FILES'); + } + catch (runtime_exception $e) + { + if ($e instanceof resource_limit_reached_exception) + { + throw new resource_limit_reached_exception(); + } + + $current_method = $this->installer_config->get('file_update_method', ''); + + // File updater failed, try to fallback to download file update mode + if ($current_method !== 'compression') + { + $this->iohandler->add_warning_message(array( + 'UPDATE_FILE_UPDATER_HAS_FAILED', + $current_method, + 'compression' + )); + $this->installer_config->set('file_update_method', 'compression'); + + // We only want a simple refresh here + throw new resource_limit_reached_exception(); + } + else + { + // Nowhere to fallback to :( + // Due to the way the installer handles fatal errors, we need to throw a low level exception + throw new runtime_exception('UPDATE_FILE_UPDATERS_HAVE_FAILED'); + } + } + + $file_updater_method = $this->installer_config->get('file_update_method', ''); + if ($file_updater_method === 'compression' || $file_updater_method === 'ftp') + { + $this->file_updater->close(); + } + } + + /** + * Get file updater + * + * @param null|string $file_updater_method Name of the file updater to use + * + * @return file_updater_interface File updater + */ + protected function get_file_updater($file_updater_method = null) + { + $file_updater_method = ($file_updater_method === null) ? $this->installer_config->get('file_update_method', '') : $file_updater_method; + + if ($file_updater_method === 'compression') + { + $compression_method = $this->installer_config->get('file_update_compression', ''); + + /** @var \phpbb\install\helper\file_updater\compression_file_updater $file_updater */ + $file_updater = $this->factory->get('compression'); + $archive_path = $file_updater->init($compression_method); + $this->installer_config->set('update_file_archive', $archive_path); + } + else if ($file_updater_method === 'ftp') + { + /** @var \phpbb\install\helper\file_updater\ftp_file_updater $file_updater */ + $file_updater = $this->factory->get('ftp'); + $file_updater->init( + $this->installer_config->get('ftp_method', ''), + $this->installer_config->get('ftp_host', ''), + $this->installer_config->get('ftp_user', ''), + $this->installer_config->get('ftp_pass', ''), + $this->installer_config->get('ftp_path', ''), + $this->installer_config->get('ftp_port', 0), + $this->installer_config->get('ftp_timeout', 10) + ); + } + else + { + /** @var file_updater_interface $file_updater */ + $file_updater = $this->factory->get('direct_file'); + } + + return $file_updater; + } + + /** + * {@inheritdoc} + */ + static public function get_step_count() + { + return 0; + } + + /** + * {@inheritdoc} + */ + public function get_task_lang_name() + { + return ''; + } +} diff --git a/phpBB/phpbb/install/module_base.php b/phpBB/phpbb/install/module_base.php new file mode 100644 index 0000000000..93c10bd656 --- /dev/null +++ b/phpBB/phpbb/install/module_base.php @@ -0,0 +1,213 @@ +<?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\install; + +use phpbb\di\ordered_service_collection; +use phpbb\install\exception\resource_limit_reached_exception; +use phpbb\install\helper\config; +use phpbb\install\helper\iohandler\iohandler_interface; + +/** + * Base class for installer module + */ +abstract class module_base implements module_interface +{ + /** + * @var config + */ + protected $install_config; + + /** + * @var iohandler_interface + */ + protected $iohandler; + + /** + * @var bool + */ + protected $is_essential; + + /** + * Array of tasks for installer module + * + * @var ordered_service_collection + */ + protected $task_collection; + + /** + * @var array + */ + protected $task_step_count; + + /** + * @var bool + */ + protected $allow_progress_bar; + + /** + * Installer module constructor + * + * @param ordered_service_collection $tasks array of installer tasks for installer module + * @param bool $essential flag indicating whether the module is essential or not + * @param bool $allow_progress_bar flag indicating whether or not to send progress information from within the module + */ + public function __construct(ordered_service_collection $tasks, $essential = true, $allow_progress_bar = true) + { + $this->task_collection = $tasks; + $this->is_essential = $essential; + $this->allow_progress_bar = $allow_progress_bar; + } + + /** + * Dependency getter + * + * @param config $config + * @param iohandler_interface $iohandler + */ + public function setup(config $config, iohandler_interface $iohandler) + { + $this->install_config = $config; + $this->iohandler = $iohandler; + } + + /** + * {@inheritdoc} + */ + public function is_essential() + { + return $this->is_essential; + } + + /** + * {@inheritdoc} + * + * Overwrite this method if your task is non-essential! + */ + public function check_requirements() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Recover install progress + $task_index = $this->recover_progress(); + $iterator = $this->task_collection->getIterator(); + + if ($task_index < $iterator->count()) + { + $iterator->seek($task_index); + } + else + { + $this->install_config->set_finished_task(0); + return; + } + + while ($iterator->valid()) + { + $task = $iterator->current(); + $name = $iterator->key(); + + // Check if we can run the task + if (!$task->is_essential() && !$task->check_requirements()) + { + $this->iohandler->add_log_message(array( + 'SKIP_TASK', + $name, + )); + + $this->install_config->increment_current_task_progress($this->task_step_count[$name]); + } + else + { + // Send progress information + if ($this->allow_progress_bar) + { + $this->iohandler->set_progress( + $task->get_task_lang_name(), + $this->install_config->get_current_task_progress() + ); + + $this->iohandler->send_response(); + } + + $task->run(); + + if ($this->allow_progress_bar) + { + // Only increment progress by one, as if a task has more than one steps + // then that should be incremented in the task itself + $this->install_config->increment_current_task_progress(); + } + } + + $task_index++; + $this->install_config->set_finished_task($task_index); + $iterator->next(); + + // Send progress information + if ($this->allow_progress_bar) + { + $this->iohandler->set_progress( + $task->get_task_lang_name(), + $this->install_config->get_current_task_progress() + ); + } + + $this->iohandler->send_response(); + + // Stop execution if resource limit is reached + if ($iterator->valid() && ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0)) + { + throw new resource_limit_reached_exception(); + } + } + + // Module finished, so clear task progress + $this->install_config->set_finished_task(0); + } + + /** + * Returns the next task's name + * + * @return string Index of the array element of the next task + */ + protected function recover_progress() + { + $progress_array = $this->install_config->get_progress_data(); + return $progress_array['last_task_index']; + } + + /** + * {@inheritdoc} + */ + public function get_step_count() + { + $task_step_count = 0; + $task_class_names = $this->task_collection->get_service_classes(); + + foreach ($task_class_names as $name => $task_class) + { + $step_count = $task_class::get_step_count(); + $task_step_count += $step_count; + $this->task_step_count[$name] = $step_count; + } + + return $task_step_count; + } +} diff --git a/phpBB/phpbb/install/module_interface.php b/phpBB/phpbb/install/module_interface.php new file mode 100644 index 0000000000..a2d61e3958 --- /dev/null +++ b/phpBB/phpbb/install/module_interface.php @@ -0,0 +1,63 @@ +<?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\install; + +/** + * Interface for installer modules + * + * An installer module is a task collection which executes installer tasks. + */ +interface module_interface +{ + /** + * Checks if the execution of the module is essential to install phpBB or it can be skipped + * + * Note: Please note that all the non-essential modules have to implement check_requirements() + * method. + * + * @return bool true if the module is essential, false otherwise + */ + public function is_essential(); + + /** + * Checks requirements for the tasks + * + * Note: Only need to be implemented for non-essential tasks, as essential tasks + * requirements should be checked in the requirements install module. + * + * @return bool true if the task's requirements are met + */ + public function check_requirements(); + + /** + * Executes the task + * + * @return null + */ + public function run(); + + /** + * Returns the number of tasks in the module + * + * @return int + */ + public function get_step_count(); + + /** + * Returns an array to the correct navigation stage + * + * @return array + */ + public function get_navigation_stage_path(); +} diff --git a/phpBB/phpbb/install/task_base.php b/phpBB/phpbb/install/task_base.php new file mode 100644 index 0000000000..b5199be4af --- /dev/null +++ b/phpBB/phpbb/install/task_base.php @@ -0,0 +1,53 @@ +<?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\install; + +/** + * Base class for installer task + */ +abstract class task_base implements task_interface +{ + /** + * @var bool + */ + protected $is_essential; + + /** + * Constructor + * + * @param bool $essential + */ + public function __construct($essential = true) + { + $this->is_essential = $essential; + } + + /** + * {@inheritdoc} + */ + public function is_essential() + { + return $this->is_essential; + } + + /** + * {@inheritdoc} + * + * Note: Overwrite this method if your task is non-essential! + */ + public function check_requirements() + { + return true; + } +} diff --git a/phpBB/phpbb/install/task_interface.php b/phpBB/phpbb/install/task_interface.php new file mode 100644 index 0000000000..794cb16482 --- /dev/null +++ b/phpBB/phpbb/install/task_interface.php @@ -0,0 +1,61 @@ +<?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\install; + +/** + * Interface for installer tasks + */ +interface task_interface +{ + /** + * Returns the number of steps the task contains + * + * This is a helper method to provide a better progress bar for the front-end. + * + * @return int The number of steps that the task contains + */ + static public function get_step_count(); + + /** + * Checks if the task is essential to install phpBB or it can be skipped + * + * Note: Please note that all the non-essential modules have to implement check_requirements() + * method. + * + * @return bool true if the task is essential, false otherwise + */ + public function is_essential(); + + /** + * Checks requirements for the tasks + * + * Note: Only need to be implemented for non-essential tasks, as essential tasks + * requirements should be checked in the requirements install module. + * + * @return bool true if the task's requirements are met + */ + public function check_requirements(); + + /** + * Executes the task + */ + public function run(); + + /** + * Returns the language key of the name of the task + * + * @return string + */ + public function get_task_lang_name(); +} diff --git a/phpBB/phpbb/install/updater_configuration.php b/phpBB/phpbb/install/updater_configuration.php new file mode 100644 index 0000000000..5c1c29f1da --- /dev/null +++ b/phpBB/phpbb/install/updater_configuration.php @@ -0,0 +1,44 @@ +<?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\install; + +use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; + +class updater_configuration implements ConfigurationInterface +{ + + /** + * Generates the configuration tree builder. + * + * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder + */ + public function getConfigTreeBuilder() + { + $treeBuilder = new TreeBuilder(); + $rootNode = $treeBuilder->root('updater'); + $rootNode + ->addDefaultsIfNotSet() + ->children() + ->enumNode('type')->values(['all','db_only'])->defaultValue('all')->end() + ->arrayNode('extensions') + ->prototype('scalar')->end() + ->defaultValue([]) + ->end() + ->end() + ; + + return $treeBuilder; + } +} |