[ticket/13740] Implementation of the new installer framework

[ci skip]

PHPBB3-13740
This commit is contained in:
MateBartus 2015-04-17 23:17:23 +02:00 committed by Mate Bartus
parent 53c5610080
commit 8155205ae7
19 changed files with 2106 additions and 0 deletions

View file

@ -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;
/**
* This exception should be thrown when
*/
class cannot_build_container_exception extends installer_exception
{
}

View file

@ -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;
/**
* This exception should be thrown when
*/
class invalid_dbms_exception extends installer_exception
{
}

View file

@ -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;
/**
* This exception should be thrown when user interaction is inevitable
*/
class user_interaction_required_exception extends installer_exception
{
}

View file

@ -0,0 +1,259 @@
<?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;
/**
* 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 \phpbb\php\ini
*/
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;
/**
* Constructor
*/
public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, \phpbb\php\ini $php_ini, $phpbb_root_path)
{
$this->filesystem = $filesystem;
$this->php_ini = $php_ini;
$this->phpbb_root_path = $phpbb_root_path;
// Set up data arrays
$this->installer_config = array();
$this->system_data = array();
$this->progress_data = array(
'last_task_module_index' => 0,
'last_task_module_name' => '', // Stores the service name of the latest finished module
'last_task_index' => 0,
'last_task_name' => '', // Stores the service name of the latest finished task
);
$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
*
* @return null
*/
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()
{
return ($this->system_data['start_time'] + $this->system_data['max_execution_time']) - time();
}
/**
* Returns remaining memory available for PHP
*
* @return int Remaining memory until reaching the limit
*/
public function get_memory_remaining()
{
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 string $task_service_name Name of the installer task service
* @param int $task_index Index of the task in the task list array
*
* @return null
*/
public function set_finished_task($task_service_name, $task_index)
{
$this->progress_data['last_task_name'] = $task_service_name;
$this->progress_data['last_task_index'] = $task_index;
}
/**
* Set active module
*
* @param string $module_service_name Name of the installer module service
* @param int $module_index Index of the module in the module list array
*
* @return null
*/
public function set_active_module($module_service_name, $module_index)
{
$this->progress_data['last_task_module_name'] = $module_service_name;
$this->progress_data['last_task_module_index'] = $module_index;
}
/**
* Getter for progress data
*
* @return array
*/
public function get_progress_data()
{
return $this->progress_data;
}
/**
* Recovers install configuration from file
*
* @return null
*/
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));
$unserialized_data = unserialize($serialized_data);
$this->installer_config = $unserialized_data['installer_config'];
$this->progress_data = $unserialized_data['progress_data'];
}
/**
* Dumps install configuration to disk
*
* @return null
*/
public function save_config()
{
// Create array to save
$save_array = array(
'installer_config' => $this->installer_config,
'progress_data' => $this->progress_data,
);
// Create file content
$file_content = '<?php // ';
$file_content .= serialize($save_array);
$file_content .= "\n";
// Dump file_content to disk
$fp = fopen($this->install_config_file, 'w');
fwrite($fp, $file_content);
fclose($fp);
}
/**
* Filling up system_data array
*
* @return null
*/
protected function setup_system_data()
{
// Query maximum runtime from php.ini
$execution_time = $this->php_ini->get_int('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'] = time();
// Get memory limit
$this->system_data['memory_limit'] = $this->php_ini->get_bytes('memory_limit');
}
}

View file

