diff options
Diffstat (limited to 'phpBB/phpbb')
63 files changed, 3566 insertions, 658 deletions
diff --git a/phpBB/phpbb/avatar/driver/driver.php b/phpBB/phpbb/avatar/driver/driver.php index b6fd380bda..c849533166 100644 --- a/phpBB/phpbb/avatar/driver/driver.php +++ b/phpBB/phpbb/avatar/driver/driver.php @@ -30,7 +30,7 @@ abstract class driver implements \phpbb\avatar\driver\driver_interface  	*/  	protected $config; -	/** @var \fastImageSize\fastImageSize */ +	/** @var \FastImageSize\FastImageSize */  	protected $imagesize;  	/** @@ -76,13 +76,13 @@ abstract class driver implements \phpbb\avatar\driver\driver_interface  	* Construct a driver object  	*  	* @param \phpbb\config\config $config phpBB configuration -	* @param \fastImageSize\fastImageSize $imagesize fastImageSize class +	* @param \FastImageSize\FastImageSize $imagesize FastImageSize class  	* @param string $phpbb_root_path Path to the phpBB root  	* @param string $php_ext PHP file extension  	* @param \phpbb\path_helper $path_helper phpBB path helper  	* @param \phpbb\cache\driver\driver_interface $cache Cache driver  	*/ -	public function __construct(\phpbb\config\config $config, \fastImageSize\fastImageSize $imagesize, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null) +	public function __construct(\phpbb\config\config $config, \FastImageSize\FastImageSize $imagesize, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null)  	{  		$this->config = $config;  		$this->imagesize = $imagesize; diff --git a/phpBB/phpbb/avatar/driver/remote.php b/phpBB/phpbb/avatar/driver/remote.php index 90443c9b4e..0526b9184e 100644 --- a/phpBB/phpbb/avatar/driver/remote.php +++ b/phpBB/phpbb/avatar/driver/remote.php @@ -114,13 +114,8 @@ class remote extends \phpbb\avatar\driver\driver  			return false;  		} -		if (!class_exists('fileupload')) -		{ -			include($this->phpbb_root_path . 'includes/functions_upload.' . $this->php_ext); -		} - -		$types = \fileupload::image_types(); -		$extension = strtolower(\filespec::get_extension($url)); +		$types = \phpbb\files\upload::image_types(); +		$extension = strtolower(\phpbb\files\filespec::get_extension($url));  		// Check if this is actually an image  		if ($file_stream = @fopen($url, 'r')) diff --git a/phpBB/phpbb/avatar/driver/upload.php b/phpBB/phpbb/avatar/driver/upload.php index 1939a91cfe..a0c23cb624 100644 --- a/phpBB/phpbb/avatar/driver/upload.php +++ b/phpBB/phpbb/avatar/driver/upload.php @@ -24,43 +24,43 @@ class upload extends \phpbb\avatar\driver\driver  	protected $filesystem;  	/** -	* @var \phpbb\mimetype\guesser -	*/ -	protected $mimetype_guesser; - -	/**  	* @var \phpbb\event\dispatcher_interface  	*/  	protected $dispatcher;  	/** +	 * @var \phpbb\files\factory +	 */ +	protected $files_factory; + +	/**  	* Construct a driver object  	*  	* @param \phpbb\config\config $config phpBB configuration  	* @param string $phpbb_root_path Path to the phpBB root  	* @param string $php_ext PHP file extension -	* @param \phpbb\filesystem\filesystem_interface phpBB filesystem helper +	* @param \phpbb\filesystem\filesystem_interface $filesystem phpBB filesystem helper  	* @param \phpbb\path_helper $path_helper phpBB path helper -	* @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser  	* @param \phpbb\event\dispatcher_interface $dispatcher phpBB Event dispatcher object +	* @param \phpbb\files\factory $files_factory File classes factory  	* @param \phpbb\cache\driver\driver_interface $cache Cache driver  	*/ -	public function __construct(\phpbb\config\config $config, $phpbb_root_path, $php_ext, \phpbb\filesystem\filesystem_interface $filesystem, \phpbb\path_helper $path_helper, \phpbb\mimetype\guesser $mimetype_guesser, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\cache\driver\driver_interface $cache = null) +	public function __construct(\phpbb\config\config $config, $phpbb_root_path, $php_ext, \phpbb\filesystem\filesystem_interface $filesystem, \phpbb\path_helper $path_helper, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\files\factory $files_factory, \phpbb\cache\driver\driver_interface $cache = null)  	{  		$this->config = $config;  		$this->phpbb_root_path = $phpbb_root_path;  		$this->php_ext = $php_ext;  		$this->filesystem = $filesystem;  		$this->path_helper = $path_helper; -		$this->mimetype_guesser = $mimetype_guesser;  		$this->dispatcher = $dispatcher; +		$this->files_factory = $files_factory;  		$this->cache = $cache;  	}  	/**  	* {@inheritdoc}  	*/ -	public function get_data($row, $ignore_config = false) +	public function get_data($row)  	{  		$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $this->path_helper->get_web_root_path(); @@ -99,19 +99,24 @@ class upload extends \phpbb\avatar\driver\driver  			return false;  		} -		if (!class_exists('fileupload')) -		{ -			include($this->phpbb_root_path . 'includes/functions_upload.' . $this->php_ext); -		} - -		$upload = new \fileupload($this->filesystem, 'AVATAR_', $this->allowed_extensions, $this->config['avatar_filesize'], $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], (isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false)); +		/** @var \phpbb\files\upload $upload */ +		$upload = $this->files_factory->get('upload') +			->set_error_prefix('AVATAR_') +			->set_allowed_extensions($this->allowed_extensions) +			->set_max_filesize($this->config['avatar_filesize']) +			->set_allowed_dimensions( +				$this->config['avatar_min_width'], +				$this->config['avatar_min_height'], +				$this->config['avatar_max_width'], +				$this->config['avatar_max_height']) +			->set_disallowed_content((isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false));  		$url = $request->variable('avatar_upload_url', '');  		$upload_file = $request->file('avatar_upload_file');  		if (!empty($upload_file['name']))  		{ -			$file = $upload->form_upload('avatar_upload_file', $this->mimetype_guesser); +			$file = $upload->handle_upload('files.types.form', 'avatar_upload_file');  		}  		else if (!empty($this->config['allow_avatar_remote_upload']) && !empty($url))  		{ @@ -141,7 +146,7 @@ class upload extends \phpbb\avatar\driver\driver  				return false;  			} -			$file = $upload->remote_upload($url, $this->mimetype_guesser); +			$file = $upload->handle_upload('files.types.remote', $url);  		}  		else  		{ diff --git a/phpBB/phpbb/composer.json b/phpBB/phpbb/composer.json index 175be4b0ab..8241091dc1 100644 --- a/phpBB/phpbb/composer.json +++ b/phpBB/phpbb/composer.json @@ -22,6 +22,6 @@  		"classmap": [""]  	},  	"require": { -		"php": ">=5.3.9" +		"php": ">=5.4"      }  } diff --git a/phpBB/phpbb/console/application.php b/phpBB/phpbb/console/application.php index 2c69a3cc73..dc9b8016b2 100644 --- a/phpBB/phpbb/console/application.php +++ b/phpBB/phpbb/console/application.php @@ -13,6 +13,7 @@  namespace phpbb\console; +use Symfony\Component\Console\Input\InputDefinition;  use Symfony\Component\Console\Shell;  use Symfony\Component\Console\Input\InputInterface;  use Symfony\Component\Console\Input\InputOption; @@ -49,12 +50,7 @@ class application extends \Symfony\Component\Console\Application  	{  		$input_definition = parent::getDefaultInputDefinition(); -		$input_definition->addOption(new InputOption( -			'safe-mode', -			null, -			InputOption::VALUE_NONE, -			$this->language->lang('CLI_DESCRIPTION_OPTION_SAFE_MODE') -		)); +		$this->register_global_options($input_definition);  		return $input_definition;  	} @@ -76,12 +72,20 @@ class application extends \Symfony\Component\Console\Application  			return parent::getHelp();  		} -		$this->getDefinition()->addOption(new InputOption( -			'--shell', -			'-s', -			InputOption::VALUE_NONE, -			$this->language->lang('CLI_DESCRIPTION_OPTION_SHELL') -		)); +		try +		{ +			$definition = $this->getDefinition(); +			$definition->addOption(new InputOption( +				'--shell', +				'-s', +				InputOption::VALUE_NONE, +				$this->language->lang('CLI_DESCRIPTION_OPTION_SHELL') +			)); +		} +		catch (\LogicException $e) +		{ +			// Do nothing +		}  		return parent::getHelp();  	} @@ -117,4 +121,33 @@ class application extends \Symfony\Component\Console\Application  		return parent::doRun($input, $output);  	} + +	/** +	 * Register global options +	 * +	 * @param InputDefinition $definition An InputDefinition instance +	 */ +	protected function register_global_options(InputDefinition $definition) +	{ +		try +		{ +			$definition->addOption(new InputOption( +				'safe-mode', +				null, +				InputOption::VALUE_NONE, +				$this->language->lang('CLI_DESCRIPTION_OPTION_SAFE_MODE') +			)); + +			$definition->addOption(new InputOption( +				'env', +				'e', +				InputOption::VALUE_REQUIRED, +				$this->language->lang('CLI_DESCRIPTION_OPTION_ENV') +			)); +		} +		catch (\LogicException $e) +		{ +			// Do nothing +		} +	}  } diff --git a/phpBB/phpbb/console/command/cron/run.php b/phpBB/phpbb/console/command/cron/run.php index da185b81b3..dea6493007 100644 --- a/phpBB/phpbb/console/command/cron/run.php +++ b/phpBB/phpbb/console/command/cron/run.php @@ -51,6 +51,7 @@ class run extends \phpbb\console\command\command  		$this  			->setName('cron:run')  			->setDescription($this->user->lang('CLI_DESCRIPTION_CRON_RUN')) +			->setHelp($this->user->lang('CLI_HELP_CRON_RUN'))  			->addArgument('name', InputArgument::OPTIONAL, $this->user->lang('CLI_DESCRIPTION_CRON_RUN_ARGUMENT_1'))  		;  	} diff --git a/phpBB/phpbb/console/command/db/list_command.php b/phpBB/phpbb/console/command/db/list_command.php new file mode 100644 index 0000000000..708107b592 --- /dev/null +++ b/phpBB/phpbb/console/command/db/list_command.php @@ -0,0 +1,73 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +namespace phpbb\console\command\db; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class list_command extends \phpbb\console\command\db\migration_command +{ +	protected function configure() +	{ +		$this +			->setName('db:list') +			->setDescription($this->user->lang('CLI_DESCRIPTION_DB_LIST')) +			->addOption( +				'available', +				'u', +				InputOption::VALUE_NONE, +				$this->user->lang('CLI_MIGRATIONS_ONLY_AVAILABLE') +			) +		; +	} + +	protected function execute(InputInterface $input, OutputInterface $output) +	{ +		$show_installed = !$input->getOption('available'); +		$installed = $available = array(); + +		foreach ($this->load_migrations() as $name) +		{ +			if ($this->migrator->migration_state($name) !== false) +			{ +				$installed[] = $name; +			} +			else +			{ +				$available[] = $name; +			} +		} + +		if ($show_installed) +		{ +			$output->writeln('<info>' . $this->user->lang('CLI_MIGRATIONS_INSTALLED') . $this->user->lang('COLON') . '</info>'); +			$output->writeln($installed); + +			if (empty($installed)) +			{ +				$output->writeln($this->user->lang('CLI_MIGRATIONS_EMPTY')); +			} + +			$output->writeln(''); +		} + +		$output->writeln('<info>' . $this->user->lang('CLI_MIGRATIONS_AVAILABLE') . $this->user->lang('COLON') . '</info>'); +		$output->writeln($available); + +		if (empty($available)) +		{ +			$output->writeln($this->user->lang('CLI_MIGRATIONS_EMPTY')); +		} +	} +} diff --git a/phpBB/phpbb/console/command/db/migrate.php b/phpBB/phpbb/console/command/db/migrate.php index 2490bf1310..43029b7458 100644 --- a/phpBB/phpbb/console/command/db/migrate.php +++ b/phpBB/phpbb/console/command/db/migrate.php @@ -15,20 +15,8 @@ namespace phpbb\console\command\db;  use Symfony\Component\Console\Input\InputInterface;  use Symfony\Component\Console\Output\OutputInterface; -class migrate extends \phpbb\console\command\command +class migrate extends \phpbb\console\command\db\migration_command  { -	/** @var \phpbb\db\migrator */ -	protected $migrator; - -	/** @var \phpbb\extension\manager */ -	protected $extension_manager; - -	/** @var \phpbb\config\config */ -	protected $config; - -	/** @var \phpbb\cache\service */ -	protected $cache; -  	/** @var \phpbb\log\log */  	protected $log; @@ -40,14 +28,10 @@ class migrate extends \phpbb\console\command\command  	function __construct(\phpbb\user $user, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache, \phpbb\log\log $log, \phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path)  	{ -		$this->migrator = $migrator; -		$this->extension_manager = $extension_manager; -		$this->config = $config; -		$this->cache = $cache;  		$this->log = $log;  		$this->filesystem = $filesystem;  		$this->phpbb_root_path = $phpbb_root_path; -		parent::__construct($user); +		parent::__construct($user, $migrator, $extension_manager, $config, $cache);  		$this->user->add_lang(array('common', 'install', 'migrator'));  	} @@ -91,21 +75,4 @@ class migrate extends \phpbb\console\command\command  		$this->finalise_update();  		$output->writeln($this->user->lang['DATABASE_UPDATE_COMPLETE']);  	} - -	protected function load_migrations() -	{ -		$migrations = $this->extension_manager -			->get_finder() -			->core_path('phpbb/db/migration/data/') -			->extension_directory('/migrations') -			->get_classes(); - -		$this->migrator->set_migrations($migrations); -	} - -	protected function finalise_update() -	{ -		$this->cache->purge(); -		$this->config->increment('assets_version', 1); -	}  } diff --git a/phpBB/phpbb/console/command/db/migration_command.php b/phpBB/phpbb/console/command/db/migration_command.php new file mode 100644 index 0000000000..d44ef8c5cb --- /dev/null +++ b/phpBB/phpbb/console/command/db/migration_command.php @@ -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\console\command\db; + +abstract class migration_command extends \phpbb\console\command\command +{ +	/** @var \phpbb\db\migrator */ +	protected $migrator; + +	/** @var \phpbb\extension\manager */ +	protected $extension_manager; + +	/** @var \phpbb\config\config */ +	protected $config; + +	/** @var \phpbb\cache\service */ +	protected $cache; + +	function __construct(\phpbb\user $user, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache) +	{ +		$this->migrator = $migrator; +		$this->extension_manager = $extension_manager; +		$this->config = $config; +		$this->cache = $cache; +		parent::__construct($user); +	} + +	protected function load_migrations() +	{ +		$migrations = $this->extension_manager +			->get_finder() +			->core_path('phpbb/db/migration/data/') +			->extension_directory('/migrations') +			->get_classes(); + +		$this->migrator->set_migrations($migrations); + +		return $migrations; +	} + +	protected function finalise_update() +	{ +		$this->cache->purge(); +		$this->config->increment('assets_version', 1); +	} +} diff --git a/phpBB/phpbb/console/command/db/revert.php b/phpBB/phpbb/console/command/db/revert.php new file mode 100644 index 0000000000..838640968e --- /dev/null +++ b/phpBB/phpbb/console/command/db/revert.php @@ -0,0 +1,83 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ +namespace phpbb\console\command\db; + +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class revert extends \phpbb\console\command\db\migration_command +{ +	/** @var string phpBB root path */ +	protected $phpbb_root_path; + +	/** @var  \phpbb\filesystem\filesystem_interface */ +	protected $filesystem; + +	function __construct(\phpbb\user $user, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache, \phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path) +	{ +		$this->filesystem = $filesystem; +		$this->phpbb_root_path = $phpbb_root_path; +		parent::__construct($user, $migrator, $extension_manager, $config, $cache); +		$this->user->add_lang(array('common', 'migrator')); +	} + +	protected function configure() +	{ +		$this +			->setName('db:revert') +			->setDescription($this->user->lang('CLI_DESCRIPTION_DB_REVERT')) +			->addArgument( +				'name', +				InputArgument::REQUIRED, +				$this->user->lang('CLI_MIGRATION_NAME') +			) +		; +	} + +	protected function execute(InputInterface $input, OutputInterface $output) +	{ +		$name = str_replace('/', '\\', $input->getArgument('name')); + +		$this->migrator->set_output_handler(new \phpbb\db\log_wrapper_migrator_output_handler($this->user, new console_migrator_output_handler($this->user, $output), $this->phpbb_root_path . 'store/migrations_' . time() . '.log', $this->filesystem)); + +		$this->cache->purge(); + +		if (!in_array($name, $this->load_migrations())) +		{ +			$output->writeln('<error>' . $this->user->lang('MIGRATION_NOT_VALID', $name) . '</error>'); +			return 1; +		} +		else if ($this->migrator->migration_state($name) === false) +		{ +			$output->writeln('<error>' . $this->user->lang('MIGRATION_NOT_INSTALLED', $name) . '</error>'); +			return 1; +		} + +		try +		{ +			while ($this->migrator->migration_state($name) !== false) +			{ +				$this->migrator->revert($name); +			} +		} +		catch (\phpbb\db\migration\exception $e) +		{ +			$output->writeln('<error>' . $e->getLocalisedMessage($this->user) . '</error>'); +			$this->finalise_update(); +			return 1; +		} + +		$this->finalise_update(); +	} +} diff --git a/phpBB/phpbb/controller/helper.php b/phpBB/phpbb/controller/helper.php index 3782512fa4..e98de0e771 100644 --- a/phpBB/phpbb/controller/helper.php +++ b/phpBB/phpbb/controller/helper.php @@ -16,7 +16,6 @@ namespace phpbb\controller;  use Symfony\Component\HttpFoundation\JsonResponse;  use Symfony\Component\HttpFoundation\Response;  use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Component\Routing\RequestContext;  /**  * Controller helper class, contains methods that do things for controllers @@ -41,12 +40,6 @@ class helper  	*/  	protected $config; -	/** -	 * phpBB router -	 * @var \phpbb\routing\router -	 */ -	protected $router; -  	/* @var \phpbb\symfony_request */  	protected $symfony_request; @@ -54,21 +47,9 @@ class helper  	protected $request;  	/** -	* @var \phpbb\filesystem\filesystem_interface The filesystem object -	*/ -	protected $filesystem; - -	/** -	* phpBB root path -	* @var string -	*/ -	protected $phpbb_root_path; - -	/** -	* PHP file extension -	* @var string -	*/ -	protected $php_ext; +	 * @var \phpbb\routing\helper +	 */ +	protected $routing_helper;  	/**  	* Constructor @@ -76,24 +57,18 @@ class helper  	* @param \phpbb\template\template $template Template object  	* @param \phpbb\user $user User object  	* @param \phpbb\config\config $config Config object -	* @param \phpbb\routing\router $router phpBB router  	* @param \phpbb\symfony_request $symfony_request Symfony Request object  	* @param \phpbb\request\request_interface $request phpBB request object -	* @param \phpbb\filesystem\filesystem_interface $filesystem The filesystem object -	* @param string $phpbb_root_path phpBB root path -	* @param string $php_ext PHP file extension +	* @param \phpbb\routing\helper $routing_helper Helper to generate the routes  	*/ -	public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\routing\router $router, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path, $php_ext) +	public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\routing\helper $routing_helper)  	{  		$this->template = $template;  		$this->user = $user;  		$this->config = $config; -		$this->router = $router;  		$this->symfony_request = $symfony_request;  		$this->request = $request; -		$this->filesystem = $filesystem; -		$this->phpbb_root_path = $phpbb_root_path; -		$this->php_ext = $php_ext; +		$this->routing_helper = $routing_helper;  	}  	/** @@ -103,12 +78,14 @@ class helper  	* @param string $page_title The title of the page to output  	* @param int $status_code The status code to be sent to the page header  	* @param bool $display_online_list Do we display online users list +	* @param int $item_id Restrict online users to item id +	* @param string $item Restrict online users to a certain session item, e.g. forum for session_forum_id  	*  	* @return Response object containing rendered page  	*/ -	public function render($template_file, $page_title = '', $status_code = 200, $display_online_list = false) +	public function render($template_file, $page_title = '', $status_code = 200, $display_online_list = false, $item_id = 0, $item = 'forum')  	{ -		page_header($page_title, $display_online_list); +		page_header($page_title, $display_online_list, $item_id, $item);  		$this->template->set_filenames(array(  			'body'	=> $template_file, @@ -131,61 +108,7 @@ class helper  	*/  	public function route($route, array $params = array(), $is_amp = true, $session_id = false, $reference_type = UrlGeneratorInterface::ABSOLUTE_PATH)  	{ -		$anchor = ''; -		if (isset($params['#'])) -		{ -			$anchor = '#' . $params['#']; -			unset($params['#']); -		} - -		$context = new RequestContext(); -		$context->fromRequest($this->symfony_request); - -		$script_name = $this->symfony_request->getScriptName(); -		$page_name = substr($script_name, -1, 1) == '/' ? '' : utf8_basename($script_name); - -		$base_url = $context->getBaseUrl(); - -		// Append page name if base URL does not contain it -		if (!empty($page_name) && strpos($base_url, '/' . $page_name) === false) -		{ -			$base_url .= '/' . $page_name; -		} - -		// If enable_mod_rewrite is false we need to replace the current front-end by app.php, otherwise we need to remove it. -		$base_url = str_replace('/' . $page_name, empty($this->config['enable_mod_rewrite']) ? '/app.' . $this->php_ext : '', $base_url); - -		// We need to update the base url to move to the directory of the app.php file if the current script is not app.php -		if ($page_name !== 'app.php') -		{ -			if (empty($this->config['enable_mod_rewrite'])) -			{ -				$base_url = str_replace('/app.' . $this->php_ext, '/' . $this->phpbb_root_path . 'app.' . $this->php_ext, $base_url); -			} -			else -			{ -				$base_url .= preg_replace(get_preg_expression('path_remove_dot_trailing_slash'), '$2', $this->phpbb_root_path); -			} -		} - -		$base_url = $this->request->escape($this->filesystem->clean_path($base_url), true); - -		$context->setBaseUrl($base_url); - -		$this->router->setContext($context); -		$route_url = $this->router->generate($route, $params, $reference_type); - -		if ($is_amp) -		{ -			$route_url = str_replace(array('&', '&'), array('&', '&'), $route_url); -		} - -		if ($reference_type === UrlGeneratorInterface::RELATIVE_PATH && empty($this->config['enable_mod_rewrite'])) -		{ -			$route_url = 'app.' . $this->php_ext . '/' . $route_url; -		} - -		return append_sid($route_url . $anchor, false, $is_amp, $session_id, true); +		return $this->routing_helper->route($route, $params, $is_amp, $session_id, $reference_type);  	}  	/** diff --git a/phpBB/phpbb/db/driver/sqlite3.php b/phpBB/phpbb/db/driver/sqlite3.php index f5c2dd225b..b7f6e60337 100644 --- a/phpBB/phpbb/db/driver/sqlite3.php +++ b/phpBB/phpbb/db/driver/sqlite3.php @@ -48,6 +48,7 @@ class sqlite3 extends \phpbb\db\driver\driver  		try  		{  			$this->dbo = new \SQLite3($this->server, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE); +			$this->dbo->busyTimeout(60000);  			$this->db_connect_id = true;  		}  		catch (\Exception $e) diff --git a/phpBB/phpbb/db/migration/data/v31x/v316.php b/phpBB/phpbb/db/migration/data/v31x/v316.php new file mode 100644 index 0000000000..cec113eff2 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/v316.php @@ -0,0 +1,31 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class v316 extends \phpbb\db\migration\migration +{ +	static public function depends_on() +	{ +		return array( +			'\phpbb\db\migration\data\v31x\v316rc1', +		); +	} + +	public function update_data() +	{ +		return array( +			array('config.update', array('version', '3.1.6')), +		); +	} +} diff --git a/phpBB/phpbb/db/migration/data/v320/font_awesome_update.php b/phpBB/phpbb/db/migration/data/v320/font_awesome_update.php new file mode 100644 index 0000000000..6ffaf18b4a --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v320/font_awesome_update.php @@ -0,0 +1,29 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v320; + +class font_awesome_update extends \phpbb\db\migration\migration +{ +	public function effectively_installed() +	{ +		return isset($this->config['load_font_awesome_url']); +	} + +	public function update_data() +	{ +		return array( +			array('config.add', array('load_font_awesome_url', 'https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css')), +		); +	} +} diff --git a/phpBB/phpbb/db/migration/data/v320/log_post_id.php b/phpBB/phpbb/db/migration/data/v320/log_post_id.php new file mode 100644 index 0000000000..0f155d543c --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v320/log_post_id.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\db\migration\data\v320; + +class log_post_id extends \phpbb\db\migration\migration +{ +	static public function depends_on() +	{ +		return array('\phpbb\db\migration\data\v310\dev'); +	} + +	public function update_schema() +	{ +		return array( +			'add_columns'        => array( +				$this->table_prefix . 'log'        => array( +					'post_id'    => array('UINT', 0, 'after' => 'topic_id'), +				), +			), +		); +	} + +	public function revert_schema() +	{ +		return array( +			'drop_columns'        => array( +				$this->table_prefix . 'log'        => array( +					'post_id', +				), +			), +		); +	} +} diff --git a/phpBB/phpbb/db/migration/data/v310/notifications_board.php b/phpBB/phpbb/db/migration/data/v320/notifications_board.php index 525d94e984..fd9f1a2ad6 100644 --- a/phpBB/phpbb/db/migration/data/v310/notifications_board.php +++ b/phpBB/phpbb/db/migration/data/v320/notifications_board.php @@ -11,7 +11,7 @@  *  */ -namespace phpbb\db\migration\data\v310; +namespace phpbb\db\migration\data\v320;  class notifications_board extends \phpbb\db\migration\migration  { diff --git a/phpBB/phpbb/db/migration/data/v320/remove_outdated_media.php b/phpBB/phpbb/db/migration/data/v320/remove_outdated_media.php new file mode 100644 index 0000000000..59208be4dc --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v320/remove_outdated_media.php @@ -0,0 +1,83 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v320; + +class remove_outdated_media extends \phpbb\db\migration\migration +{ +	protected $cat_id = array( +			ATTACHMENT_CATEGORY_WM, +			ATTACHMENT_CATEGORY_RM, +			ATTACHMENT_CATEGORY_QUICKTIME, +		); + +	public function update_data() +	{ +		return array( +			array('custom', array(array($this, 'change_extension_group'))), +		); +	} + +	public function change_extension_group() +	{ +		// select group ids of outdated media +		$sql = 'SELECT group_id +			FROM ' . EXTENSION_GROUPS_TABLE . ' +			WHERE ' . $this->db->sql_in_set('cat_id', $this->cat_id); +		$result = $this->db->sql_query($sql); + +		$group_ids = array(); +		while ($group_id = (int) $this->db->sql_fetchfield('group_id')) +		{ +			$group_ids[] = $group_id; +		} +		$this->db->sql_freeresult($result); + +		// nothing to do, admin has removed all the outdated media extension groups +		if (empty($group_ids)) +		{ +			return true; +		} + +		// get the group id of downloadable files +		$sql = 'SELECT group_id +			FROM ' . EXTENSION_GROUPS_TABLE . " +			WHERE group_name = 'DOWNLOADABLE_FILES'"; +		$result = $this->db->sql_query($sql); +		$download_id = (int) $this->db->sql_fetchfield('group_id'); +		$this->db->sql_freeresult($result); + +		if (empty($download_id)) +		{ +			$sql = 'UPDATE ' . EXTENSIONS_TABLE . ' +				SET group_id = 0 +				WHERE ' . $this->db->sql_in_set('group_id', $group_ids); +		} +		else +		{ +			// move outdated media extensions to downloadable files +			$sql = 'UPDATE ' . EXTENSIONS_TABLE . " +				SET group_id = $download_id" . ' +				WHERE ' . $this->db->sql_in_set('group_id', $group_ids); +		} + +		$result = $this->db->sql_query($sql); +		$this->db->sql_freeresult($result); + +		// delete the now empty, outdated media extension groups +		$sql = 'DELETE FROM ' . EXTENSION_GROUPS_TABLE . ' +			WHERE ' . $this->db->sql_in_set('group_id', $group_ids); +		$result = $this->db->sql_query($sql); +		$this->db->sql_freeresult($result); +	} +} diff --git a/phpBB/phpbb/db/migrator.php b/phpBB/phpbb/db/migrator.php index 6902913c64..18c6403c07 100644 --- a/phpBB/phpbb/db/migrator.php +++ b/phpBB/phpbb/db/migrator.php @@ -416,6 +416,9 @@ class migrator  		if ($state['migration_data_done'])  		{ +			$this->output_handler->write(array('MIGRATION_REVERT_DATA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); +			$elapsed_time = microtime(true); +  			if ($state['migration_data_state'] !== 'revert_data')  			{  				$result = $this->process_data_step($migration->update_data(), $state['migration_data_state'], true); @@ -431,9 +434,22 @@ class migrator  			}  			$this->set_migration_state($name, $state); + +			$elapsed_time = microtime(true) - $elapsed_time; +			if ($state['migration_data_done']) +			{ +				$this->output_handler->write(array('MIGRATION_REVERT_DATA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL); +			} +			else +			{ +				$this->output_handler->write(array('MIGRATION_REVERT_DATA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE); +			}  		}  		else if ($state['migration_schema_done'])  		{ +			$this->output_handler->write(array('MIGRATION_REVERT_SCHEMA_RUNNING', $name), migrator_output_handler_interface::VERBOSITY_VERBOSE); +			$elapsed_time = microtime(true); +  			$steps = $this->helper->get_schema_steps($migration->revert_schema());  			$result = $this->process_data_step($steps, $state['migration_data_state']); @@ -448,6 +464,9 @@ class migrator  				unset($this->migration_state[$name]);  			} + +			$elapsed_time = microtime(true) - $elapsed_time; +			$this->output_handler->write(array('MIGRATION_REVERT_SCHEMA_DONE', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_NORMAL);  		}  		return true; diff --git a/phpBB/phpbb/di/container_builder.php b/phpBB/phpbb/di/container_builder.php index c9adbe7d63..fb391760ce 100644 --- a/phpBB/phpbb/di/container_builder.php +++ b/phpBB/phpbb/di/container_builder.php @@ -465,7 +465,7 @@ class container_builder  				'core.root_path'     => $this->phpbb_root_path,  				'core.php_ext'       => $this->php_ext,  				'core.environment'   => $this->get_environment(), -				'core.debug'         => DEBUG, +				'core.debug'         => defined('DEBUG') ? DEBUG : false,  			),  			$this->get_env_parameters()  		); diff --git a/phpBB/phpbb/feed/attachments_base.php b/phpBB/phpbb/feed/attachments_base.php index 04812f1570..b14dafe15a 100644 --- a/phpBB/phpbb/feed/attachments_base.php +++ b/phpBB/phpbb/feed/attachments_base.php @@ -16,7 +16,7 @@ namespace phpbb\feed;  /**  * Abstract class for feeds displaying attachments  */ -abstract class attachments_base extends \phpbb\feed\base +abstract class attachments_base extends base  {  	/**  	* Attachments that may be displayed diff --git a/phpBB/phpbb/feed/base.php b/phpBB/phpbb/feed/base.php index 322e2ee9f1..188d229515 100644 --- a/phpBB/phpbb/feed/base.php +++ b/phpBB/phpbb/feed/base.php @@ -1,27 +1,27 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */  namespace phpbb\feed;  /** -* Base class with some generic functions and settings. -*/ -abstract class base + * Base class with some generic functions and settings. + */ +abstract class base implements feed_interface  {  	/** -	* Feed helper object -	* @var \phpbb\feed\helper -	*/ +	 * Feed helper object +	 * @var \phpbb\feed\helper +	 */  	protected $helper;  	/** @var \phpbb\config\config */ @@ -43,46 +43,46 @@ abstract class base  	protected $phpEx;  	/** -	* SQL Query to be executed to get feed items -	*/ -	var $sql = array(); +	 * SQL Query to be executed to get feed items +	 */ +	protected $sql = array();  	/** -	* Keys specified for retrieval of title, content, etc. -	*/ -	var $keys = array(); +	 * Keys specified for retrieval of title, content, etc. +	 */ +	protected $keys = array();  	/** -	* Number of items to fetch. Usually overwritten by $config['feed_something'] -	*/ -	var $num_items = 15; +	 * Number of items to fetch. Usually overwritten by $config['feed_something'] +	 */ +	protected $num_items = 15;  	/** -	* Separator for title elements to separate items (for example forum / topic) -	*/ -	var $separator = "\xE2\x80\xA2"; // • +	 * Separator for title elements to separate items (for example forum / topic) +	 */ +	protected $separator = "\xE2\x80\xA2"; // •  	/** -	* Separator for the statistics row (Posted by, post date, replies, etc.) -	*/ -	var $separator_stats = "\xE2\x80\x94"; // — +	 * Separator for the statistics row (Posted by, post date, replies, etc.) +	 */ +	protected $separator_stats = "\xE2\x80\x94"; // —  	/** @var mixed Query result handle */  	protected $result;  	/** -	* Constructor -	* -	* @param \phpbb\feed\helper					$helper		Feed helper -	* @param \phpbb\config\config				$config		Config object -	* @param \phpbb\db\driver\driver_interface	$db			Database connection -	* @param \phpbb\cache\driver\driver_interface	$cache	Cache object -	* @param \phpbb\user						$user		User object -	* @param \phpbb\auth\auth					$auth		Auth object -	* @param \phpbb\content_visibility			$content_visibility		Auth object -	* @param string								$phpEx		php file extension -	*/ -	function __construct(\phpbb\feed\helper $helper, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache, \phpbb\user $user, \phpbb\auth\auth $auth, \phpbb\content_visibility $content_visibility, $phpEx) +	 * Constructor +	 * +	 * @param \phpbb\feed\helper					$helper		Feed helper +	 * @param \phpbb\config\config				$config		Config object +	 * @param \phpbb\db\driver\driver_interface	$db			Database connection +	 * @param \phpbb\cache\driver\driver_interface	$cache	Cache object +	 * @param \phpbb\user						$user		User object +	 * @param \phpbb\auth\auth					$auth		Auth object +	 * @param \phpbb\content_visibility			$content_visibility		Auth object +	 * @param string								$phpEx		php file extension +	 */ +	public function __construct(\phpbb\feed\helper $helper, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache, \phpbb\user $user, \phpbb\auth\auth $auth, \phpbb\content_visibility $content_visibility, $phpEx)  	{  		$this->config = $config;  		$this->helper = $helper; @@ -109,23 +109,23 @@ abstract class base  	}  	/** -	* Set keys. -	*/ -	function set_keys() +	 * {@inheritdoc} +	 */ +	public function set_keys()  	{  	}  	/** -	* Open feed -	*/ -	function open() +	 * {@inheritdoc} +	 */ +	public function open()  	{  	}  	/** -	* Close feed -	*/ -	function close() +	 * {@inheritdoc} +	 */ +	public function close()  	{  		if (!empty($this->result))  		{ @@ -134,28 +134,47 @@ abstract class base  	}  	/** -	* Set key -	* -	* @param string $key Key -	* @param mixed $value Value -	*/ -	function set($key, $value) +	 * {@inheritdoc} +	 */ +	public function set($key, $value)  	{  		$this->keys[$key] = $value;  	}  	/** -	* Get key -	* -	* @param string $key Key -	* @return mixed -	*/ -	function get($key) +	 * {@inheritdoc} +	 */ +	public function get($key)  	{  		return (isset($this->keys[$key])) ? $this->keys[$key] : null;  	} -	function get_readable_forums() +	/** +	 * {@inheritdoc} +	 */ +	public function get_item() +	{ +		if (!isset($this->result)) +		{ +			if (!$this->get_sql()) +			{ +				return false; +			} + +			// Query database +			$sql = $this->db->sql_build_query('SELECT', $this->sql); +			$this->result = $this->db->sql_query_limit($sql, $this->num_items); +		} + +		return $this->db->sql_fetchrow($this->result); +	} + +	/** +	 * Returns the ids of the forums readable by the current user. +	 * +	 * @return int[] +	 */ +	protected function get_readable_forums()  	{  		static $forum_ids; @@ -167,7 +186,12 @@ abstract class base  		return $forum_ids;  	} -	function get_moderator_approve_forums() +	/** +	 * Returns the ids of the forum for which the current user can approve the post in the moderation queue. +	 * +	 * @return int[] +	 */ +	protected function get_moderator_approve_forums()  	{  		static $forum_ids; @@ -179,7 +203,13 @@ abstract class base  		return $forum_ids;  	} -	function is_moderator_approve_forum($forum_id) +	/** +	 * Returns true if the current user can approve the post of the given forum +	 * +	 * @param int $forum_id Forum id to check +	 * @return bool +	 */ +	protected function is_moderator_approve_forum($forum_id)  	{  		static $forum_ids; @@ -191,7 +221,12 @@ abstract class base  		return (isset($forum_ids[$forum_id])) ? true : false;  	} -	function get_excluded_forums() +	/** +	 * Returns the ids of the forum excluded from the feeds +	 * +	 * @return int[] +	 */ +	protected function get_excluded_forums()  	{  		static $forum_ids; @@ -218,36 +253,35 @@ abstract class base  		return $forum_ids;  	} -	function is_excluded_forum($forum_id) +	/** +	 * Returns true if the given id is in the excluded forums list. +	 * +	 * @param int $forum_id Id to check +	 * @return bool +	 */ +	protected function is_excluded_forum($forum_id)  	{  		$forum_ids = $this->get_excluded_forums();  		return isset($forum_ids[$forum_id]) ? true : false;  	} -	function get_passworded_forums() +	/** +	 * Returns all password protected forum ids the current user is currently NOT authenticated for. +	 * +	 * @return array     Array of forum ids +	 */ +	protected function get_passworded_forums()  	{  		return $this->user->get_passworded_forums();  	} -	function get_item() -	{ -		if (!isset($this->result)) -		{ -			if (!$this->get_sql()) -			{ -				return false; -			} - -			// Query database -			$sql = $this->db->sql_build_query('SELECT', $this->sql); -			$this->result = $this->db->sql_query_limit($sql, $this->num_items); -		} - -		return $this->db->sql_fetchrow($this->result); -	} - -	function user_viewprofile($row) +	/** +	 * Returns the link to the user profile. +	 * +	 * @return string +	 */ +	protected function user_viewprofile($row)  	{  		$author_id = (int) $row[$this->get('author_id')]; @@ -260,4 +294,11 @@ abstract class base  		return '<a href="' . $this->helper->append_sid('memberlist.' . $this->phpEx, 'mode=viewprofile&u=' . $author_id) . '">' . $row[$this->get('creator')] . '</a>';  	} + +	/** +	 * Returns the SQL query used to retrieve the posts of the feed. +	 * +	 * @return string SQL SELECT query +	 */ +	protected abstract function get_sql();  } diff --git a/phpBB/phpbb/feed/controller/feed.php b/phpBB/phpbb/feed/controller/feed.php new file mode 100644 index 0000000000..31476b7317 --- /dev/null +++ b/phpBB/phpbb/feed/controller/feed.php @@ -0,0 +1,389 @@ +<?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\feed\controller; + +use phpbb\auth\auth; +use phpbb\config\config; +use phpbb\db\driver\driver_interface; +use phpbb\exception\http_exception; +use phpbb\feed\feed_interface; +use phpbb\feed\exception\feed_unavailable_exception; +use phpbb\feed\exception\unauthorized_exception; +use phpbb\feed\helper as feed_helper; +use phpbb\controller\helper as controller_helper; +use phpbb\symfony_request; +use phpbb\user; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + +class feed +{ +	/** +	 * @var \Twig_Environment +	 */ +	protected $template; + +	/** +	 * @var symfony_request +	 */ +	protected $request; + +	/** +	 * @var controller_helper +	 */ +	protected $controller_helper; + +	/** +	 * @var config +	 */ +	protected $config; + +	/** +	 * @var driver_interface +	 */ +	protected $db; + +	/** +	 * @var ContainerInterface +	 */ +	protected $container; + +	/** +	 * @var feed_helper +	 */ +	protected $feed_helper; + +	/** +	 * @var user +	 */ +	protected $user; + +	/** +	 * @var auth +	 */ +	protected $auth; + +	/** +	 * @var string +	 */ +	protected $php_ext; + +	/** +	 * Constructor +	 * +	 * @param \Twig_Environment $twig +	 * @param symfony_request $request +	 * @param controller_helper $controller_helper +	 * @param config $config +	 * @param driver_interface $db +	 * @param ContainerInterface $container +	 * @param feed_helper $feed_helper +	 * @param user $user +	 * @param auth $auth +	 * @param string $php_ext +	 */ +	public function __construct(\Twig_Environment $twig, symfony_request $request, controller_helper $controller_helper, config $config, driver_interface $db, ContainerInterface $container, feed_helper $feed_helper, user $user, auth $auth, $php_ext) +	{ +		$this->request = $request; +		$this->controller_helper = $controller_helper; +		$this->config = $config; +		$this->db = $db; +		$this->container = $container; +		$this->feed_helper = $feed_helper; +		$this->user = $user; +		$this->auth = $auth; +		$this->php_ext = $php_ext; +		$this->template = $twig; +	} + +	/** +	 * Controller for /feed/forums route +	 * +	 * @return Response +	 * +	 * @throws http_exception when the feed is disabled +	 */ +	public function forums() +	{ +		if (!$this->config['feed_overall_forums']) +		{ +			$this->send_unavailable(); +		} + +		return $this->send_feed($this->container->get('feed.forums')); +	} + +	/** +	 * Controller for /feed/news route +	 * +	 * @return Response +	 * +	 * @throws http_exception when the feed is disabled +	 */ +	public function news() +	{ +		// Get at least one news forum +		$sql = 'SELECT forum_id +					FROM ' . FORUMS_TABLE . ' +					WHERE ' . $this->db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0'); +		$result = $this->db->sql_query_limit($sql, 1, 0, 600); +		$s_feed_news = (int) $this->db->sql_fetchfield('forum_id'); +		$this->db->sql_freeresult($result); + +		if (!$s_feed_news) +		{ +			$this->send_unavailable(); +		} + +		return $this->send_feed($this->container->get('feed.news')); +	} + +	/** +	 * Controller for /feed/topics route +	 * +	 * @return Response +	 * +	 * @throws http_exception when the feed is disabled +	 */ +	public function topics() +	{ +		if (!$this->config['feed_topics_new']) +		{ +			$this->send_unavailable(); +		} + +		return $this->send_feed($this->container->get('feed.topics')); +	} + +	/** +	 * Controller for /feed/topics_new route +	 * +	 * @return Response +	 * +	 * @throws http_exception when the feed is disabled +	 */ +	public function topics_new() +	{ +		return $this->topics(); +	} + +	/** +	 * Controller for /feed/topics_active route +	 * +	 * @return Response +	 * +	 * @throws http_exception when the feed is disabled +	 */ +	public function topics_active() +	{ +		if (!$this->config['feed_topics_active']) +		{ +			$this->send_unavailable(); +		} + +		return $this->send_feed($this->container->get('feed.topics_active')); +	} + +	/** +	 * Controller for /feed/forum/{forum_id} route +	 * +	 * @param int $forum_id +	 * +	 * @return Response +	 * +	 * @throws http_exception when the feed is disabled +	 */ +	public function forum($forum_id) +	{ +		if (!$this->config['feed_forum']) +		{ +			$this->send_unavailable(); +		} + +		return $this->send_feed($this->container->get('feed.forum')->set_forum_id($forum_id)); +	} + +	/** +	 * Controller for /feed/topic/{topic_id} route +	 * +	 * @param int $topic_id +	 * +	 * @return Response +	 * +	 * @throws http_exception when the feed is disabled +	 */ +	public function topic($topic_id) +	{ +		if (!$this->config['feed_topic']) +		{ +			$this->send_unavailable(); +		} + +		return $this->send_feed($this->container->get('feed.topic')->set_topic_id($topic_id)); +	} + +	/** +	 * Controller for /feed/{mode] route +	 * +	 * @return Response +	 * +	 * @throws http_exception when the feed is disabled +	 */ +	public function overall() +	{ +		if (!$this->config['feed_overall']) +		{ +			$this->send_unavailable(); +		} + +		return $this->send_feed($this->container->get('feed.overall')); +	} + +	/** +	 * Display a given feed +	 * +	 * @param feed_interface $feed +	 * +	 * @return Response +	 */ +	protected function send_feed(feed_interface $feed) +	{ +		try +		{ +			return $this->send_feed_do($feed); +		} +		catch (feed_unavailable_exception $e) +		{ +			throw new http_exception(Response::HTTP_NOT_FOUND, $e->getMessage(), $e->get_parameters(), $e); +		} +		catch (unauthorized_exception $e) +		{ +			throw new http_exception(Response::HTTP_FORBIDDEN, $e->getMessage(), $e->get_parameters(), $e); +		} +	} + +	/** +	 * Really send the feed +	 * +	 * @param feed_interface $feed +	 * +	 * @return Response +	 * +	 * @throw exception\feed_exception +	 */ +	protected function send_feed_do(feed_interface $feed) +	{ +		$feed_updated_time = 0; +		$item_vars = array(); + +		$board_url = $this->feed_helper->get_board_url(); + +		// Open Feed +		$feed->open(); + +		// Iterate through items +		while ($row = $feed->get_item()) +		{ +			// BBCode options to correctly disable urls, smilies, bbcode... +			if ($feed->get('options') === null) +			{ +				// Allow all combinations +				$options = 7; + +				if ($feed->get('enable_bbcode') !== null && $feed->get('enable_smilies') !== null && $feed->get('enable_magic_url') !== null) +				{ +					$options = (($row[$feed->get('enable_bbcode')]) ? OPTION_FLAG_BBCODE : 0) + (($row[$feed->get('enable_smilies')]) ? OPTION_FLAG_SMILIES : 0) + (($row[$feed->get('enable_magic_url')]) ? OPTION_FLAG_LINKS : 0); +				} +			} +			else +			{ +				$options = $row[$feed->get('options')]; +			} + +			$title = (isset($row[$feed->get('title')]) && $row[$feed->get('title')] !== '') ? $row[$feed->get('title')] : ((isset($row[$feed->get('title2')])) ? $row[$feed->get('title2')] : ''); + +			$published = ($feed->get('published') !== null) ? (int) $row[$feed->get('published')] : 0; +			$updated = ($feed->get('updated') !== null) ? (int) $row[$feed->get('updated')] : 0; + +			$display_attachments = ($this->auth->acl_get('u_download') && $this->auth->acl_get('f_download', $row['forum_id']) && isset($row['post_attachment']) && $row['post_attachment']) ? true : false; + +			$item_row = array( +				'author'		=> ($feed->get('creator') !== null) ? $row[$feed->get('creator')] : '', +				'published'		=> ($published > 0) ? $this->feed_helper->format_date($published) : '', +				'updated'		=> ($updated > 0) ? $this->feed_helper->format_date($updated) : '', +				'link'			=> '', +				'title'			=> censor_text($title), +				'category'		=> ($this->config['feed_item_statistics'] && !empty($row['forum_id'])) ? $board_url . '/viewforum.' . $this->php_ext . '?f=' . $row['forum_id'] : '', +				'category_name'	=> ($this->config['feed_item_statistics'] && isset($row['forum_name'])) ? $row['forum_name'] : '', +				'description'	=> censor_text($this->feed_helper->generate_content($row[$feed->get('text')], $row[$feed->get('bbcode_uid')], $row[$feed->get('bitfield')], $options, $row['forum_id'], ($display_attachments ? $feed->get_attachments($row['post_id']) : array()))), +				'statistics'	=> '', +			); + +			// Adjust items, fill link, etc. +			$feed->adjust_item($item_row, $row); + +			$item_vars[] = $item_row; + +			$feed_updated_time = max($feed_updated_time, $published, $updated); +		} + +		// If we do not have any items at all, sending the current time is better than sending no time. +		if (!$feed_updated_time) +		{ +			$feed_updated_time = time(); +		} + +		$feed->close(); + +		$content = $this->template->render('feed.xml.twig', array( +			// Some default assignments +			// FEED_IMAGE is not used (atom) +			'FEED_IMAGE'			=> '', +			'SELF_LINK'				=> $this->controller_helper->route($this->request->attributes->get('_route'), $this->request->attributes->get('_route_params'), true, '', UrlGeneratorInterface::ABSOLUTE_URL), +			'FEED_LINK'				=> $board_url . '/index.' . $this->php_ext, +			'FEED_TITLE'			=> $this->config['sitename'], +			'FEED_SUBTITLE'			=> $this->config['site_desc'], +			'FEED_UPDATED'			=> $this->feed_helper->format_date($feed_updated_time), +			'FEED_LANG'				=> $this->user->lang['USER_LANG'], +			'FEED_AUTHOR'			=> $this->config['sitename'], + +			// Feed entries +			'FEED_ROWS'				=> $item_vars, +		)); + +		$response = new Response($content); +		$response->headers->set('Content-Type', 'application/atom+xml'); +		$response->setCharset('UTF-8'); +		$response->setLastModified(new \DateTime('@' . $feed_updated_time)); + +		if (!empty($this->user->data['is_bot'])) +		{ +			// Let reverse proxies know we detected a bot. +			$response->headers->set('X-PHPBB-IS-BOT', 'yes'); +		} + +		return $response; +	} + +	/** +	 * Throw and exception saying that the feed isn't available +	 * +	 * @throw http_exception +	 */ +	protected function send_unavailable() +	{ +		throw new http_exception(404, 'FEATURE_NOT_AVAILABLE'); +	} +} diff --git a/phpBB/phpbb/feed/exception/feed_exception.php b/phpBB/phpbb/feed/exception/feed_exception.php new file mode 100644 index 0000000000..c9c888211e --- /dev/null +++ b/phpBB/phpbb/feed/exception/feed_exception.php @@ -0,0 +1,21 @@ +<?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\feed\exception; + +use phpbb\exception\runtime_exception; + +abstract class feed_exception extends runtime_exception +{ + +} diff --git a/phpBB/phpbb/feed/exception/feed_unavailable_exception.php b/phpBB/phpbb/feed/exception/feed_unavailable_exception.php new file mode 100644 index 0000000000..4b6605b47d --- /dev/null +++ b/phpBB/phpbb/feed/exception/feed_unavailable_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\feed\exception; + +abstract class feed_unavailable_exception extends feed_exception +{ + +} diff --git a/phpBB/phpbb/feed/exception/no_feed_exception.php b/phpBB/phpbb/feed/exception/no_feed_exception.php new file mode 100644 index 0000000000..af6357b74c --- /dev/null +++ b/phpBB/phpbb/feed/exception/no_feed_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\feed\exception; + +class no_feed_exception extends feed_unavailable_exception +{ +	public function __construct(\Exception $previous = null, $code = 0) +	{ +		parent::__construct('NO_FEED', array(), $previous, $code); +	} +} diff --git a/phpBB/phpbb/feed/exception/no_forum_exception.php b/phpBB/phpbb/feed/exception/no_forum_exception.php new file mode 100644 index 0000000000..a60832957a --- /dev/null +++ b/phpBB/phpbb/feed/exception/no_forum_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\feed\exception; + +class no_forum_exception extends feed_unavailable_exception +{ +	public function __construct($forum_id, \Exception $previous = null, $code = 0) +	{ +		parent::__construct('NO_FORUM', array($forum_id), $previous, $code); +	} +} diff --git a/phpBB/phpbb/feed/exception/no_topic_exception.php b/phpBB/phpbb/feed/exception/no_topic_exception.php new file mode 100644 index 0000000000..b961a65d1c --- /dev/null +++ b/phpBB/phpbb/feed/exception/no_topic_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\feed\exception; + +class no_topic_exception extends feed_unavailable_exception +{ +	public function __construct($topic_id, \Exception $previous = null, $code = 0) +	{ +		parent::__construct('NO_TOPIC', array($topic_id), $previous, $code); +	} +} diff --git a/phpBB/phpbb/feed/exception/unauthorized_exception.php b/phpBB/phpbb/feed/exception/unauthorized_exception.php new file mode 100644 index 0000000000..7868975779 --- /dev/null +++ b/phpBB/phpbb/feed/exception/unauthorized_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\feed\exception; + +abstract class unauthorized_exception extends feed_exception +{ + +} diff --git a/phpBB/phpbb/feed/exception/unauthorized_forum_exception.php b/phpBB/phpbb/feed/exception/unauthorized_forum_exception.php new file mode 100644 index 0000000000..4384c7b39b --- /dev/null +++ b/phpBB/phpbb/feed/exception/unauthorized_forum_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\feed\exception; + +class unauthorized_forum_exception extends unauthorized_exception +{ +	public function __construct($forum_id, \Exception $previous = null, $code = 0) +	{ +		parent::__construct('SORRY_AUTH_READ', array($forum_id), $previous, $code); +	} +} diff --git a/phpBB/phpbb/feed/exception/unauthorized_topic_exception.php b/phpBB/phpbb/feed/exception/unauthorized_topic_exception.php new file mode 100644 index 0000000000..f49f0a0476 --- /dev/null +++ b/phpBB/phpbb/feed/exception/unauthorized_topic_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\feed\exception; + +class unauthorized_topic_exception extends unauthorized_exception +{ +	public function __construct($topic_id, \Exception $previous = null, $code = 0) +	{ +		parent::__construct('SORRY_AUTH_READ_TOPIC', array($topic_id), $previous, $code); +	} +} diff --git a/phpBB/phpbb/feed/factory.php b/phpBB/phpbb/feed/factory.php deleted file mode 100644 index f364f06d03..0000000000 --- a/phpBB/phpbb/feed/factory.php +++ /dev/null @@ -1,127 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -namespace phpbb\feed; - -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** -* Factory class to return correct object -*/ -class factory -{ -	/** -	* Service container object -	* @var ContainerInterface -	*/ -	protected $container; - -	/** @var \phpbb\config\config */ -	protected $config; - -	/** @var \phpbb\db\driver\driver_interface */ -	protected $db; - -	/** -	* Constructor -	* -	* @param ContainerInterface					$container	Container object -	* @param \phpbb\config\config				$config		Config object -	* @param \phpbb\db\driver\driver_interface	$db			Database connection -	*/ -	public function __construct(ContainerInterface $container, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db) -	{ -		$this->container = $container; -		$this->config = $config; -		$this->db = $db; -	} - -	/** -	* Return correct object for specified mode -	* -	* @param string	$mode		The feeds mode. -	* @param int	$forum_id	Forum id specified by the script if forum feed provided. -	* @param int	$topic_id	Topic id specified by the script if topic feed provided. -	* -	* @return object	Returns correct feeds object for specified mode. -	*/ -	function get_feed($mode, $forum_id, $topic_id) -	{ -		switch ($mode) -		{ -			case 'forums': -				if (!$this->config['feed_overall_forums']) -				{ -					return false; -				} - -				return $this->container->get('feed.forums'); -			break; - -			case 'topics': -			case 'topics_new': -				if (!$this->config['feed_topics_new']) -				{ -					return false; -				} - -				return $this->container->get('feed.topics'); -			break; - -			case 'topics_active': -				if (!$this->config['feed_topics_active']) -				{ -					return false; -				} - -				return $this->container->get('feed.topics_active'); -			break; - -			case 'news': -				// Get at least one news forum -				$sql = 'SELECT forum_id -					FROM ' . FORUMS_TABLE . ' -					WHERE ' . $this->db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0'); -				$result = $this->db->sql_query_limit($sql, 1, 0, 600); -				$s_feed_news = (int) $this->db->sql_fetchfield('forum_id'); -				$this->db->sql_freeresult($result); - -				if (!$s_feed_news) -				{ -					return false; -				} - -				return $this->container->get('feed.news'); -			break; - -			default: -				if ($topic_id && $this->config['feed_topic']) -				{ -					return $this->container->get('feed.topic') -								->set_topic_id($topic_id); -				} -				else if ($forum_id && $this->config['feed_forum']) -				{ -					return $this->container->get('feed.forum') -								->set_forum_id($forum_id); -				} -				else if ($this->config['feed_overall']) -				{ -				return $this->container->get('feed.overall'); -				} - -				return false; -			break; -		} -	} -} diff --git a/phpBB/phpbb/feed/feed_interface.php b/phpBB/phpbb/feed/feed_interface.php new file mode 100644 index 0000000000..c185cd249c --- /dev/null +++ b/phpBB/phpbb/feed/feed_interface.php @@ -0,0 +1,67 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\feed; + +/** + * Interface implemented by all feeds types + */ +interface feed_interface +{ +	/** +	 * Set keys. +	 */ +	public function set_keys(); + +	/** +	 * Open feed +	 */ +	public function open(); + +	/** +	 * Close feed +	 */ +	public function close(); + +	/** +	 * Set key +	 * +	 * @param string $key Key +	 * @param mixed $value Value +	 */ +	public function set($key, $value); + +	/** +	 * Get key +	 * +	 * @param string $key Key +	 * @return mixed +	 */ +	public function get($key); + +	/** +	 * Get the next post in the feed +	 * +	 * @return array +	 */ +	public function get_item(); + +	/** +	 * Adjust a feed entry +	 * +	 * @param $item_row +	 * @param $row +	 * @return array +	 */ +	public function adjust_item(&$item_row, &$row); +} diff --git a/phpBB/phpbb/feed/forum.php b/phpBB/phpbb/feed/forum.php index 7a2087c1cd..6701c4d9e7 100644 --- a/phpBB/phpbb/feed/forum.php +++ b/phpBB/phpbb/feed/forum.php @@ -1,35 +1,39 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */  namespace phpbb\feed; +use phpbb\feed\exception\no_feed_exception; +use phpbb\feed\exception\no_forum_exception; +use phpbb\feed\exception\unauthorized_forum_exception; +  /** -* Forum feed -* -* This will give you the last {$this->num_items} posts made -* within a specific forum. -*/ -class forum extends \phpbb\feed\post_base + * Forum feed + * + * This will give you the last {$this->num_items} posts made + * within a specific forum. + */ +class forum extends post_base  { -	var $forum_id		= 0; -	var $forum_data		= array(); +	protected $forum_id		= 0; +	protected $forum_data	= array();  	/** -	* Set the Forum ID -	* -	* @param int	$forum_id			Forum ID -	* @return	\phpbb\feed\forum -	*/ +	 * Set the Forum ID +	 * +	 * @param int	$forum_id			Forum ID +	 * @return	\phpbb\feed\forum +	 */  	public function set_forum_id($forum_id)  	{  		$this->forum_id = (int) $forum_id; @@ -37,7 +41,10 @@ class forum extends \phpbb\feed\post_base  		return $this;  	} -	function open() +	/** +	 * {@inheritdoc} +	 */ +	public function open()  	{  		// Check if forum exists  		$sql = 'SELECT forum_id, forum_name, forum_password, forum_type, forum_options @@ -49,25 +56,25 @@ class forum extends \phpbb\feed\post_base  		if (empty($this->forum_data))  		{ -			trigger_error('NO_FORUM'); +			throw new no_forum_exception($this->forum_id);  		}  		// Forum needs to be postable  		if ($this->forum_data['forum_type'] != FORUM_POST)  		{ -			trigger_error('NO_FEED'); +			throw new no_feed_exception();  		}  		// Make sure forum is not excluded from feed  		if (phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $this->forum_data['forum_options']))  		{ -			trigger_error('NO_FEED'); +			throw new no_feed_exception();  		}  		// Make sure we can read this forum  		if (!$this->auth->acl_get('f_read', $this->forum_id))  		{ -			trigger_error('SORRY_AUTH_READ'); +			throw new unauthorized_forum_exception($this->forum_id);  		}  		// Make sure forum is not passworded or user is authed @@ -77,7 +84,7 @@ class forum extends \phpbb\feed\post_base  			if (isset($forum_ids_passworded[$this->forum_id]))  			{ -				trigger_error('SORRY_AUTH_READ'); +				throw new unauthorized_forum_exception($this->forum_id);  			}  			unset($forum_ids_passworded); @@ -86,7 +93,10 @@ class forum extends \phpbb\feed\post_base  		parent::open();  	} -	function get_sql() +	/** +	 * {@inheritdoc} +	 */ +	protected function get_sql()  	{  		// Determine topics with recent activity  		$sql = 'SELECT topic_id, topic_last_post_time @@ -114,7 +124,7 @@ class forum extends \phpbb\feed\post_base  		$this->sql = array(  			'SELECT'	=>	'p.post_id, p.topic_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' . -							'u.username, u.user_id', +				'u.username, u.user_id',  			'FROM'		=> array(  				POSTS_TABLE		=> 'p',  				USERS_TABLE		=> 'u', @@ -129,7 +139,10 @@ class forum extends \phpbb\feed\post_base  		return true;  	} -	function adjust_item(&$item_row, &$row) +	/** +	 * {@inheritdoc} +	 */ +	public function adjust_item(&$item_row, &$row)  	{  		parent::adjust_item($item_row, $row); @@ -137,7 +150,10 @@ class forum extends \phpbb\feed\post_base  		$item_row['forum_id'] = $this->forum_id;  	} -	function get_item() +	/** +	 * {@inheritdoc} +	 */ +	public function get_item()  	{  		return ($row = parent::get_item()) ? array_merge($this->forum_data, $row) : $row;  	} diff --git a/phpBB/phpbb/feed/forums.php b/phpBB/phpbb/feed/forums.php index ee14a5bc76..92f2b2dd4d 100644 --- a/phpBB/phpbb/feed/forums.php +++ b/phpBB/phpbb/feed/forums.php @@ -1,29 +1,32 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */  namespace phpbb\feed;  /** -* 'All Forums' feed -* -* This will give you a list of all postable forums where feeds are enabled -* including forum description, topic stats and post stats -*/ -class forums extends \phpbb\feed\base + * 'All Forums' feed + * + * This will give you a list of all postable forums where feeds are enabled + * including forum description, topic stats and post stats + */ +class forums extends base  { -	var $num_items	= 0; +	protected $num_items	= 0; -	function set_keys() +	/** +	 * {@inheritdoc} +	 */ +	public function set_keys()  	{  		$this->set('title',		'forum_name');  		$this->set('text',		'forum_desc'); @@ -33,7 +36,10 @@ class forums extends \phpbb\feed\base  		$this->set('options',	'forum_desc_options');  	} -	function get_sql() +	/** +	 * {@inheritdoc} +	 */ +	public function get_sql()  	{  		$in_fid_ary = array_diff($this->get_readable_forums(), $this->get_excluded_forums());  		if (empty($in_fid_ary)) @@ -55,7 +61,10 @@ class forums extends \phpbb\feed\base  		return true;  	} -	function adjust_item(&$item_row, &$row) +	/** +	 * {@inheritdoc} +	 */ +	public function adjust_item(&$item_row, &$row)  	{  		$item_row['link'] = $this->helper->append_sid('viewforum.' . $this->phpEx, 'f=' . $row['forum_id']); diff --git a/phpBB/phpbb/feed/helper.php b/phpBB/phpbb/feed/helper.php index 198134cdcf..e15d1e131e 100644 --- a/phpBB/phpbb/feed/helper.php +++ b/phpBB/phpbb/feed/helper.php @@ -1,21 +1,21 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */  namespace phpbb\feed;  /** -* Class with some helpful functions used in feeds -*/ + * Class with some helpful functions used in feeds + */  class helper  {  	/** @var \phpbb\config\config */ @@ -31,13 +31,13 @@ class helper  	protected $phpEx;  	/** -	* Constructor -	* -	* @param	\phpbb\config\config	$config		Config object -	* @param	\phpbb\user		$user		User object -	* @param	string	$phpbb_root_path	Root path -	* @param	string	$phpEx				PHP file extension -	*/ +	 * Constructor +	 * +	 * @param	\phpbb\config\config	$config		Config object +	 * @param	\phpbb\user		$user		User object +	 * @param	string	$phpbb_root_path	Root path +	 * @param	string	$phpEx				PHP file extension +	 */  	public function __construct(\phpbb\config\config $config, \phpbb\user $user, $phpbb_root_path, $phpEx)  	{  		$this->config = $config; @@ -47,8 +47,8 @@ class helper  	}  	/** -	* Run links through append_sid(), prepend generate_board_url() and remove session id -	*/ +	 * Run links through append_sid(), prepend generate_board_url() and remove session id +	 */  	public function get_board_url()  	{  		static $board_url; @@ -62,16 +62,16 @@ class helper  	}  	/** -	* Run links through append_sid(), prepend generate_board_url() and remove session id -	*/ +	 * Run links through append_sid(), prepend generate_board_url() and remove session id +	 */  	public function append_sid($url, $params)  	{  		return append_sid($this->get_board_url() . '/' . $url, $params, true, '');  	}  	/** -	* Generate ISO 8601 date string (RFC 3339) -	*/ +	 * Generate ISO 8601 date string (RFC 3339) +	 */  	public function format_date($time)  	{  		static $zone_offset; @@ -87,16 +87,16 @@ class helper  	}  	/** -	* Generate text content -	* -	* @param string $content is feed text content -	* @param string $uid is bbcode_uid -	* @param string $bitfield is bbcode bitfield -	* @param int $options bbcode flag options -	* @param int $forum_id is the forum id -	* @param array $post_attachments is an array containing the attachments and their respective info -	* @return string the html content to be printed for the feed -	*/ +	 * Generate text content +	 * +	 * @param string $content is feed text content +	 * @param string $uid is bbcode_uid +	 * @param string $bitfield is bbcode bitfield +	 * @param int $options bbcode flag options +	 * @param int $forum_id is the forum id +	 * @param array $post_attachments is an array containing the attachments and their respective info +	 * @return string the html content to be printed for the feed +	 */  	public function generate_content($content, $uid, $bitfield, $options, $forum_id, $post_attachments)  	{  		if (empty($content)) @@ -122,16 +122,16 @@ class helper  		// Firefox does not support CSS for feeds, though  		// Remove font sizes -	//	$content = preg_replace('#<span style="font-size: [0-9]+%; line-height: [0-9]+%;">([^>]+)</span>#iU', '\1', $content); +		//	$content = preg_replace('#<span style="font-size: [0-9]+%; line-height: [0-9]+%;">([^>]+)</span>#iU', '\1', $content);  		// Make text strong :P -	//	$content = preg_replace('#<span style="font-weight: bold?">(.*?)</span>#iU', '<strong>\1</strong>', $content); +		//	$content = preg_replace('#<span style="font-weight: bold?">(.*?)</span>#iU', '<strong>\1</strong>', $content);  		// Italic -	//	$content = preg_replace('#<span style="font-style: italic?">([^<]+)</span>#iU', '<em>\1</em>', $content); +		//	$content = preg_replace('#<span style="font-style: italic?">([^<]+)</span>#iU', '<em>\1</em>', $content);  		// Underline -	//	$content = preg_replace('#<span style="text-decoration: underline?">([^<]+)</span>#iU', '<u>\1</u>', $content); +		//	$content = preg_replace('#<span style="text-decoration: underline?">([^<]+)</span>#iU', '<u>\1</u>', $content);  		// Remove embed Windows Media Streams  		$content	= preg_replace( '#<\!--\[if \!IE\]>-->([^[]+)<\!--<!\[endif\]-->#si', '', $content); @@ -149,12 +149,10 @@ class helper  		{  			$update_count = array();  			parse_attachments($forum_id, $content, $post_attachments, $update_count); -			$post_attachments = implode('<br />', $post_attachments); +			$content .= implode('<br />', $post_attachments);  			// Convert attachments' relative path to absolute path -			$post_attachments = str_replace($this->phpbb_root_path . 'download/file.' . $this->phpEx, $this->get_board_url() . '/download/file.' . $this->phpEx, $post_attachments); - -			$content .= $post_attachments; +			$content = str_replace($this->phpbb_root_path . 'download/file.' . $this->phpEx, $this->get_board_url() . '/download/file.' . $this->phpEx, $content);  		}  		// Remove Comments from inline attachments [ia] diff --git a/phpBB/phpbb/feed/news.php b/phpBB/phpbb/feed/news.php index a02c199d85..fb6fa09278 100644 --- a/phpBB/phpbb/feed/news.php +++ b/phpBB/phpbb/feed/news.php @@ -1,27 +1,31 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */  namespace phpbb\feed;  /** -* News feed -* -* This will give you {$this->num_items} first posts -* of all topics in the selected news forums. -*/ -class news extends \phpbb\feed\topic_base + * News feed + * + * This will give you {$this->num_items} first posts + * of all topics in the selected news forums. + */ +class news extends topic_base  { -	function get_news_forums() +	/** +	 * Returns the ids of the 'news forums' +	 * @return int[] +	 */ +	private function get_news_forums()  	{  		static $forum_ids; @@ -48,7 +52,10 @@ class news extends \phpbb\feed\topic_base  		return $forum_ids;  	} -	function get_sql() +	/** +	 * {@inheritdoc} +	 */ +	protected function get_sql()  	{  		// Determine forum ids  		$in_fid_ary = array_intersect($this->get_news_forums(), $this->get_readable_forums()); diff --git a/phpBB/phpbb/feed/overall.php b/phpBB/phpbb/feed/overall.php index ab452f5386..40cf94ace0 100644 --- a/phpBB/phpbb/feed/overall.php +++ b/phpBB/phpbb/feed/overall.php @@ -1,27 +1,30 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */  namespace phpbb\feed;  /** -* Board wide feed (aka overall feed) -* -* This will give you the newest {$this->num_items} posts -* from the whole board. -*/ -class overall extends \phpbb\feed\post_base + * Board wide feed (aka overall feed) + * + * This will give you the newest {$this->num_items} posts + * from the whole board. + */ +class overall extends post_base  { -	function get_sql() +	/** +	 * {@inheritdoc} +	 */ +	protected function get_sql()  	{  		$forum_ids = array_diff($this->get_readable_forums(), $this->get_excluded_forums(), $this->get_passworded_forums());  		if (empty($forum_ids)) @@ -55,8 +58,8 @@ class overall extends \phpbb\feed\post_base  		// Get the actual data  		$this->sql = array(  			'SELECT'	=>	'f.forum_id, f.forum_name, ' . -							'p.post_id, p.topic_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' . -							'u.username, u.user_id', +				'p.post_id, p.topic_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' . +				'u.username, u.user_id',  			'FROM'		=> array(  				USERS_TABLE		=> 'u',  				POSTS_TABLE		=> 'p', @@ -77,7 +80,10 @@ class overall extends \phpbb\feed\post_base  		return true;  	} -	function adjust_item(&$item_row, &$row) +	/** +	 * {@inheritdoc} +	 */ +	public function adjust_item(&$item_row, &$row)  	{  		parent::adjust_item($item_row, $row); diff --git a/phpBB/phpbb/feed/post_base.php b/phpBB/phpbb/feed/post_base.php index 011775b6af..f6dc39cbec 100644 --- a/phpBB/phpbb/feed/post_base.php +++ b/phpBB/phpbb/feed/post_base.php @@ -1,27 +1,29 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */  namespace phpbb\feed;  /** -* Abstract class for post based feeds -*/ -abstract class post_base extends \phpbb\feed\attachments_base + * Abstract class for post based feeds + */ +abstract class post_base extends attachments_base  { -	var $num_items = 'feed_limit_post'; -	var $attachments = array(); +	protected $num_items = 'feed_limit_post'; -	function set_keys() +	/** +	 * {@inheritdoc} +	 */ +	public function set_keys()  	{  		$this->set('title',		'post_subject');  		$this->set('title2',	'topic_title'); @@ -40,7 +42,10 @@ abstract class post_base extends \phpbb\feed\attachments_base  		$this->set('enable_magic_url',	'enable_magic_url');  	} -	function adjust_item(&$item_row, &$row) +	/** +	 * {@inheritdoc} +	 */ +	public function adjust_item(&$item_row, &$row)  	{  		$item_row['link'] = $this->helper->append_sid('viewtopic.' . $this->phpEx, "t={$row['topic_id']}&p={$row['post_id']}#p{$row['post_id']}"); diff --git a/phpBB/phpbb/feed/topic.php b/phpBB/phpbb/feed/topic.php index 66c49e55cf..f029c2b00e 100644 --- a/phpBB/phpbb/feed/topic.php +++ b/phpBB/phpbb/feed/topic.php @@ -1,35 +1,40 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * 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\feed; +use phpbb\feed\exception\no_feed_exception; +use phpbb\feed\exception\no_topic_exception; +use phpbb\feed\exception\unauthorized_forum_exception; +use phpbb\feed\exception\unauthorized_topic_exception; +  /** -* Topic feed for a specific topic -* -* This will give you the last {$this->num_items} posts made within this topic. -*/ -class topic extends \phpbb\feed\post_base + * Topic feed for a specific topic + * + * This will give you the last {$this->num_items} posts made within this topic. + */ +class topic extends post_base  { -	var $topic_id		= 0; -	var $forum_id		= 0; -	var $topic_data		= array(); +	protected $topic_id		= 0; +	protected $forum_id		= 0; +	protected $topic_data	= array();  	/** -	* Set the Topic ID -	* -	* @param int	$topic_id			Topic ID -	* @return	\phpbb\feed\topic -	*/ +	 * Set the Topic ID +	 * +	 * @param int	$topic_id			Topic ID +	 * @return	\phpbb\feed\topic +	 */  	public function set_topic_id($topic_id)  	{  		$this->topic_id = (int) $topic_id; @@ -37,7 +42,10 @@ class topic extends \phpbb\feed\post_base  		return $this;  	} -	function open() +	/** +	 * {@inheritdoc} +	 */ +	public function open()  	{  		$sql = 'SELECT f.forum_options, f.forum_password, t.topic_id, t.forum_id, t.topic_visibility, t.topic_title, t.topic_time, t.topic_views, t.topic_posts_approved, t.topic_type  			FROM ' . TOPICS_TABLE . ' t @@ -50,7 +58,7 @@ class topic extends \phpbb\feed\post_base  		if (empty($this->topic_data))  		{ -			trigger_error('NO_TOPIC'); +			throw new no_topic_exception($this->topic_id);  		}  		$this->forum_id = (int) $this->topic_data['forum_id']; @@ -58,19 +66,19 @@ class topic extends \phpbb\feed\post_base  		// Make sure topic is either approved or user authed  		if ($this->topic_data['topic_visibility'] != ITEM_APPROVED && !$this->auth->acl_get('m_approve', $this->forum_id))  		{ -			trigger_error('SORRY_AUTH_READ'); +			throw new unauthorized_topic_exception($this->topic_id);  		}  		// Make sure forum is not excluded from feed  		if (phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $this->topic_data['forum_options']))  		{ -			trigger_error('NO_FEED'); +			throw new no_feed_exception();  		}  		// Make sure we can read this forum  		if (!$this->auth->acl_get('f_read', $this->forum_id))  		{ -			trigger_error('SORRY_AUTH_READ'); +			throw new unauthorized_forum_exception($this->forum_id);  		}  		// Make sure forum is not passworded or user is authed @@ -80,7 +88,7 @@ class topic extends \phpbb\feed\post_base  			if (isset($forum_ids_passworded[$this->forum_id]))  			{ -				trigger_error('SORRY_AUTH_READ'); +				throw new unauthorized_forum_exception($this->forum_id);  			}  			unset($forum_ids_passworded); @@ -89,11 +97,14 @@ class topic extends \phpbb\feed\post_base  		parent::open();  	} -	function get_sql() +	/** +	 * {@inheritdoc} +	 */ +	protected function get_sql()  	{  		$this->sql = array(  			'SELECT'	=>	'p.post_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' . -							'u.username, u.user_id', +				'u.username, u.user_id',  			'FROM'		=> array(  				POSTS_TABLE		=> 'p',  				USERS_TABLE		=> 'u', @@ -107,14 +118,20 @@ class topic extends \phpbb\feed\post_base  		return true;  	} -	function adjust_item(&$item_row, &$row) +	/** +	 * {@inheritdoc} +	 */ +	public function adjust_item(&$item_row, &$row)  	{  		parent::adjust_item($item_row, $row);  		$item_row['forum_id'] = $this->forum_id;  	} -	function get_item() +	/** +	 * {@inheritdoc} +	 */ +	public function get_item()  	{  		return ($row = parent::get_item()) ? array_merge($this->topic_data, $row) : $row;  	} diff --git a/phpBB/phpbb/feed/topic_base.php b/phpBB/phpbb/feed/topic_base.php index f9ff368cba..0f1a9ccb70 100644 --- a/phpBB/phpbb/feed/topic_base.php +++ b/phpBB/phpbb/feed/topic_base.php @@ -1,26 +1,29 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */  namespace phpbb\feed;  /** -* Abstract class for topic based feeds -*/ -abstract class topic_base extends \phpbb\feed\attachments_base + * Abstract class for topic based feeds + */ +abstract class topic_base extends attachments_base  { -	var $num_items = 'feed_limit_topic'; +	protected $num_items = 'feed_limit_topic'; -	function set_keys() +	/** +	 * {@inheritdoc} +	 */ +	public function set_keys()  	{  		$this->set('title',		'topic_title');  		$this->set('title2',	'forum_name'); @@ -39,7 +42,10 @@ abstract class topic_base extends \phpbb\feed\attachments_base  		$this->set('enable_magic_url',	'enable_magic_url');  	} -	function adjust_item(&$item_row, &$row) +	/** +	 * {@inheritdoc} +	 */ +	public function adjust_item(&$item_row, &$row)  	{  		$item_row['link'] = $this->helper->append_sid('viewtopic.' . $this->phpEx, 't=' . $row['topic_id'] . '&p=' . $row['post_id'] . '#p' . $row['post_id']); diff --git a/phpBB/phpbb/feed/topics.php b/phpBB/phpbb/feed/topics.php index 2b9cb3501a..cf4a2e579e 100644 --- a/phpBB/phpbb/feed/topics.php +++ b/phpBB/phpbb/feed/topics.php @@ -1,27 +1,30 @@  <?php  /** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */  namespace phpbb\feed;  /** -* New Topics feed -* -* This will give you the last {$this->num_items} created topics -* including the first post. -*/ -class topics extends \phpbb\feed\topic_base + * New Topics feed + * + * This will give you the last {$this->num_items} created topics + * including the first post. + */ +class topics extends topic_base  { -	function get_sql() +	/** +	 * {@inheritdoc} +	 */ +	protected function get_sql()  	{  		$forum_ids_read = $this->get_readable_forums();  		if (empty($forum_ids_read)) @@ -77,7 +80,10 @@ class topics extends \phpbb\feed\topic_base  		return true;  	} -	function adjust_item(&$item_row, &$row) +	/** +	 * {@inheritdoc} +	 */ +	public function adjust_item(&$item_row, &$row)  	{  		parent::adjust_item($item_row, $row); diff --git a/phpBB/phpbb/feed/topics_active.php b/phpBB/phpbb/feed/topics_active.php index 6d5eddfc16..52340dc2d5 100644 --- a/phpBB/phpbb/feed/topics_active.php +++ b/phpBB/phpbb/feed/topics_active.php @@ -1,30 +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. -* -*/ + * + * 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\feed;  /** -* Active Topics feed -* -* This will give you the last {$this->num_items} topics -* with replies made withing the last {$this->sort_days} days -* including the last post. -*/ -class topics_active extends \phpbb\feed\topic_base + * Active Topics feed + * + * This will give you the last {$this->num_items} topics + * with replies made withing the last {$this->sort_days} days + * including the last post. + */ +class topics_active extends topic_base  { -	var $sort_days = 7; +	protected $sort_days = 7; -	function set_keys() +	/** +	 * {@inheritdoc} +	 */ +	public function set_keys()  	{  		parent::set_keys(); @@ -32,7 +35,10 @@ class topics_active extends \phpbb\feed\topic_base  		$this->set('creator',	'topic_last_poster_name');  	} -	function get_sql() +	/** +	 * {@inheritdoc} +	 */ +	protected function get_sql()  	{  		$forum_ids_read = $this->get_readable_forums();  		if (empty($forum_ids_read)) @@ -94,7 +100,12 @@ class topics_active extends \phpbb\feed\topic_base  		return true;  	} -	function get_forum_ids() +	/** +	 * Returns the ids of the forums not excluded from the active list +	 * +	 * @return int[] +	 */ +	private function get_forum_ids()  	{  		static $forum_ids; @@ -122,7 +133,10 @@ class topics_active extends \phpbb\feed\topic_base  		return $forum_ids;  	} -	function adjust_item(&$item_row, &$row) +	/** +	 * {@inheritdoc} +	 */ +	public function adjust_item(&$item_row, &$row)  	{  		parent::adjust_item($item_row, $row); diff --git a/phpBB/phpbb/files/factory.php b/phpBB/phpbb/files/factory.php new file mode 100644 index 0000000000..84b7cc9449 --- /dev/null +++ b/phpBB/phpbb/files/factory.php @@ -0,0 +1,58 @@ +<?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\files; + +class factory +{ +	/** +	 * @var \Symfony\Component\DependencyInjection\ContainerInterface +	 */ +	private $container; + +	/** +	 * Constructor +	 * +	 * @param \Symfony\Component\DependencyInjection\ContainerInterface $container +	 */ +	public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container) +	{ +		$this->container = $container; +	} + +	/** +	 * Get files service +	 * +	 * @param string $name Service name +	 * +	 * @return object|bool Requested service or false if service could not be +	 *				found by the container +	 */ +	public function get($name) +	{ +		$service = false; + +		$name = (strpos($name, '.') === false) ? 'files.' . $name : $name; + +		try +		{ +			$service = $this->container->get($name); +		} +		catch (\Exception $e) +		{ +			// do nothing +		} + +		return $service; +	} +} diff --git a/phpBB/phpbb/files/filespec.php b/phpBB/phpbb/files/filespec.php new file mode 100644 index 0000000000..2ff2a92c83 --- /dev/null +++ b/phpBB/phpbb/files/filespec.php @@ -0,0 +1,584 @@ +<?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\files; + +use phpbb\language\language; + +/** + * Responsible for holding all file relevant information, as well as doing file-specific operations. + * The {@link fileupload fileupload class} can be used to upload several files, each of them being this object to operate further on. + */ +class filespec +{ +	/** @var string File name */ +	protected $filename = ''; + +	/** @var string Real name of file */ +	protected $realname = ''; + +	/** @var string Upload name of file */ +	protected $uploadname = ''; + +	/** @var string Mimetype of file */ +	protected $mimetype = ''; + +	/** @var string File extension */ +	protected $extension = ''; + +	/** @var int File size */ +	protected $filesize = 0; + +	/** @var int Width of file */ +	protected $width = 0; + +	/** @var int Height of file */ +	protected $height = 0; + +	/** @var array Image info including type and size */ +	protected $image_info = array(); + +	/** @var string Destination file name */ +	protected $destination_file = ''; + +	/** @var string Destination file path */ +	protected $destination_path = ''; + +	/** @var bool Whether file was moved */ +	protected $file_moved = false; + +	/** @var bool Whether file is local */ +	protected $local = false; + +	/** @var bool Class initialization flag */ +	protected $class_initialized = false; + +	/** @var array Error array */ +	public $error = array(); + +	/** @var upload Instance of upload class  */ +	public $upload; + +	/** @var \phpbb\filesystem\filesystem_interface */ +	protected $filesystem; + +	/** @var \bantu\IniGetWrapper\IniGetWrapper ini_get() wrapper class */ +	protected $php_ini; + +	/** @var \FastImageSize\FastImageSize */ +	protected $imagesize; + +	/** @var language Language class */ +	protected $language; + +	/** @var string phpBB root path */ +	protected $phpbb_root_path; + +	/** @var \phpbb\plupload\plupload The plupload object */ +	protected $plupload; + +	/** @var \phpbb\mimetype\guesser phpBB Mimetype guesser */ +	protected $mimetype_guesser; + +	/** +	 * File upload class +	 * +	 * @param \phpbb\filesystem\filesystem_interface	$phpbb_filesystem Filesystem +	 * @param language					$language Language +	 * @param \bantu\IniGetWrapper\IniGetWrapper			$php_ini ini_get() wrapper +	 * @param \FastImageSize\FastImageSize $imagesize Imagesize class +	 * @param string					$phpbb_root_path phpBB root path +	 * @param \phpbb\mimetype\guesser	$mimetype_guesser Mime type guesser +	 * @param \phpbb\plupload\plupload	$plupload Plupload +	 */ +	public function __construct(\phpbb\filesystem\filesystem_interface $phpbb_filesystem, language $language, \bantu\IniGetWrapper\IniGetWrapper $php_ini, \FastImageSize\FastImageSize $imagesize, $phpbb_root_path, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null) +	{ +		$this->filesystem = $phpbb_filesystem; +		$this->language = $language; +		$this->php_ini = $php_ini; +		$this->imagesize = $imagesize; +		$this->phpbb_root_path = $phpbb_root_path; +		$this->plupload = $plupload; +		$this->mimetype_guesser = $mimetype_guesser; +	} + +	/** +	 * Set upload ary +	 * +	 * @param array $upload_ary Upload ary +	 * +	 * @return filespec This instance of the filespec class +	 */ +	public function set_upload_ary($upload_ary) +	{ +		if (!isset($upload_ary) || !sizeof($upload_ary)) +		{ +			return $this; +		} + +		$this->class_initialized = true; +		$this->filename = $upload_ary['tmp_name']; +		$this->filesize = $upload_ary['size']; +		$name = (STRIP) ? stripslashes($upload_ary['name']) : $upload_ary['name']; +		$name = trim(utf8_basename($name)); +		$this->realname = $this->uploadname = $name; +		$this->mimetype = $upload_ary['type']; + +		// Opera adds the name to the mime type +		$this->mimetype	= (strpos($this->mimetype, '; name') !== false) ? str_replace(strstr($this->mimetype, '; name'), '', $this->mimetype) : $this->mimetype; + +		if (!$this->mimetype) +		{ +			$this->mimetype = 'application/octet-stream'; +		} + +		$this->extension = strtolower(self::get_extension($this->realname)); + +		// Try to get real filesize from temporary folder (not always working) ;) +		$this->filesize = ($this->get_filesize($this->filename)) ?: $this->filesize; + +		$this->width = $this->height = 0; +		$this->file_moved = false; + +		$this->local = (isset($upload_ary['local_mode'])) ? true : false; + +		return $this; +	} + +	/** +	 * Set the upload namespace +	 * +	 * @param upload $namespace Instance of upload class +	 * +	 * @return filespec This instance of the filespec class +	 */ +	public function set_upload_namespace($namespace) +	{ +		$this->upload = $namespace; + +		return $this; +	} + +	/** +	 * Check if class members were not properly initialised yet +	 * +	 * @return bool True if there was an init error, false if not +	 */ +	public function init_error() +	{ +		return !$this->class_initialized; +	} + +	/** +	 * Set error in error array +	 * +	 * @param mixed $error Content for error array +	 * +	 * @return \phpbb\files\filespec This instance of the filespec class +	 */ +	public function set_error($error) +	{ +		$this->error[] = $error; + +		return $this; +	} + +	/** +	 * Cleans destination filename +	 * +	 * @param string $mode Either real, unique, or unique_ext. Real creates a +	 *				realname, filtering some characters, lowering every +	 *				character. Unique creates a unique filename. +	 * @param string $prefix Prefix applied to filename +	 * @param string $user_id The user_id is only needed for when cleaning a user's avatar +	 */ +	public function clean_filename($mode = 'unique', $prefix = '', $user_id = '') +	{ +		if ($this->init_error()) +		{ +			return; +		} + +		switch ($mode) +		{ +			case 'real': +				// Remove every extension from filename (to not let the mime bug being exposed) +				if (strpos($this->realname, '.') !== false) +				{ +					$this->realname = substr($this->realname, 0, strpos($this->realname, '.')); +				} + +				// Replace any chars which may cause us problems with _ +				$bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|'); + +				$this->realname = rawurlencode(str_replace($bad_chars, '_', strtolower($this->realname))); +				$this->realname = preg_replace("/%(\w{2})/", '_', $this->realname); + +				$this->realname = $prefix . $this->realname . '.' . $this->extension; +			break; + +			case 'unique': +				$this->realname = $prefix . md5(unique_id()); +			break; + +			case 'avatar': +				$this->extension = strtolower($this->extension); +				$this->realname = $prefix . $user_id . '.' . $this->extension; + +			break; + +			case 'unique_ext': +			default: +				$this->realname = $prefix . md5(unique_id()) . '.' . $this->extension; +		} +	} + +	/** +	 * Get property from file object +	 * +	 * @param string $property Name of property +	 * +	 * @return mixed Content of property +	 */ +	public function get($property) +	{ +		if ($this->init_error() || !isset($this->$property)) +		{ +			return false; +		} + +		return $this->$property; +	} + +	/** +	 * Check if file is an image (mime type) +	 * +	 * @return bool true if it is an image, false if not +	 */ +	public function is_image() +	{ +		return (strpos($this->mimetype, 'image/') === 0); +	} + +	/** +	 * Check if the file got correctly uploaded +	 * +	 * @return bool true if it is a valid upload, false if not +	 */ +	public function is_uploaded() +	{ +		$is_plupload = $this->plupload && $this->plupload->is_active(); + +		if (!$this->local && !$is_plupload && !is_uploaded_file($this->filename)) +		{ +			return false; +		} + +		if (($this->local || $is_plupload) && !file_exists($this->filename)) +		{ +			return false; +		} + +		return true; +	} + +	/** +	 * Remove file +	 */ +	public function remove() +	{ +		if ($this->file_moved) +		{ +			@unlink($this->destination_file); +		} +	} + +	/** +	 * Get file extension +	 * +	 * @param string $filename Filename that needs to be checked +	 * +	 * @return string Extension of the supplied filename +	 */ +	static public function get_extension($filename) +	{ +		$filename = utf8_basename($filename); + +		if (strpos($filename, '.') === false) +		{ +			return ''; +		} + +		$filename = explode('.', $filename); +		return array_pop($filename); +	} + +	/** +	 * Get mime type +	 * +	 * @param string $filename Filename that needs to be checked +	 * @return string Mime type of supplied filename +	 */ +	public function get_mimetype($filename) +	{ +		if ($this->mimetype_guesser !== null) +		{ +			$mimetype = $this->mimetype_guesser->guess($filename, $this->uploadname); + +			if ($mimetype !== 'application/octet-stream') +			{ +				$this->mimetype = $mimetype; +			} +		} + +		return $this->mimetype; +	} + +	/** +	 * Get file size +	 * +	 * @param string $filename File name of file to check +	 * +	 * @return int File size +	 */ +	public function get_filesize($filename) +	{ +		return @filesize($filename); +	} + + +	/** +	 * Check the first 256 bytes for forbidden content +	 * +	 * @param array $disallowed_content Array containg disallowed content +	 * +	 * @return bool False if disallowed content found, true if not +	 */ +	public function check_content($disallowed_content) +	{ +		if (empty($disallowed_content)) +		{ +			return true; +		} + +		$fp = @fopen($this->filename, 'rb'); + +		if ($fp !== false) +		{ +			$ie_mime_relevant = fread($fp, 256); +			fclose($fp); +			foreach ($disallowed_content as $forbidden) +			{ +				if (stripos($ie_mime_relevant, '<' . $forbidden) !== false) +				{ +					return false; +				} +			} +		} +		return true; +	} + +	/** +	 * Move file to destination folder +	 * The phpbb_root_path variable will be applied to the destination path +	 * +	 * @param string $destination Destination path, for example $config['avatar_path'] +	 * @param bool $overwrite If set to true, an already existing file will be overwritten +	 * @param bool $skip_image_check If set to true, the check for the file to be a valid image is skipped +	 * @param string|bool $chmod Permission mask for chmodding the file after a successful move. +	 *				The mode entered here reflects the mode defined by {@link phpbb_chmod()} +	 * +	 * @return bool True if file was moved, false if not +	 * @access public +	 */ +	public function move_file($destination, $overwrite = false, $skip_image_check = false, $chmod = false) +	{ +		if (sizeof($this->error)) +		{ +			return false; +		} + +		$chmod = ($chmod === false) ? CHMOD_READ | CHMOD_WRITE : $chmod; + +		// We need to trust the admin in specifying valid upload directories and an attacker not being able to overwrite it... +		$this->destination_path = $this->phpbb_root_path . $destination; + +		// Check if the destination path exist... +		if (!file_exists($this->destination_path)) +		{ +			@unlink($this->filename); +			return false; +		} + +		$upload_mode = ($this->php_ini->getBool('open_basedir') || $this->php_ini->getBool('safe_mode')) ? 'move' : 'copy'; +		$upload_mode = ($this->local) ? 'local' : $upload_mode; +		$this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname); + +		// Check if the file already exist, else there is something wrong... +		if (file_exists($this->destination_file) && !$overwrite) +		{ +			@unlink($this->filename); +			$this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file); +			$this->file_moved = false; +			return false; +		} +		else +		{ +			if (file_exists($this->destination_file)) +			{ +				@unlink($this->destination_file); +			} + +			switch ($upload_mode) +			{ +				case 'copy': + +					if (!@copy($this->filename, $this->destination_file)) +					{ +						if (!@move_uploaded_file($this->filename, $this->destination_file)) +						{ +							$this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file); +						} +					} + +				break; + +				case 'move': + +					if (!@move_uploaded_file($this->filename, $this->destination_file)) +					{ +						if (!@copy($this->filename, $this->destination_file)) +						{ +							$this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file); +						} +					} + +				break; + +				case 'local': + +					if (!@copy($this->filename, $this->destination_file)) +					{ +						$this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file); +					} + +				break; +			} + +			// Remove temporary filename +			@unlink($this->filename); + +			if (sizeof($this->error)) +			{ +				return false; +			} + +			try +			{ +				$this->filesystem->phpbb_chmod($this->destination_file, $chmod); +			} +			catch (\phpbb\filesystem\exception\filesystem_exception $e) +			{ +				// Do nothing +			} +		} + +		// Try to get real filesize from destination folder +		$this->filesize = ($this->get_filesize($this->destination_file)) ?: $this->filesize; + +		// Get mimetype of supplied file +		$this->mimetype = $this->get_mimetype($this->destination_file); + +		if ($this->is_image() && !$skip_image_check) +		{ +			$this->width = $this->height = 0; + +			$this->image_info = $this->imagesize->getImageSize($this->destination_file, $this->mimetype); + +			if ($this->image_info !== false) +			{ +				$this->width = $this->image_info['width']; +				$this->height = $this->image_info['height']; + +				// Check image type +				$types = upload::image_types(); + +				if (!isset($types[$this->image_info['type']]) || !in_array($this->extension, $types[$this->image_info['type']])) +				{ +					if (!isset($types[$this->image_info['type']])) +					{ +						$this->error[] = $this->language->lang('IMAGE_FILETYPE_INVALID', $this->image_info['type'], $this->mimetype); +					} +					else +					{ +						$this->error[] = $this->language->lang('IMAGE_FILETYPE_MISMATCH', $types[$this->image_info['type']][0], $this->extension); +					} +				} + +				// Make sure the dimensions match a valid image +				if (empty($this->width) || empty($this->height)) +				{ +					$this->error[] = $this->language->lang('ATTACHED_IMAGE_NOT_IMAGE'); +				} +			} +			else +			{ +				$this->error[] = $this->language->lang('UNABLE_GET_IMAGE_SIZE'); +			} +		} + +		$this->file_moved = true; +		$this->additional_checks(); +		unset($this->upload); + +		return true; +	} + +	/** +	 * Performing additional checks +	 * +	 * @return bool False if issue was found, true if not +	 */ +	public function additional_checks() +	{ +		if (!$this->file_moved) +		{ +			return false; +		} + +		// Filesize is too big or it's 0 if it was larger than the maxsize in the upload form +		if ($this->upload->max_filesize && ($this->get('filesize') > $this->upload->max_filesize || $this->filesize == 0)) +		{ +			$max_filesize = get_formatted_filesize($this->upload->max_filesize, false); + +			$this->error[] = $this->language->lang($this->upload->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']); + +			return false; +		} + +		if (!$this->upload->valid_dimensions($this)) +		{ +			$this->error[] = $this->language->lang($this->upload->error_prefix . 'WRONG_SIZE', +				$this->language->lang('PIXELS', (int) $this->upload->min_width), +				$this->language->lang('PIXELS', (int) $this->upload->min_height), +				$this->language->lang('PIXELS', (int) $this->upload->max_width), +				$this->language->lang('PIXELS', (int) $this->upload->max_height), +				$this->language->lang('PIXELS', (int) $this->width), +				$this->language->lang('PIXELS', (int) $this->height)); + +			return false; +		} + +		return true; +	} +} diff --git a/phpBB/phpbb/files/types/base.php b/phpBB/phpbb/files/types/base.php new file mode 100644 index 0000000000..3313ad040b --- /dev/null +++ b/phpBB/phpbb/files/types/base.php @@ -0,0 +1,65 @@ +<?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\files\types; + +abstract class base implements type_interface +{ +	/** @var \phpbb\language\language */ +	protected $language; + +	/** @var \bantu\IniGetWrapper\IniGetWrapper */ +	protected $php_ini; + +	/** @var \phpbb\files\upload */ +	protected $upload; + +	/** +	 * Check if upload exceeds maximum file size +	 * +	 * @param \phpbb\files\filespec $file Filespec object +	 * +	 * @return \phpbb\files\filespec Returns same filespec instance +	 */ +	public function check_upload_size($file) +	{ +		// PHP Upload filesize exceeded +		if ($file->get('filename') == 'none') +		{ +			$max_filesize = $this->php_ini->getString('upload_max_filesize'); +			$unit = 'MB'; + +			if (!empty($max_filesize)) +			{ +				$unit = strtolower(substr($max_filesize, -1, 1)); +				$max_filesize = (int) $max_filesize; + +				$unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB'); +			} + +			$file->error[] = (empty($max_filesize)) ? $this->language->lang($this->upload->error_prefix . 'PHP_SIZE_NA') : $this->language->lang($this->upload->error_prefix . 'PHP_SIZE_OVERRUN', $max_filesize, $this->language->lang($unit)); +		} + +		return $file; +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function set_upload(\phpbb\files\upload $upload) +	{ +		$this->upload = $upload; + +		return $this; +	} +} diff --git a/phpBB/phpbb/files/types/form.php b/phpBB/phpbb/files/types/form.php new file mode 100644 index 0000000000..832f090c47 --- /dev/null +++ b/phpBB/phpbb/files/types/form.php @@ -0,0 +1,138 @@ +<?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\files\types; + +use bantu\IniGetWrapper\IniGetWrapper; +use phpbb\files\factory; +use phpbb\files\filespec; +use phpbb\language\language; +use phpbb\plupload\plupload; +use phpbb\request\request_interface; + +class form extends base +{ +	/** @var factory Files factory */ +	protected $factory; + +	/** @var language */ +	protected $language; + +	/** @var IniGetWrapper */ +	protected $php_ini; + +	/** @var plupload */ +	protected $plupload; + +	/** @var request_interface */ +	protected $request; + +	/** @var \phpbb\files\upload */ +	protected $upload; + +	/** +	 * Construct a form upload type +	 * +	 * @param factory			$factory	Files factory +	 * @param language			$language	Language class +	 * @param IniGetWrapper		$php_ini	ini_get() wrapper +	 * @param plupload			$plupload	Plupload +	 * @param request_interface	$request	Request object +	 */ +	public function __construct(factory $factory, language $language, IniGetWrapper $php_ini, plupload $plupload, request_interface $request) +	{ +		$this->factory = $factory; +		$this->language = $language; +		$this->php_ini = $php_ini; +		$this->plupload = $plupload; +		$this->request = $request; +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function upload() +	{ +		$args = func_get_args(); +		return $this->form_upload($args[0]); +	} + +	/** +	 * Form upload method +	 * Upload file from users harddisk +	 * +	 * @param string $form_name Form name assigned to the file input field (if it is an array, the key has to be specified) +	 * +	 * @return filespec $file Object "filespec" is returned, all further operations can be done with this object +	 * @access public +	 */ +	protected function form_upload($form_name) +	{ +		$upload = $this->request->file($form_name); +		unset($upload['local_mode']); + +		$result = $this->plupload->handle_upload($form_name); +		if (is_array($result)) +		{ +			$upload = array_merge($upload, $result); +		} + +		/** @var filespec $file */ +		$file = $this->factory->get('filespec') +			->set_upload_ary($upload) +			->set_upload_namespace($this->upload); + +		if ($file->init_error()) +		{ +			$file->error[] = ''; +			return $file; +		} + +		// Error array filled? +		if (isset($upload['error'])) +		{ +			$error = $this->upload->assign_internal_error($upload['error']); + +			if ($error !== false) +			{ +				$file->error[] = $error; +				return $file; +			} +		} + +		// Check if empty file got uploaded (not catched by is_uploaded_file) +		if (isset($upload['size']) && $upload['size'] == 0) +		{ +			$file->error[] = $this->language->lang($this->upload->error_prefix . 'EMPTY_FILEUPLOAD'); +			return $file; +		} + +		// PHP Upload file size check +		$file = $this->check_upload_size($file); +		if (sizeof($file->error)) +		{ +			return $file; +		} + +		// Not correctly uploaded +		if (!$file->is_uploaded()) +		{ +			$file->error[] = $this->language->lang($this->upload->error_prefix . 'NOT_UPLOADED'); +			return $file; +		} + +		$this->upload->common_checks($file); + +		return $file; +	} +} diff --git a/phpBB/phpbb/files/types/local.php b/phpBB/phpbb/files/types/local.php new file mode 100644 index 0000000000..7e9210b196 --- /dev/null +++ b/phpBB/phpbb/files/types/local.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\files\types; + +use bantu\IniGetWrapper\IniGetWrapper; +use phpbb\files\factory; +use phpbb\files\filespec; +use phpbb\language\language; +use phpbb\request\request_interface; + +class local extends base +{ +	/** @var factory Files factory */ +	protected $factory; + +	/** @var language */ +	protected $language; + +	/** @var IniGetWrapper */ +	protected $php_ini; + +	/** @var request_interface */ +	protected $request; + +	/** @var \phpbb\files\upload */ +	protected $upload; + +	/** +	 * Construct a form upload type +	 * +	 * @param factory $factory Files factory +	 * @param language $language Language class +	 * @param IniGetWrapper $php_ini ini_get() wrapper +	 * @param request_interface $request Request object +	 */ +	public function __construct(factory $factory, language $language, IniGetWrapper $php_ini, request_interface $request) +	{ +		$this->factory = $factory; +		$this->language = $language; +		$this->php_ini = $php_ini; +		$this->request = $request; +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function upload() +	{ +		$args = func_get_args(); +		return $this->local_upload($args[0], isset($args[1]) ? $args[1] : false); +	} + +	/** +	 * Move file from another location to phpBB +	 * +	 * @param string $source_file Filename of source file +	 * @param array|bool $filedata Array with filedata or false +	 * +	 * @return filespec Object "filespec" is returned, all further operations can be done with this object +	 */ +	protected function local_upload($source_file, $filedata = false) +	{ +		$upload = $this->get_upload_ary($source_file, $filedata); + +		/** @var filespec $file */ +		$file = $this->factory->get('filespec') +			->set_upload_ary($upload) +			->set_upload_namespace($this->upload); + +		if ($file->init_error()) +		{ +			$file->error[] = ''; +			return $file; +		} + +		// PHP Upload file size check +		$file = $this->check_upload_size($file); +		if (sizeof($file->error)) +		{ +			return $file; +		} + +		// Not correctly uploaded +		if (!$file->is_uploaded()) +		{ +			$file->error[] = $this->language->lang($this->upload->error_prefix . 'NOT_UPLOADED'); +			return $file; +		} + +		$this->upload->common_checks($file); +		$this->request->overwrite('local', $upload, request_interface::FILES); + +		return $file; +	} + +	/** +	 * Retrieve upload array +	 * +	 * @param string $source_file Source file name +	 * @param array $filedata File data array +	 * +	 * @return array Upload array +	 */ +	protected function get_upload_ary($source_file, $filedata) +	{ +		$upload = array(); + +		$upload['local_mode'] = true; +		$upload['tmp_name'] = $source_file; + +		if ($filedata === false) +		{ +			$upload['name'] = utf8_basename($source_file); +			$upload['size'] = 0; +		} +		else +		{ +			$upload['name'] = $filedata['realname']; +			$upload['size'] = $filedata['size']; +			$upload['type'] = $filedata['type']; +		} + +		return $upload; +	} +} diff --git a/phpBB/phpbb/files/types/remote.php b/phpBB/phpbb/files/types/remote.php new file mode 100644 index 0000000000..44feab0ece --- /dev/null +++ b/phpBB/phpbb/files/types/remote.php @@ -0,0 +1,260 @@ +<?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\files\types; + +use bantu\IniGetWrapper\IniGetWrapper; +use phpbb\files\factory; +use phpbb\files\filespec; +use phpbb\language\language; +use phpbb\request\request_interface; + +class remote extends base +{ +	/** @var factory Files factory */ +	protected $factory; + +	/** @var language */ +	protected $language; + +	/** @var IniGetWrapper */ +	protected $php_ini; + +	/** @var request_interface */ +	protected $request; + +	/** @var \phpbb\files\upload */ +	protected $upload; + +	/** @var string phpBB root path */ +	protected $phpbb_root_path; + +	/** +	 * Construct a form upload type +	 * +	 * @param factory $factory Files factory +	 * @param language $language Language class +	 * @param IniGetWrapper $php_ini ini_get() wrapper +	 * @param request_interface $request Request object +	 * @param string $phpbb_root_path phpBB root path +	 */ +	public function __construct(factory $factory, language $language, IniGetWrapper $php_ini, request_interface $request, $phpbb_root_path) +	{ +		$this->factory = $factory; +		$this->language = $language; +		$this->php_ini = $php_ini; +		$this->request = $request; +		$this->phpbb_root_path = $phpbb_root_path; +	} + +	/** +	 * {@inheritdoc} +	 */ +	public function upload() +	{ +		$args = func_get_args(); +		return $this->remote_upload($args[0]); +	} + +	/** +	 * Remote upload method +	 * Uploads file from given url +	 * +	 * @param string $upload_url URL pointing to file to upload, for example http://www.foobar.com/example.gif +	 * @return filespec $file Object "filespec" is returned, all further operations can be done with this object +	 * @access public +	 */ +	protected function remote_upload($upload_url) +	{ +		$upload_ary = array(); +		$upload_ary['local_mode'] = true; + +		if (!preg_match('#^(https?://).*?\.(' . implode('|', $this->upload->allowed_extensions) . ')$#i', $upload_url, $match)) +		{ +			return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'URL_INVALID')); +		} + +		$url = parse_url($upload_url); + +		$host = $url['host']; +		$path = $url['path']; +		$port = (!empty($url['port'])) ? (int) $url['port'] : 80; + +		$upload_ary['type'] = 'application/octet-stream'; + +		$url['path'] = explode('.', $url['path']); +		$ext = array_pop($url['path']); + +		$url['path'] = implode('', $url['path']); +		$upload_ary['name'] = utf8_basename($url['path']) . (($ext) ? '.' . $ext : ''); +		$filename = $url['path']; +		$filesize = 0; + +		$remote_max_filesize = $this->get_max_file_size(); + +		$errno = 0; +		$errstr = ''; + +		if (!($fsock = @fsockopen($host, $port, $errno, $errstr))) +		{ +			return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'NOT_UPLOADED')); +		} + +		// Make sure $path not beginning with / +		if (strpos($path, '/') === 0) +		{ +			$path = substr($path, 1); +		} + +		fputs($fsock, 'GET /' . $path . " HTTP/1.1\r\n"); +		fputs($fsock, "HOST: " . $host . "\r\n"); +		fputs($fsock, "Connection: close\r\n\r\n"); + +		// Set a proper timeout for the socket +		socket_set_timeout($fsock, $this->upload->upload_timeout); + +		$get_info = false; +		$data = ''; +		$length = false; +		$timer_stop = time() + $this->upload->upload_timeout; + +		while ((!$length || $filesize < $length) && !@feof($fsock)) +		{ +			if ($get_info) +			{ +				if ($length) +				{ +					// Don't attempt to read past end of file if server indicated length +					$block = @fread($fsock, min($length - $filesize, 1024)); +				} +				else +				{ +					$block = @fread($fsock, 1024); +				} + +				$filesize += strlen($block); + +				if ($remote_max_filesize && $filesize > $remote_max_filesize) +				{ +					$max_filesize = get_formatted_filesize($remote_max_filesize, false); + +					return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit'])); +				} + +				$data .= $block; +			} +			else +			{ +				$line = @fgets($fsock, 1024); + +				if ($line == "\r\n") +				{ +					$get_info = true; +				} +				else +				{ +					if (stripos($line, 'content-type: ') !== false) +					{ +						$upload_ary['type'] = rtrim(str_replace('content-type: ', '', strtolower($line))); +					} +					else if ($this->upload->max_filesize && stripos($line, 'content-length: ') !== false) +					{ +						$length = (int) str_replace('content-length: ', '', strtolower($line)); + +						if ($remote_max_filesize && $length && $length > $remote_max_filesize) +						{ +							$max_filesize = get_formatted_filesize($remote_max_filesize, false); + +							return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit'])); +						} +					} +					else if (stripos($line, '404 not found') !== false) +					{ +						return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'URL_NOT_FOUND'); +					} +				} +			} + +			$stream_meta_data = stream_get_meta_data($fsock); + +			// Cancel upload if we exceed timeout +			if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop) +			{ +				return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'REMOTE_UPLOAD_TIMEOUT'); +			} +		} +		@fclose($fsock); + +		if (empty($data)) +		{ +			return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'EMPTY_REMOTE_DATA'); +		} + +		$tmp_path = (!$this->php_ini->getBool('safe_mode')) ? false : $this->phpbb_root_path . 'cache'; +		$filename = tempnam($tmp_path, unique_id() . '-'); + +		if (!($fp = @fopen($filename, 'wb'))) +		{ +			return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'NOT_UPLOADED'); +		} + +		$upload_ary['size'] = fwrite($fp, $data); +		fclose($fp); +		unset($data); + +		$upload_ary['tmp_name'] = $filename; + +		/** @var filespec $file */ +		$file = $this->factory->get('filespec') +			->set_upload_ary($upload_ary) +			->set_upload_namespace($this->upload); +		$this->upload->common_checks($file); + +		return $file; +	} + +	/** +	 * Get maximum file size for remote uploads +	 * +	 * @return int Maximum file size +	 */ +	protected function get_max_file_size() +	{ +		$max_file_size = $this->upload->max_filesize; +		if (!$max_file_size) +		{ +			$max_file_size = $this->php_ini->getString('upload_max_filesize'); + +			if (!empty($max_file_size)) +			{ +				$unit = strtolower(substr($max_file_size, -1, 1)); +				$max_file_size = (int) $max_file_size; + +				switch ($unit) +				{ +					case 'g': +						$max_file_size *= 1024; +					// no break +					case 'm': +						$max_file_size *= 1024; +					// no break +					case 'k': +						$max_file_size *= 1024; +					// no break +				} +			} +		} + +		return $max_file_size; +	} +} diff --git a/phpBB/phpbb/files/types/type_interface.php b/phpBB/phpbb/files/types/type_interface.php new file mode 100644 index 0000000000..e07078349a --- /dev/null +++ b/phpBB/phpbb/files/types/type_interface.php @@ -0,0 +1,38 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\files\types; + +use phpbb\files\upload; + +interface type_interface +{ +	/** +	 * Handle upload for upload types. Arguments passed to this method will be +	 * handled by the upload type classes themselves. +	 * +	 * @return \phpbb\files\filespec|bool Filespec instance if upload is +	 *                                    successful or false if not +	 */ +	public function upload(); + +	/** +	 * Set upload instance +	 * Needs to be executed before every upload. +	 * +	 * @param upload $upload Upload instance +	 * +	 * @return type_interface Returns itself +	 */ +	public function set_upload(upload $upload); +} diff --git a/phpBB/phpbb/files/upload.php b/phpBB/phpbb/files/upload.php new file mode 100644 index 0000000000..e011e714e5 --- /dev/null +++ b/phpBB/phpbb/files/upload.php @@ -0,0 +1,395 @@ +<?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\files; + +use phpbb\filesystem\filesystem_interface; +use phpbb\language\language; +use phpbb\request\request_interface; + +/** + * File upload class + * Init class (all parameters optional and able to be set/overwritten separately) - scope is global and valid for all uploads + */ +class upload +{ +	/** @var array Allowed file extensions */ +	public $allowed_extensions = array(); + +	/** @var array Disallowed content */ +	protected $disallowed_content = array('body', 'head', 'html', 'img', 'plaintext', 'a href', 'pre', 'script', 'table', 'title'); + +	/** @var int Maximum filesize */ +	public $max_filesize = 0; + +	/** @var int Minimum width of images */ +	public $min_width = 0; + +	/** @var int Minimum height of images */ +	public $min_height = 0; + +	/** @var int Maximum width of images */ +	public $max_width = 0; + +	/** @var int Maximum height of images */ +	public $max_height = 0; + +	/** @var string Prefix for language variables of errors */ +	public $error_prefix = ''; + +	/** @var int Timeout for remote upload */ +	public $upload_timeout = 6; + +	/** @var filesystem_interface */ +	protected $filesystem; + +	/** @var \phpbb\files\factory Files factory */ +	protected $factory; + +	/** @var \bantu\IniGetWrapper\IniGetWrapper ini_get() wrapper */ +	protected $php_ini; + +	/** @var \phpbb\language\language Language class */ +	protected $language; + +	/** @var request_interface Request class */ +	protected $request; + +	/** @var string phpBB root path */ +	protected $phpbb_root_path; + +	/** +	 * Init file upload class. +	 * +	 * @param filesystem_interface $filesystem +	 * @param factory $factory Files factory +	 * @param language $language Language class +	 * @param \bantu\IniGetWrapper\IniGetWrapper $php_ini ini_get() wrapper +	 * @param request_interface $request Request class +	 * @param string $phpbb_root_path phpBB root path +	 */ +	public function __construct(filesystem_interface $filesystem, factory $factory, language $language, \bantu\IniGetWrapper\IniGetWrapper $php_ini, request_interface $request, $phpbb_root_path) +	{ +		$this->filesystem = $filesystem; +		$this->factory = $factory; +		$this->language = $language; +		$this->php_ini = $php_ini; +		$this->request = $request; +		$this->phpbb_root_path = $phpbb_root_path; +	} + +	/** +	 * Reset vars +	 */ +	public function reset_vars() +	{ +		$this->max_filesize = 0; +		$this->min_width = $this->min_height = $this->max_width = $this->max_height = 0; +		$this->error_prefix = ''; +		$this->allowed_extensions = array(); +		$this->disallowed_content = array(); +	} + +	/** +	 * Set allowed extensions +	 * +	 * @param array $allowed_extensions Allowed file extensions +	 * +	 * @return \phpbb\files\upload This instance of upload +	 */ +	public function set_allowed_extensions($allowed_extensions) +	{ +		if ($allowed_extensions !== false && is_array($allowed_extensions)) +		{ +			$this->allowed_extensions = $allowed_extensions; +		} + +		return $this; +	} + +	/** +	 * Set allowed dimensions +	 * +	 * @param int $min_width Minimum image width +	 * @param int $min_height Minimum image height +	 * @param int $max_width Maximum image width +	 * @param int $max_height Maximum image height +	 * +	 * @return \phpbb\files\upload This instance of upload +	 */ +	public function set_allowed_dimensions($min_width, $min_height, $max_width, $max_height) +	{ +		$this->min_width = (int) $min_width; +		$this->min_height = (int) $min_height; +		$this->max_width = (int) $max_width; +		$this->max_height = (int) $max_height; + +		return $this; +	} + +	/** +	 * Set maximum allowed file size +	 * +	 * @param int $max_filesize Maximum file size +	 * +	 * @return \phpbb\files\upload This instance of upload +	 */ +	public function set_max_filesize($max_filesize) +	{ +		if ($max_filesize !== false && (int) $max_filesize) +		{ +			$this->max_filesize = (int) $max_filesize; +		} + +		return $this; +	} + +	/** +	 * Set disallowed strings +	 * +	 * @param array $disallowed_content Disallowed content +	 * +	 * @return \phpbb\files\upload This instance of upload +	 */ +	public function set_disallowed_content($disallowed_content) +	{ +		if ($disallowed_content !== false && is_array($disallowed_content)) +		{ +			$this->disallowed_content = array_diff($disallowed_content, array('')); +		} + +		return $this; +	} + +	/** +	 * Set error prefix +	 * +	 * @param string $error_prefix Prefix for language variables of errors +	 * +	 * @return \phpbb\files\upload This instance of upload +	 */ +	public function set_error_prefix($error_prefix) +	{ +		$this->error_prefix = $error_prefix; + +		return $this; +	} + +	/** +	 * Handle upload based on type +	 * +	 * @param string $type Upload type +	 * +	 * @return \phpbb\files\filespec|bool A filespec instance if upload was +	 *		successful, false if there were issues or the type is not supported +	 */ +	public function handle_upload($type) +	{ +		$args = func_get_args(); +		array_shift($args); +		$type_class = $this->factory->get($type) +			->set_upload($this); + +		return (is_object($type_class)) ? call_user_func_array(array($type_class, 'upload'), $args) : false; +	} + +	/** +	 * Assign internal error +	 * +	 * @param string $errorcode Error code to assign +	 * +	 * @return string Error string +	 * @access public +	 */ +	public function assign_internal_error($errorcode) +	{ +		switch ($errorcode) +		{ +			case UPLOAD_ERR_INI_SIZE: +				$max_filesize = $this->php_ini->getString('upload_max_filesize'); +				$unit = 'MB'; + +				if (!empty($max_filesize)) +				{ +					$unit = strtolower(substr($max_filesize, -1, 1)); +					$max_filesize = (int) $max_filesize; + +					$unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB'); +				} + +				$error = (empty($max_filesize)) ? $this->language->lang($this->error_prefix . 'PHP_SIZE_NA') : $this->language->lang($this->error_prefix . 'PHP_SIZE_OVERRUN', $max_filesize, $this->language->lang($unit)); +			break; + +			case UPLOAD_ERR_FORM_SIZE: +				$max_filesize = get_formatted_filesize($this->max_filesize, false); + +				$error = $this->language->lang($this->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']); +			break; + +			case UPLOAD_ERR_PARTIAL: +				$error = $this->language->lang($this->error_prefix . 'PARTIAL_UPLOAD'); +			break; + +			case UPLOAD_ERR_NO_FILE: +				$error = $this->language->lang($this->error_prefix . 'NOT_UPLOADED'); +			break; + +			case UPLOAD_ERR_NO_TMP_DIR: +			case UPLOAD_ERR_CANT_WRITE: +				$error = $this->language->lang($this->error_prefix . 'NO_TEMP_DIR'); +			break; + +			case UPLOAD_ERR_EXTENSION: +				$error = $this->language->lang($this->error_prefix . 'PHP_UPLOAD_STOPPED'); +			break; + +			default: +				$error = false; +			break; +		} + +		return $error; +	} + +	/** +	 * Perform common file checks +	 * +	 * @param filespec $file Instance of filespec class +	 */ +	public function common_checks(&$file) +	{ +		// Filesize is too big or it's 0 if it was larger than the maxsize in the upload form +		if ($this->max_filesize && ($file->get('filesize') > $this->max_filesize || $file->get('filesize') == 0)) +		{ +			$max_filesize = get_formatted_filesize($this->max_filesize, false); + +			$file->error[] = $this->language->lang($this->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']); +		} + +		// check Filename +		if (preg_match("#[\\/:*?\"<>|]#i", $file->get('realname'))) +		{ +			$file->error[] = $this->language->lang($this->error_prefix . 'INVALID_FILENAME', $file->get('realname')); +		} + +		// Invalid Extension +		if (!$this->valid_extension($file)) +		{ +			$file->error[] = $this->language->lang($this->error_prefix . 'DISALLOWED_EXTENSION', $file->get('extension')); +		} + +		// MIME Sniffing +		if (!$this->valid_content($file)) +		{ +			$file->error[] = $this->language->lang($this->error_prefix . 'DISALLOWED_CONTENT'); +		} +	} + +	/** +	 * Check for allowed extension +	 * +	 * @param filespec $file Instance of filespec class +	 * +	 * @return bool True if extension is allowed, false if not +	 */ +	public function valid_extension(&$file) +	{ +		return (in_array($file->get('extension'), $this->allowed_extensions)) ? true : false; +	} + +	/** +	 * Check for allowed dimension +	 * +	 * @param filespec $file Instance of filespec class +	 * +	 * @return bool True if dimensions are valid or no constraints set, false +	 *			if not +	 */ +	public function valid_dimensions(&$file) +	{ +		if (!$this->max_width && !$this->max_height && !$this->min_width && !$this->min_height) +		{ +			return true; +		} + +		if (($file->get('width') > $this->max_width && $this->max_width) || +			($file->get('height') > $this->max_height && $this->max_height) || +			($file->get('width') < $this->min_width && $this->min_width) || +			($file->get('height') < $this->min_height && $this->min_height)) +		{ +			return false; +		} + +		return true; +	} + +	/** +	 * Check if form upload is valid +	 * +	 * @param string $form_name Name of form +	 * +	 * @return bool True if form upload is valid, false if not +	 */ +	public function is_valid($form_name) +	{ +		$upload = $this->request->file($form_name); + +		return (!empty($upload) && $upload['name'] !== 'none'); +	} + + +	/** +	 * Check for bad content (IE mime-sniffing) +	 * +	 * @param filespec $file Instance of filespec class +	 * +	 * @return bool True if content is valid, false if not +	 */ +	public function valid_content(&$file) +	{ +		return ($file->check_content($this->disallowed_content)); +	} + +	/** +	 * Get image type/extension mapping +	 * +	 * @return array Array containing the image types and their extensions +	 */ +	static public function image_types() +	{ +		$result = array( +			IMAGETYPE_GIF		=> array('gif'), +			IMAGETYPE_JPEG		=> array('jpg', 'jpeg'), +			IMAGETYPE_PNG		=> array('png'), +			IMAGETYPE_SWF		=> array('swf'), +			IMAGETYPE_PSD		=> array('psd'), +			IMAGETYPE_BMP		=> array('bmp'), +			IMAGETYPE_TIFF_II	=> array('tif', 'tiff'), +			IMAGETYPE_TIFF_MM	=> array('tif', 'tiff'), +			IMAGETYPE_JPC		=> array('jpg', 'jpeg'), +			IMAGETYPE_JP2		=> array('jpg', 'jpeg'), +			IMAGETYPE_JPX		=> array('jpg', 'jpeg'), +			IMAGETYPE_JB2		=> array('jpg', 'jpeg'), +			IMAGETYPE_IFF		=> array('iff'), +			IMAGETYPE_WBMP		=> array('wbmp'), +			IMAGETYPE_XBM		=> array('xbm'), +		); + +		if (defined('IMAGETYPE_SWC')) +		{ +			$result[IMAGETYPE_SWC] = array('swc'); +		} + +		return $result; +	} +} diff --git a/phpBB/phpbb/install/helper/config.php b/phpBB/phpbb/install/helper/config.php index b0480e7e5b..d5653f1924 100644 --- a/phpBB/phpbb/install/helper/config.php +++ b/phpBB/phpbb/install/helper/config.php @@ -41,7 +41,7 @@ class config  	protected $install_config_file;  	/** -	 * @var \phpbb\php\ini +	 * @var \bantu\IniGetWrapper\IniGetWrapper  	 */  	protected $php_ini; @@ -83,7 +83,7 @@ class config  	/**  	 * Constructor  	 */ -	public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, \phpbb\php\ini $php_ini, $phpbb_root_path) +	public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, \bantu\IniGetWrapper\IniGetWrapper $php_ini, $phpbb_root_path)  	{  		$this->filesystem		= $filesystem;  		$this->php_ini			= $php_ini; @@ -373,7 +373,7 @@ class config  	protected function setup_system_data()  	{  		// Query maximum runtime from php.ini -		$execution_time = $this->php_ini->get_int('max_execution_time'); +		$execution_time = $this->php_ini->getNumeric('max_execution_time');  		$execution_time = min(15, $execution_time / 2);  		$this->system_data['max_execution_time'] = $execution_time; @@ -381,6 +381,6 @@ class config  		$this->system_data['start_time'] = time();  		// Get memory limit -		$this->system_data['memory_limit'] = $this->php_ini->get_bytes('memory_limit'); +		$this->system_data['memory_limit'] = $this->php_ini->getBytes('memory_limit');  	}  } diff --git a/phpBB/phpbb/install/module/requirements/task/check_server_environment.php b/phpBB/phpbb/install/module/requirements/task/check_server_environment.php index 50efdc55a2..62485a2097 100644 --- a/phpBB/phpbb/install/module/requirements/task/check_server_environment.php +++ b/phpBB/phpbb/install/module/requirements/task/check_server_environment.php @@ -95,7 +95,7 @@ class check_server_environment extends \phpbb\install\task_base  	{  		$php_version = PHP_VERSION; -		if (version_compare($php_version, '5.3.9') < 0) +		if (version_compare($php_version, '5.4') < 0)  		{  			$this->response_helper->add_error_message('PHP_VERSION_REQD', 'PHP_VERSION_REQD_EXPLAIN'); diff --git a/phpBB/phpbb/language/language.php b/phpBB/phpbb/language/language.php index 3ffb466c19..47f055f56a 100644 --- a/phpBB/phpbb/language/language.php +++ b/phpBB/phpbb/language/language.php @@ -239,15 +239,28 @@ class language  	 */  	public function lang()  	{ +		$args = func_get_args(); +		$key = array_shift($args); + +		return $this->lang_array($key, $args); +	} + +	/** +	 * Act like lang() but takes a key and an array of parameters instead of using variadic +	 * +	 * @param string|array	$key	Language key +	 * @param array			$args	Parameters +	 * +	 * @return array|string +	 */ +	public function lang_array($key, $args = array()) +	{  		// Load common language files if they not loaded yet  		if (!$this->common_language_files_loaded)  		{  			$this->load_common_language_files();  		} -		$args = func_get_args(); -		$key = $args[0]; -  		if (is_array($key))  		{  			$lang = &$this->lang[array_shift($key)]; @@ -271,26 +284,25 @@ class language  		// If the language entry is a string, we simply mimic sprintf() behaviour  		if (is_string($lang))  		{ -			if (sizeof($args) == 1) +			if (count($args) === 0)  			{  				return $lang;  			}  			// Replace key with language entry and simply pass along... -			$args[0] = $lang; -			return call_user_func_array('sprintf', $args); +			return vsprintf($lang, $args);  		}  		else if (sizeof($lang) == 0)  		{  			// If the language entry is an empty array, we just return the language key -			return $args[0]; +			return $key;  		}  		// It is an array... now handle different nullar/singular/plural forms  		$key_found = false;  		// We now get the first number passed and will select the key based upon this number -		for ($i = 1, $num_args = sizeof($args); $i < $num_args; $i++) +		for ($i = 0, $num_args = sizeof($args); $i < $num_args; $i++)  		{  			if (is_int($args[$i]) || is_float($args[$i]))  			{ @@ -337,8 +349,7 @@ class language  		}  		// Use the language string we determined and pass it to sprintf() -		$args[0] = $lang[$key_found]; -		return call_user_func_array('sprintf', $args); +		return vsprintf($lang[$key_found], $args);  	}  	/** diff --git a/phpBB/phpbb/log/log.php b/phpBB/phpbb/log/log.php index 1b02d98b82..f0ba120625 100644 --- a/phpBB/phpbb/log/log.php +++ b/phpBB/phpbb/log/log.php @@ -249,10 +249,13 @@ class log implements \phpbb\log\log_interface  				unset($additional_data['forum_id']);  				$topic_id = isset($additional_data['topic_id']) ? (int) $additional_data['topic_id'] : 0;  				unset($additional_data['topic_id']); +				$post_id = isset($additional_data['post_id']) ? (int) $additional_data['post_id'] : 0; +				unset($additional_data['post_id']);  				$sql_ary += array(  					'log_type'		=> LOG_MOD,  					'forum_id'		=> $forum_id,  					'topic_id'		=> $topic_id, +					'post_id'		=> $post_id,  					'log_data'		=> (!empty($additional_data)) ? serialize($additional_data) : '',  				);  			break; @@ -417,7 +420,7 @@ class log implements \phpbb\log\log_interface  		$this->entry_count = 0;  		$this->last_page_offset = $offset; -		$topic_id_list = $reportee_id_list = array(); +		$post_id_list = $topic_id_list = $reportee_id_list = array();  		$profile_url = ($this->get_is_admin() && $this->phpbb_admin_path) ? append_sid("{$this->phpbb_admin_path}index.{$this->php_ext}", 'i=users&mode=overview') : append_sid("{$this->phpbb_root_path}memberlist.{$this->php_ext}", 'mode=viewprofile'); @@ -643,6 +646,7 @@ class log implements \phpbb\log\log_interface  				'time'				=> (int) $row['log_time'],  				'forum_id'			=> (int) $row['forum_id'],  				'topic_id'			=> (int) $row['topic_id'], +				'post_id'			=> (int) $row['post_id'],  				'viewforum'			=> ($row['forum_id'] && $this->auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$this->phpbb_root_path}viewforum.{$this->php_ext}", 'f=' . $row['forum_id']) : false,  				'action'			=> (isset($this->user->lang[$row['log_operation']])) ? $row['log_operation'] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}', @@ -743,6 +747,7 @@ class log implements \phpbb\log\log_interface  			foreach ($log as $key => $row)  			{  				$log[$key]['viewtopic'] = (isset($topic_auth['f_read'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}viewtopic.{$this->php_ext}", 'f=' . $topic_auth['f_read'][$row['topic_id']] . '&t=' . $row['topic_id']) : false; +				$log[$key]['viewpost'] = (isset($topic_auth['f_read'][$row['topic_id']]) && $row['post_id']) ? append_sid("{$this->phpbb_root_path}viewtopic.{$this->php_ext}", 'f=' . $topic_auth['f_read'][$row['topic_id']] . '&t=' . $row['topic_id'] . '&p=' . $row['post_id']) : false;  				$log[$key]['viewlogs'] = (isset($topic_auth['m_'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}mcp.{$this->php_ext}", 'i=logs&mode=topic_logs&t=' . $row['topic_id'], true, $this->user->session_id) : false;  			}  		} diff --git a/phpBB/phpbb/notification/type/quote.php b/phpBB/phpbb/notification/type/quote.php index 57f77bba83..1cd879579a 100644 --- a/phpBB/phpbb/notification/type/quote.php +++ b/phpBB/phpbb/notification/type/quote.php @@ -117,7 +117,7 @@ class quote extends \phpbb\notification\type\post  		$notifications = array_keys($this->find_users_for_notification($post));  		// Find the notifications we must delete -		$remove_notifications = array_diff($old_notifications, array_keys($notifications)); +		$remove_notifications = array_diff(array_keys($old_notifications), array_keys($notifications));  		// Find the notifications we must add  		$add_notifications = array(); diff --git a/phpBB/phpbb/passwords/manager.php b/phpBB/phpbb/passwords/manager.php index aa9147ecf4..b2caba81f2 100644 --- a/phpBB/phpbb/passwords/manager.php +++ b/phpBB/phpbb/passwords/manager.php @@ -50,21 +50,47 @@ class manager  	protected $config;  	/** +	 * @var bool Whether or not initialized() has been called +	 */ +	private $initialized = false; + +	/** +	 * @var array Hashing driver service collection +	 */ +	private $hashing_algorithms; + +	/** +	 * @var array List of default driver types +	 */ +	private $defaults; + +	/**  	* Construct a passwords object  	* -	* @param \phpbb\config\config $config phpBB configuration -	* @param array $hashing_algorithms Hashing driver -	*			service collection -	* @param \phpbb\passwords\helper $helper Passwords helper object -	* @param array $defaults List of default driver types +	* @param \phpbb\config\config		$config				phpBB configuration +	* @param array						$hashing_algorithms	Hashing driver service collection +	* @param \phpbb\passwords\helper	$helper				Passwords helper object +	* @param array						$defaults			List of default driver types  	*/  	public function __construct(\phpbb\config\config $config, $hashing_algorithms, helper $helper, $defaults)  	{  		$this->config = $config;  		$this->helper = $helper; +		$this->hashing_algorithms = $hashing_algorithms; +		$this->defaults = $defaults; +	} -		$this->fill_type_map($hashing_algorithms); -		$this->register_default_type($defaults); +	/** +	 * Initialize the internal state +	 */ +	protected function initialize() +	{ +		if (!$this->initialized) +		{ +			$this->initialized = true; +			$this->fill_type_map($this->hashing_algorithms); +			$this->register_default_type($this->defaults); +		}  	}  	/** @@ -144,6 +170,8 @@ class manager  			return false;  		} +		$this->initialize(); +  		// Be on the lookout for multiple hashing algorithms  		// 2 is correct: H\2a > 2, H\P > 2  		if (strlen($match[1]) > 2) @@ -192,6 +220,8 @@ class manager  			return false;  		} +		$this->initialize(); +  		// Try to retrieve algorithm by service name if type doesn't  		// start with dollar sign  		if (!is_array($type) && strpos($type, '$') !== 0 && isset($this->algorithms[$type])) @@ -242,6 +272,8 @@ class manager  			return false;  		} +		$this->initialize(); +  		// First find out what kind of hash we're dealing with  		$stored_hash_type = $this->detect_algorithm($hash);  		if ($stored_hash_type == false) @@ -297,6 +329,8 @@ class manager  	*/  	public function combined_hash_password($password_hash, $type)  	{ +		$this->initialize(); +  		$data = array(  			'prefix' => '$',  			'settings' => '$', diff --git a/phpBB/phpbb/permissions.php b/phpBB/phpbb/permissions.php index c462f72a73..0c6fad295c 100644 --- a/phpBB/phpbb/permissions.php +++ b/phpBB/phpbb/permissions.php @@ -160,6 +160,28 @@ class permissions  	}  	/** +	* Checks if a category has been defined +	* +	* @param	string	$category	Identifier of the category +	* @return	bool	True if the category is defined, false otherwise +	*/ +	public function category_defined($category) +	{ +		return isset($this->categories[$category]); +	} + +	/** +	* Checks if a permission has been defined +	* +	* @param	string	$permission	Identifier of the permission +	* @return	bool	True if the permission is defined, false otherwise +	*/ +	public function permission_defined($permission) +	{ +		return isset($this->permissions[$permission]); +	} + +	/**  	* Returns the language string of a permission  	*  	* @param	string	$permission	Identifier of the permission diff --git a/phpBB/phpbb/plupload/plupload.php b/phpBB/phpbb/plupload/plupload.php index ca78167ec0..0e67ee209b 100644 --- a/phpBB/phpbb/plupload/plupload.php +++ b/phpBB/phpbb/plupload/plupload.php @@ -39,7 +39,7 @@ class plupload  	protected $user;  	/** -	* @var \phpbb\php\ini +	* @var \bantu\IniGetWrapper\IniGetWrapper  	*/  	protected $php_ini; @@ -67,10 +67,10 @@ class plupload  	* @param \phpbb\config\config $config  	* @param \phpbb\request\request_interface $request  	* @param \phpbb\user $user -	* @param \phpbb\php\ini $php_ini +	* @param \bantu\IniGetWrapper\IniGetWrapper $php_ini  	* @param \phpbb\mimetype\guesser $mimetype_guesser  	*/ -	public function __construct($phpbb_root_path, \phpbb\config\config $config, \phpbb\request\request_interface $request, \phpbb\user $user, \phpbb\php\ini $php_ini, \phpbb\mimetype\guesser $mimetype_guesser) +	public function __construct($phpbb_root_path, \phpbb\config\config $config, \phpbb\request\request_interface $request, \phpbb\user $user, \bantu\IniGetWrapper\IniGetWrapper $php_ini, \phpbb\mimetype\guesser $mimetype_guesser)  	{  		$this->phpbb_root_path = $phpbb_root_path;  		$this->config = $config; @@ -284,9 +284,9 @@ class plupload  	public function get_chunk_size()  	{  		$max = min( -			$this->php_ini->get_bytes('upload_max_filesize'), -			$this->php_ini->get_bytes('post_max_size'), -			max(1, $this->php_ini->get_bytes('memory_limit')), +			$this->php_ini->getBytes('upload_max_filesize'), +			$this->php_ini->getBytes('post_max_size'), +			max(1, $this->php_ini->getBytes('memory_limit')),  			$this->config['max_filesize']  		); @@ -303,7 +303,7 @@ class plupload  			$this->temporary_directory,  			$this->config['plupload_salt'],  			md5($file_name), -			\filespec::get_extension($file_name) +			\phpbb\files\filespec::get_extension($file_name)  		);  	} diff --git a/phpBB/phpbb/routing/helper.php b/phpBB/phpbb/routing/helper.php new file mode 100644 index 0000000000..f56974a354 --- /dev/null +++ b/phpBB/phpbb/routing/helper.php @@ -0,0 +1,153 @@ +<?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\routing; + +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Routing\RequestContext; + +/** +* Controller helper class, contains methods that do things for controllers +*/ +class helper +{ +	/** +	 * config object +	 * @var \phpbb\config\config +	 */ +	protected $config; + +	/** +	 * phpBB router +	 * @var \phpbb\routing\router +	 */ +	protected $router; + +	/** +	 * @var \phpbb\symfony_request +	 */ +	protected $symfony_request; + +	/** +	 * @var \phpbb\request\request_interface +	 */ +	protected $request; + +	/** +	 * @var \phpbb\filesystem The filesystem object +	 */ +	protected $filesystem; + +	/** +	 * phpBB root path +	 * @var string +	 */ +	protected $phpbb_root_path; + +	/** +	 * PHP file extension +	 * @var string +	 */ +	protected $php_ext; + +	/** +	 * Constructor +	 * +	 * @param \phpbb\config\config $config Config object +	 * @param \phpbb\routing\router $router phpBB router +	 * @param \phpbb\symfony_request $symfony_request Symfony Request object +	 * @param \phpbb\request\request_interface $request phpBB request object +	 * @param \phpbb\filesystem\filesystem $filesystem The filesystem object +	 * @param string $phpbb_root_path phpBB root path +	 * @param string $php_ext PHP file extension +	 */ +	public function __construct(\phpbb\config\config $config, \phpbb\routing\router $router, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem\filesystem $filesystem, $phpbb_root_path, $php_ext) +	{ +		$this->config = $config; +		$this->router = $router; +		$this->symfony_request = $symfony_request; +		$this->request = $request; +		$this->filesystem = $filesystem; +		$this->phpbb_root_path = $phpbb_root_path; +		$this->php_ext = $php_ext; +	} + +	/** +	 * Generate a URL to a route +	 * +	 * @param string	$route		Name of the route to travel +	 * @param array	$params		String or array of additional url parameters +	 * @param bool	$is_amp		Is url using & (true) or & (false) +	 * @param string|bool		$session_id	Possibility to use a custom session id instead of the global one +	 * @param bool|string		$reference_type The type of reference to be generated (one of the constants) +	 * @return string The URL already passed through append_sid() +	 */ +	public function route($route, array $params = array(), $is_amp = true, $session_id = false, $reference_type = UrlGeneratorInterface::ABSOLUTE_PATH) +	{ +		$anchor = ''; +		if (isset($params['#'])) +		{ +			$anchor = '#' . $params['#']; +			unset($params['#']); +		} + +		$context = new RequestContext(); +		$context->fromRequest($this->symfony_request); + +		$script_name = $this->symfony_request->getScriptName(); +		$page_name = substr($script_name, -1, 1) == '/' ? '' : utf8_basename($script_name); + +		$base_url = $context->getBaseUrl(); + +		// Append page name if base URL does not contain it +		if (!empty($page_name) && strpos($base_url, '/' . $page_name) === false) +		{ +			$base_url .= '/' . $page_name; +		} + +		// If enable_mod_rewrite is false we need to replace the current front-end by app.php, otherwise we need to remove it. +		$base_url = str_replace('/' . $page_name, empty($this->config['enable_mod_rewrite']) ? '/app.' . $this->php_ext : '', $base_url); + +		// We need to update the base url to move to the directory of the app.php file if the current script is not app.php +		if ($page_name !== 'app.php') +		{ +			if (empty($this->config['enable_mod_rewrite'])) +			{ +				$base_url = str_replace('/app.' . $this->php_ext, '/' . $this->phpbb_root_path . 'app.' . $this->php_ext, $base_url); +			} +			else +			{ +				$base_url .= preg_replace(get_preg_expression('path_remove_dot_trailing_slash'), '$2', $this->phpbb_root_path); +			} +		} + +		$base_url = $this->request->escape($this->filesystem->clean_path($base_url), true); + +		$context->setBaseUrl($base_url); + +		$this->router->setContext($context); +		$route_url = $this->router->generate($route, $params, $reference_type); + +		if ($is_amp) +		{ +			$route_url = str_replace(array('&', '&'), array('&', '&'), $route_url); +		} + +		if ($reference_type === UrlGeneratorInterface::RELATIVE_PATH && empty($this->config['enable_mod_rewrite'])) +		{ +			$route_url = 'app.' . $this->php_ext . '/' . $route_url; +		} + +		return append_sid($route_url . $anchor, false, $is_amp, $session_id, true); +	} +} diff --git a/phpBB/phpbb/template/twig/extension/routing.php b/phpBB/phpbb/template/twig/extension/routing.php new file mode 100644 index 0000000000..829ce738eb --- /dev/null +++ b/phpBB/phpbb/template/twig/extension/routing.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\template\twig\extension; + +use Symfony\Bridge\Twig\Extension\RoutingExtension; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + +class routing extends RoutingExtension +{ +	/** @var \phpbb\controller\helper */ +	protected $helper; + +	/** +	* Constructor +	* +	* @param \phpbb\routing\helper $helper +	*/ +	public function __construct(\phpbb\routing\helper $helper) +	{ +		$this->helper = $helper; +	} + +	public function getPath($name, $parameters = array(), $relative = false) +	{ +		return $this->helper->route($name, $parameters, true, false, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH); +	} + +	public function getUrl($name, $parameters = array(), $schemeRelative = false) +	{ +		return $this->helper->route($name, $parameters, true, false, $schemeRelative ? UrlGeneratorInterface::NETWORK_PATH : UrlGeneratorInterface::ABSOLUTE_URL); +	} +} diff --git a/phpBB/phpbb/template/twig/node/event.php b/phpBB/phpbb/template/twig/node/event.php index b765bde98d..11fdb75247 100644 --- a/phpBB/phpbb/template/twig/node/event.php +++ b/phpBB/phpbb/template/twig/node/event.php @@ -46,7 +46,7 @@ class event extends \Twig_Node  		{  			$ext_namespace = str_replace('/', '_', $ext_namespace); -			if (defined('DEBUG')) +			if ($this->environment->isDebug())  			{  				// If debug mode is enabled, lets check for new/removed EVENT  				//  templates on page load rather than at compile. This is @@ -58,7 +58,7 @@ class event extends \Twig_Node  				;  			} -			if (defined('DEBUG') || $this->environment->getLoader()->exists('@' . $ext_namespace . '/' . $location . '.html')) +			if ($this->environment->isDebug() || $this->environment->getLoader()->exists('@' . $ext_namespace . '/' . $location . '.html'))  			{  				$compiler  					->write("\$previous_look_up_order = \$this->env->getNamespaceLookUpOrder();\n") @@ -70,7 +70,7 @@ class event extends \Twig_Node  				;  			} -			if (defined('DEBUG')) +			if ($this->environment->isDebug())  			{  				$compiler  					->outdent() diff --git a/phpBB/phpbb/textformatter/s9e/factory.php b/phpBB/phpbb/textformatter/s9e/factory.php index 4a04b34cd8..63b23d2fd0 100644 --- a/phpBB/phpbb/textformatter/s9e/factory.php +++ b/phpBB/phpbb/textformatter/s9e/factory.php @@ -104,7 +104,7 @@ class factory implements \phpbb\textformatter\cache_interface  		'b'     => '<span style="font-weight: bold"><xsl:apply-templates/></span>',  		'i'     => '<span style="font-style: italic"><xsl:apply-templates/></span>',  		'u'     => '<span style="text-decoration: underline"><xsl:apply-templates/></span>', -		'img'   => '<img src="{IMAGEURL}" alt="{L_IMAGE}"/>', +		'img'   => '<img src="{IMAGEURL}" class="postimage" alt="{L_IMAGE}"/>',  		'size'  => '<span style="font-size: {FONTSIZE}%; line-height: normal"><xsl:apply-templates/></span>',  		'color' => '<span style="color: {COLOR}"><xsl:apply-templates/></span>',  		'email' => '<a> diff --git a/phpBB/phpbb/textformatter/s9e/parser.php b/phpBB/phpbb/textformatter/s9e/parser.php index 838c211e56..ffaffbc63c 100644 --- a/phpBB/phpbb/textformatter/s9e/parser.php +++ b/phpBB/phpbb/textformatter/s9e/parser.php @@ -370,7 +370,7 @@ class parser implements \phpbb\textformatter\parser_interface  		if ($max_height || $max_width)  		{ -			$imagesize = new \fastImageSize\fastImageSize(); +			$imagesize = new \FastImageSize\FastImageSize();  			$size_info = $imagesize->getImageSize($url);  			if ($size_info === false)  			{  | 