@ -0,0 +1,149 @@
<?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;
class container_factory
{
/**
* @var string
*/
protected $phpbb_root_path;
/**
* @var string
*/
protected $php_ext;
/**
* @var \phpbb\request\request
*/
protected $request;
/**
* The full phpBB container
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* Constructor
*
* @param \phpbb\request\request $request Request interface
* @param string $phpbb_root_path Path to phpBB's root
* @param string $php_ext Extension of PHP files
*/
public function __construct(\phpbb\request\request $request, $phpbb_root_path, $php_ext)
{
$this->request = $request;
$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)
{
// 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))
{
$this->build_container();
}
else
{
throw new cannot_build_container_exception();
}
}
return ($service_name === null) ? $this->container : $this->container->get($service_name);
}
/**
* Returns the specified parameter from the container
*
* @param string $param_name
*
* @return mixed
*/
public function get_parameter($param_name)
{
return $this->container->getParameter($param_name);
}
/**
* Build dependency injection container
*/
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;
}
$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;
$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();
}
$this->container = $phpbb_container = $phpbb_container_builder
->with_config($phpbb_config_php_file)
->without_cache()
->without_compiled_container()
->get_container();
// Setting request is required for the compatibility globals as those are generated from
// this container
$this->container->register('request')->setSynthetic(true);
$this->container->set('request', $this->request);
$this->container->compile();
// Restore super globals to previous state
if ($disable_super_globals)
{
$this->request->disable_super_globals();
}
// Get compatibilty globals
require ($this->phpbb_root_path . 'includes/compatibility_globals.' . $this->php_ext);
}
}

View file

@ -0,0 +1,459 @@
<?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;
/**
* 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;
// DBMS supported by phpBB
$this->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' => array(
'LABEL' => 'MS SQL Server 2000+',
'SCHEMA' => 'mssql',
'MODULE' => 'mssql',
'DELIM' => 'GO',
'DRIVER' => 'phpbb\db\driver\mssql',
'AVAILABLE' => true,
'2.0.x' => true,
),
'mssql_odbc'=> array(
'LABEL' => 'MS SQL Server [ ODBC ]',
'SCHEMA' => 'mssql',
'MODULE' => 'odbc',
'DELIM' => 'GO',
'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' => 'GO',
'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,
),
'sqlite' => array(
'LABEL' => 'SQLite',
'SCHEMA' => 'sqlite',
'MODULE' => 'sqlite',
'DELIM' => ';',
'DRIVER' => 'phpbb\db\driver\sqlite',
'AVAILABLE' => true,
'2.0.x' => false,
),
'sqlite3' => array(
'LABEL' => 'SQLite3',
'SCHEMA' => 'sqlite',
'MODULE' => 'sqlite3',
'DELIM' => ';',
'DRIVER' => 'phpbb\db\driver\sqlite3',
'AVAILABLE' => true,
'2.0.x' => false,
),
);
}
/**
* 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')) && $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(mysqli_get_server_info($db->get_db_connect_id()), '4.1.3', '<'))
{
$errors[] = array(
'title' => 'INST_ERR_DB_NO_MYSQLI',
);
}
break;
case 'sqlite':
if (version_compare(sqlite_libversion(), '2.8.2', '<'))
{
$errors[] = array(
'title' => 'INST_ERR_DB_NO_SQLITE',
);
}
break;
case 'sqlite3':
$version = \SQLite3::version();
if (version_compare($version['versionString'], '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;
}
}

View file

@ -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\iohandler;
/**
* Input-Output handler for the AJAX frontend
*/
class ajax_iohandler extends iohandler_base
{
/**
* @var \phpbb\request\request_interface
*/
protected $request;
/**
* @var \phpbb\template\template
*/
protected $template;
/**
* @var string
*/
protected $form;
/**
* Constructor
*
* @param \phpbb\request\request_interface $request HTTP request interface
* @param \phpbb\template\template $template Template engine
*/
public function __construct(\phpbb\request\request_interface $request, \phpbb\template\template $template)
{
$this->request = $request;
$this->template = $template;
$this->form = '';
parent::__construct();
}
/**
* {@inheritdoc}
*/
public function get_input($name, $default, $multibyte = false)
{
return $this->request->variable($name, $default, $multibyte);
}
/**
* {@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 code is pretty ugly... but works
//
$this->template->assign_block_vars('options', array(
'LEGEND' => $this->language->lang($title),
'S_LEGEND' => true,
));
foreach ($form as $input_name => $input_options)
{
if (!isset($input_options['type']))
{
continue;
}
$tpl_ary = array();
$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')))
{
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'];
}
$this->template->assign_block_vars('options', $tpl_ary);
}
$this->template->set_filenames(array(
'form_install' => 'installer_form.html',
));
$this->form = $this->template->assign_display('form_install');
}
/**
* {@inheritdoc}
*/
public function send_response()
{
$json_data_array = $this->prepare_json_array();
$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.
*
* @return array
*/
protected function prepare_json_array()
{
$json_array = array(
'errors' => $this->errors,
'warnings' => $this->warnings,
'logs' => $this->logs,
);
if (!empty($this->form))
{
$json_array['form'] = $this->form;
$this->form = '';
}
$this->errors = array();
$this->warnings = array();
$this->logs = array();
return $json_array;
}
/**
* 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 '';
}
}

View file

@ -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
{
}

View file

@ -0,0 +1,72 @@
<?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;
default:
throw new iohandler_not_implemented_exception();
break;
}
}
}

View file

@ -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\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;
/**
* @var \phpbb\language\language
*/
protected $language;
/**
* Constructor
*/
public function __construct()
{
$this->errors = array();
$this->warnings = array();
$this->logs = array();
}
/**
* Set language service
*
* @param \phpbb\language\language $language
*
* @return null
*/
public function set_language(\phpbb\language\language $language)
{
$this->language = $language;
}
/**
* {@inheritdoc}
*/
public function add_error_message($error_title, $error_description = false)
{
$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);
}
/**
* 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;
}
}

View file

@ -0,0 +1,119 @@
<?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
*/
public function send_response();
/**
* 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 server variable
*
* This function should work the same as request_interterface::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_interterface::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.
*
* @return null
*/
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 error message
* @param string|bool|array $warning_description Description of the error (and possibly guidelines to resolve it),
* or false if the error description is not available
*
* @return null
*/
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 error message
* @param string|bool|array $log_description Description of the error (and possibly guidelines to resolve it),
* or false if the error description is not available
*
* @return null
*/
public function add_log_message($log_title, $log_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)
*
* @return null
*/
public function add_user_form_group($title, $form);
}

View file

@ -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\helper\navigation;
class install_navigation implements navigation_interface
{
public function get()
{
return array(
'install' => array(
'label' => 'INSTALL',
'route' => 'phpbb_installer_install',
'order' => 0,
),
);
}
}

View file

@ -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();
}

View file

@ -0,0 +1,92 @@
<?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;
/**
* Installers navigation provider
*/
class navigation_provider
{
/**
* @var array
*/
private $menu_collection;
/**
* Constructor
*
* @param \phpbb\di\service_collection $plugins
*/
public function __construct(\phpbb\di\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->merge($nav_arry, $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
*/
private function merge(&$array_to_merge, &$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))
{
$this->merge($value, $array_to_merge_into[$key]);
}
else
{
$array_to_merge_into[$key] = $value;
}
}
else
{
$array_to_merge_into[$key] = $value;
}
}
}
}

146
phpBB/install/installer.php Normal file
View file

@ -0,0 +1,146 @@
<?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;
class installer
{
/**
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* @var \phpbb\install\helper\config
*/
protected $install_config;
/**
* @var array
*/
protected $installer_modules;
/**
* Constructor
*
* @param \phpbb\install\helper\config $config Installer config handler
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container Dependency injection container
*/
public function __construct(\phpbb\install\helper\config $config, \Symfony\Component\DependencyInjection\ContainerInterface $container)
{
$this->install_config = $config;
$this->container = $container;
$this->installer_modules = array();
}
/**
* Sets modules to execute
*
* Note: The installer will run modules in the order they are set in
* the array.
*
* @param array $modules Array of module service names
*/
public function set_modules($modules)
{
$modules = (array) $modules;
$this->installer_modules = $modules;
}
/**
* Run phpBB installer
*
* @return null
*/
public function run()
{
// Load install progress
$this->install_config->load_config();
// Recover install progress
$module_index = $this->recover_progress();
$install_finished = false;
try
{
// Run until there are available resources
while ($this->install_config->get_time_remaining() > 0 && $this->install_config->get_memory_remaining() > 0)
{
// Check if module exists, if not the install is completed
if (!isset($this->installer_modules[$module_index]))
{
$install_finished = true;
break;
}
// Log progress
$module_service_name = $this->installer_modules[$module_index];
$this->install_config->set_active_module($module_service_name, $module_index);
// Get module from container
/** @var \phpbb\install\module_interface $module */
$module = $this->container->get($module_service_name);
$module_index++;
// Check if module should be executed
if (!$module->is_essential() && !$module->check_requirements())
{
continue;
}
$module->run();
// Clear task progress
$this->install_config->set_finished_task('', 0);
}
if ($install_finished)
{
die ("install finished");
}
else
{
die ("install memory or time limit reached");
}
}
catch (\phpbb\install\exception\user_interaction_required_exception $e)
{
// @todo handle exception
}
// Save install progress
$this->install_config->save_config();
}
/**
* Recover install progress
*
* @return int Index of the next installer module to execute
*/
protected function recover_progress()
{
$progress_array = $this->install_config->get_progress_data();
$module_service = $progress_array['last_task_module_name'];
$module_index = $progress_array['last_task_module_index'];
if ($this->installer_modules[$module_index] === $module_service)
{
return $module_index;
}
return 0;
}
}

View file

@ -0,0 +1,175 @@
<?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 module
*/
abstract class module_base implements module_interface
{
/**
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* @var \phpbb\install\helper\config
*/
protected $install_config;
/**
* @var \phpbb\install\helper\iohandler\iohandler_interface
*/
protected $iohandler;
/**
* @var bool
*/
protected $is_essential;
/**
* Array of tasks for installer module
*
* @var array
*/
protected $task_collection;
/**
* Installer module constructor
*
* @param array $tasks array of installer tasks for installer module
* @param bool $essential flag that indicates if module is essential or not
*/
public function __construct(array $tasks, $essential = true)
{
$this->task_collection = $tasks;
$this->is_essential = $essential;
}
/**
* Dependency getter
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* @param \phpbb\install\helper\config $config
* @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler
*
* @return null
*/
public function setup(\Symfony\Component\DependencyInjection\ContainerInterface $container, \phpbb\install\helper\config $config, \phpbb\install\helper\iohandler\iohandler_interface $iohandler)
{
$this->container = $container;
$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();
// Run until there are available resources
while ($this->install_config->get_time_remaining() > 0 && $this->install_config->get_memory_remaining() > 0)
{
// Check if task exists
if (!isset($this->task_collection[$task_index]))
{
break;
}
// Recover task to be executed
/** @var \phpbb\install\task_interface $task */
$task = $this->container->get($this->task_collection[$task_index]);
// Iterate to the next task
$task_index++;
// Check if we can run the task
if (!$task->is_essential() && !$task->check_requirements())
{
continue;
}
$task->run();
// Increment progress
if ($this->get_task_count() !== 0)
{
//$this->iohandler->increment_progress();
}
$this->iohandler->send_response();
// Log install progress
$current_task_index = $task_index - 1;
$this->install_config->set_finished_task($this->task_collection[$current_task_index], $current_task_index);
}
}
/**
* Returns the next task's index
*
* @return int index of the array element of the next task
*/
protected function recover_progress()
{
$progress_array = $this->install_config->get_progress_data();
$last_finished_task_name = $progress_array['last_task_name'];
$last_finished_task_index = $progress_array['last_task_index'];
// Check if the data is relevant to this module
if (isset($this->task_collection[$last_finished_task_index]))
{
if ($this->task_collection[$last_finished_task_index] === $last_finished_task_name)
{
// Return the task index of the next task
return $last_finished_task_index + 1;
}
}
// As of now if the progress has not been resolved we assume that it is because
// the task progress belongs to the previous module,
// so just default to the first task
// @todo make module aware of it's service name that way this can be improved
return 0;
}
/**
* {@inheritdoc}
*/
public function get_task_count()
{
return sizeof($this->task_collection);
}
}

View file

@ -0,0 +1,56 @@
<?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_task_count();
}

View file

@ -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}
*
* Overwrite this method if your task is non-essential!
*/
public function check_requirements()
{
return true;
}
}

View file

@ -0,0 +1,47 @@
<?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
{
/**
* 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
*
* @return null
*/
public function run();
}