diff options
Diffstat (limited to 'phpBB/phpbb')
| -rw-r--r-- | phpBB/phpbb/console/command/extension/enable.php | 7 | ||||
| -rw-r--r-- | phpBB/phpbb/content_visibility.php | 126 | ||||
| -rw-r--r-- | phpBB/phpbb/datetime.php | 6 | ||||
| -rw-r--r-- | phpBB/phpbb/db/migration/data/v32x/email_force_sender.php | 37 | ||||
| -rw-r--r-- | phpBB/phpbb/db/migration/data/v32x/merge_duplicate_bbcodes.php | 75 | ||||
| -rw-r--r-- | phpBB/phpbb/db/migration/data/v32x/update_prosilver_bitfield.php | 39 | ||||
| -rw-r--r-- | phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php | 6 | ||||
| -rw-r--r-- | phpBB/phpbb/install/module/update_filesystem/task/diff_files.php | 43 | ||||
| -rw-r--r-- | phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php | 7 | ||||
| -rw-r--r-- | phpBB/phpbb/search/fulltext_mysql.php | 19 | ||||
| -rw-r--r-- | phpBB/phpbb/textformatter/s9e/bbcode_merger.php | 180 | ||||
| -rw-r--r-- | phpBB/phpbb/textformatter/s9e/factory.php | 9 | ||||
| -rw-r--r-- | phpBB/phpbb/textformatter/s9e/parser.php | 6 | ||||
| -rw-r--r-- | phpBB/phpbb/textreparser/base.php | 4 | 
14 files changed, 489 insertions, 75 deletions
| diff --git a/phpBB/phpbb/console/command/extension/enable.php b/phpBB/phpbb/console/command/extension/enable.php index f92de0069c..a6f5b10e86 100644 --- a/phpBB/phpbb/console/command/extension/enable.php +++ b/phpBB/phpbb/console/command/extension/enable.php @@ -37,6 +37,13 @@ class enable extends command  		$io = new SymfonyStyle($input, $output);  		$name = $input->getArgument('extension-name'); + +		if (!$this->manager->is_available($name)) +		{ +			$io->error($this->user->lang('CLI_EXTENSION_NOT_EXIST', $name)); +			return 1; +		} +  		$extension = $this->manager->get_extension($name);  		if (!$extension->is_enableable()) diff --git a/phpBB/phpbb/content_visibility.php b/phpBB/phpbb/content_visibility.php index bf7dc2c703..237300894b 100644 --- a/phpBB/phpbb/content_visibility.php +++ b/phpBB/phpbb/content_visibility.php @@ -131,6 +131,42 @@ class content_visibility  		return (int) $data[$mode . '_approved'] + (int) $data[$mode . '_unapproved'] + (int) $data[$mode . '_softdeleted'];  	} + +	/** +	* Check topic/post visibility for a given forum ID +	* +	* Note: Read permissions are not checked. +	* +	* @param $mode		string	Either "topic" or "post" +	* @param $forum_id	int		The forum id is used for permission checks +	* @param $data		array	Array with item information to check visibility +	* @return bool		True if the item is visible, false if not +	*/ +	public function is_visible($mode, $forum_id, $data) +	{ +		$is_visible = $this->auth->acl_get('m_approve', $forum_id) || $data[$mode . '_visibility'] == ITEM_APPROVED; + +		/** +		* Allow changing the result of calling is_visible +		* +		* @event core.phpbb_content_visibility_is_visible +		* @var	bool		is_visible			Default visibility condition, to be modified by extensions if needed. +		* @var	string		mode				Either "topic" or "post" +		* @var	int			forum_id			Forum id of the current item +		* @var	array		data				Array of item information +		* @since 3.2.2-RC1 +		*/ +		$vars = array( +			'is_visible', +			'mode', +			'forum_id', +			'data', +		); +		extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_is_visible', compact($vars))); + +		return $is_visible; +	} +  	/**  	* Create topic/post visibility SQL for a given forum ID  	* @@ -176,10 +212,14 @@ class content_visibility  		if ($this->auth->acl_get('m_approve', $forum_id))  		{ -			return $where_sql . '1 = 1'; +			$where_sql .= '1 = 1'; +		} +		else +		{ +			$where_sql .= $table_alias . $mode . '_visibility = ' . ITEM_APPROVED;  		} -		return $where_sql . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED; +		return '(' . $where_sql . ')';  	}  	/** @@ -195,16 +235,21 @@ class content_visibility  	*/  	public function get_forums_visibility_sql($mode, $forum_ids = array(), $table_alias = '')  	{ -		$where_sql = '('; +		$where_sql = ''; -		$approve_forums = array_intersect($forum_ids, array_keys($this->auth->acl_getf('m_approve', true))); +		$approve_forums = array_keys($this->auth->acl_getf('m_approve', true)); +		if (!empty($forum_ids) && !empty($approve_forums)) +		{ +			$approve_forums = array_intersect($forum_ids, $approve_forums); +			$forum_ids = array_diff($forum_ids, $approve_forums); +		}  		$get_forums_visibility_sql_overwrite = false;  		/**  		* Allow changing the result of calling get_forums_visibility_sql  		*  		* @event core.phpbb_content_visibility_get_forums_visibility_before -		* @var	string		where_sql							The action the user tried to execute +		* @var	string		where_sql							Extra visibility conditions. It must end with either an SQL "AND" or an "OR"  		* @var	string		mode								Either "topic" or "post" depending on the query this is being used in  		* @var	array		forum_ids							Array of forum ids which the posts/topics are limited to  		* @var	string		table_alias							Table alias to prefix in SQL queries @@ -229,33 +274,13 @@ class content_visibility  			return $get_forums_visibility_sql_overwrite;  		} -		if (sizeof($approve_forums)) -		{ -			// Remove moderator forums from the rest -			$forum_ids = array_diff($forum_ids, $approve_forums); - -			if (!sizeof($forum_ids)) -			{ -				// The user can see all posts/topics in all specified forums -				return $where_sql . $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums) . ')'; -			} -			else -			{ -				// Moderator can view all posts/topics in some forums -				$where_sql .= $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums) . ' OR '; -			} -		} -		else -		{ -			// The user is just a normal user -			return $where_sql . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ' -				AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids, false, true) . ')'; -		} - +		// Moderator can view all posts/topics in the moderated forums +		$where_sql .= '(' . $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums, false, true) . ' OR '; +		// Normal user can view approved items only  		$where_sql .= '(' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ' -			AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids) . '))'; +			AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids, false, true) . '))'; -		return $where_sql; +		return '(' . $where_sql . ')';  	}  	/** @@ -281,12 +306,12 @@ class content_visibility  		* Allow changing the result of calling get_global_visibility_sql  		*  		* @event core.phpbb_content_visibility_get_global_visibility_before -		* @var	array		where_sqls							The action the user tried to execute +		* @var	array		where_sqls							Array of extra visibility conditions. Will be joined by imploding with "OR".  		* @var	string		mode								Either "topic" or "post" depending on the query this is being used in  		* @var	array		exclude_forum_ids					Array of forum ids the current user doesn't have access to  		* @var	string		table_alias							Table alias to prefix in SQL queries  		* @var	array		approve_forums						Array of forums where the user has m_approve permissions -		* @var	string		visibility_sql_overwrite	Forces the function to return an implosion of where_sqls (joined by "OR") +		* @var	string		visibility_sql_overwrite			If not empty, forces the function to return visibility_sql_overwrite after executing the event  		* @since 3.1.3-RC1  		*/  		$vars = array( @@ -304,24 +329,17 @@ class content_visibility  			return $visibility_sql_overwrite;  		} -		if (sizeof($exclude_forum_ids)) -		{ -			$where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true) . ' -				AND ' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ')'; -		} -		else -		{ -			$where_sqls[] = $table_alias . $mode . '_visibility = ' . ITEM_APPROVED; -		} +		// Include approved items in all forums but the excluded +		$where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true, true) . ' +			AND ' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ')'; +		// If user has moderator permissions, add everything in the moderated forums  		if (sizeof($approve_forums))  		{  			$where_sqls[] = $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums); -			return '(' . implode(' OR ', $where_sqls) . ')';  		} -		// There is only one element, so we just return that one -		return $where_sqls[0]; +		return '(' . implode(' OR ', $where_sqls) . ')';  	}  	/** @@ -437,12 +455,13 @@ class content_visibility  		 * @var			int			topic_id		Topic of the post IDs to be modified.  		 * @var			int			forum_id		Forum ID that the topic_id resides in.  		 * @var			int			user_id			User ID doing this action. -		 * @var			int			timestamp		Timestamp of this action. +		 * @var			int			time			Timestamp of this action.  		 * @var			string		reason			Reason specified by the user for this change.  		 * @var			bool		is_starter		Are we changing the topic's starter?  		 * @var			bool		is_latest		Are we changing the topic's latest post?  		 * @var			array		data			The data array for this action.  		 * @since 3.1.10-RC1 +		 * @changed 3.2.2-RC1 Use time instead of non-existent timestamp  		 */  		$vars = array(  			'visibility', @@ -450,7 +469,7 @@ class content_visibility  			'topic_id',  			'forum_id',  			'user_id', -			'timestamp', +			'time',  			'reason',  			'is_starter',  			'is_latest', @@ -622,12 +641,13 @@ class content_visibility  		 * @var			int			topic_id		Topic of the post IDs to be modified.  		 * @var			int			forum_id		Forum ID that the topic_id resides in.  		 * @var			int			user_id			User ID doing this action. -		 * @var			int			timestamp		Timestamp of this action. +		 * @var			int			time			Timestamp of this action.  		 * @var			string		reason			Reason specified by the user for this change.  		 * @var			bool		is_starter		Are we changing the topic's starter?  		 * @var			bool		is_latest		Are we changing the topic's latest post?  		 * @var			array		data			The data array for this action.  		 * @since 3.1.10-RC1 +		 * @changed 3.2.2-RC1 Use time instead of non-existent timestamp  		 */  		$vars = array(  			'visibility', @@ -635,7 +655,7 @@ class content_visibility  			'topic_id',  			'forum_id',  			'user_id', -			'timestamp', +			'time',  			'reason',  			'is_starter',  			'is_latest', @@ -709,18 +729,19 @@ class content_visibility  		 * @var			int			topic_id			Topic of the post IDs to be modified.  		 * @var			int			forum_id			Forum ID that the topic_id resides in.  		 * @var			int			user_id				User ID doing this action. -		 * @var			int			timestamp			Timestamp of this action. +		 * @var			int			time				Timestamp of this action.  		 * @var			string		reason				Reason specified by the user for this change.  		 * @var			bool		force_update_all	Force an update on all posts within the topic, regardless of their current approval state.  		 * @var			array		data				The data array for this action.  		 * @since 3.1.10-RC1 +		 * @changed 3.2.2-RC1 Use time instead of non-existent timestamp  		 */  		$vars = array(  			'visibility',  			'topic_id',  			'forum_id',  			'user_id', -			'timestamp', +			'time',  			'reason',  			'force_update_all',  			'data', @@ -758,18 +779,19 @@ class content_visibility  		 * @var			int			topic_id			Topic of the post IDs to be modified.  		 * @var			int			forum_id			Forum ID that the topic_id resides in.  		 * @var			int			user_id				User ID doing this action. -		 * @var			int			timestamp			Timestamp of this action. +		 * @var			int			time				Timestamp of this action.  		 * @var			string		reason				Reason specified by the user for this change.  		 * @var			bool		force_update_all	Force an update on all posts within the topic, regardless of their current approval state.  		 * @var			array		data				The data array for this action.  		 * @since 3.1.10-RC1 +		 * @changed 3.2.2-RC1 Use time instead of non-existent timestamp  		 */  		$vars = array(  			'visibility',  			'topic_id',  			'forum_id',  			'user_id', -			'timestamp', +			'time',  			'reason',  			'force_update_all',  			'data', diff --git a/phpBB/phpbb/datetime.php b/phpBB/phpbb/datetime.php index 63cdba90fd..4b799b6219 100644 --- a/phpBB/phpbb/datetime.php +++ b/phpBB/phpbb/datetime.php @@ -60,6 +60,12 @@ class datetime extends \DateTime  	public function format($format = '', $force_absolute = false)  	{  		$format		= $format ? $format : $this->user->date_format; + +		if (substr($this->user->lang_name, 0,2) != 'en') +		{ +			$format = preg_replace('/([^\\\])S/','$1', $format); +		} +  		$format		= self::format_cache($format, $this->user);  		$relative	= ($format['is_short'] && !$force_absolute);  		$now		= new self($this->user, 'now', $this->user->timezone); diff --git a/phpBB/phpbb/db/migration/data/v32x/email_force_sender.php b/phpBB/phpbb/db/migration/data/v32x/email_force_sender.php new file mode 100644 index 0000000000..5319b7f76e --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v32x/email_force_sender.php @@ -0,0 +1,37 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v32x; + +class email_force_sender extends \phpbb\db\migration\migration +{ +	static public function depends_on() +	{ +		return array( +			'\phpbb\db\migration\data\v32x\v321', +		); +	} + +	public function effectively_installed() +	{ +		return isset($this->config['email_force_sender']); +	} + +	public function update_data() +	{ +		return array( +			array('config.add', array('email_force_sender', '0')), +			array('config.remove', array('email_function_name')), +		); +	} +} diff --git a/phpBB/phpbb/db/migration/data/v32x/merge_duplicate_bbcodes.php b/phpBB/phpbb/db/migration/data/v32x/merge_duplicate_bbcodes.php new file mode 100644 index 0000000000..3bf442bab5 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v32x/merge_duplicate_bbcodes.php @@ -0,0 +1,75 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v32x; + +class merge_duplicate_bbcodes extends \phpbb\db\migration\migration +{ +	public function update_data() +	{ +		return [ +			['custom', [[$this, 'update_bbcodes_table']]], +		]; +	} + +	public function update_bbcodes_table() +	{ +		$sql     = 'SELECT bbcode_id, bbcode_tag, bbcode_helpline, bbcode_match, bbcode_tpl FROM ' . BBCODES_TABLE; +		$result  = $this->sql_query($sql); +		$bbcodes = []; +		while ($row = $this->db->sql_fetchrow($result)) +		{ +			$variant = (substr($row['bbcode_tag'], -1) === '=') ? 'with': 'without'; +			$bbcode_name = rtrim($row['bbcode_tag'], '='); +			$bbcodes[$bbcode_name][$variant] = $row; +		} +		$this->db->sql_freeresult($result); + +		foreach ($bbcodes as $bbcode_name => $variants) +		{ +			if (count($variants) === 2) +			{ +				$this->merge_bbcodes($variants['without'], $variants['with']); +			} +		} +	} + +	protected function merge_bbcodes(array $without, array $with) +	{ +		$merged = $this->container->get('text_formatter.s9e.bbcode_merger')->merge_bbcodes( +			[ +				'usage'    => $without['bbcode_match'], +				'template' => $without['bbcode_tpl'] +			], +			[ +				'usage'    => $with['bbcode_match'], +				'template' => $with['bbcode_tpl'] +			] +		); +		$bbcode_data = [ +			'bbcode_tag'      => $without['bbcode_tag'], +			'bbcode_helpline' => $without['bbcode_helpline'] . ' | ' . $with['bbcode_helpline'], +			'bbcode_match'    => $merged['usage'], +			'bbcode_tpl'      => $merged['template'] +		]; + +		$sql = 'UPDATE ' . BBCODES_TABLE . ' +			SET ' . $this->db->sql_build_array('UPDATE', $bbcode_data) . ' +			WHERE bbcode_id = ' . $without['bbcode_id']; +		$this->sql_query($sql); + +		$sql = 'DELETE FROM ' . BBCODES_TABLE . ' +			WHERE bbcode_id = ' . $with['bbcode_id']; +		$this->sql_query($sql); +	} +} diff --git a/phpBB/phpbb/db/migration/data/v32x/update_prosilver_bitfield.php b/phpBB/phpbb/db/migration/data/v32x/update_prosilver_bitfield.php new file mode 100644 index 0000000000..6e51a01834 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v32x/update_prosilver_bitfield.php @@ -0,0 +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. +* +*/ + +namespace phpbb\db\migration\data\v32x; + +class update_prosilver_bitfield extends \phpbb\db\migration\migration +{ +	static public function depends_on() +	{ +		return array( +			'\phpbb\db\migration\data\v32x\v321', +		); +	} + +	public function update_data() +	{ +		return array( +			array('custom', array(array($this, 'update_bbcode_bitfield'))), +		); +	} + +	public function update_bbcode_bitfield() +	{ +		$sql = 'UPDATE ' . STYLES_TABLE . " +			SET bbcode_bitfield = '//g=' +			WHERE style_path = 'prosilver'"; +		$this->sql_query($sql); +	} +} diff --git a/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php b/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php index bce0149890..dd584eff30 100644 --- a/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php +++ b/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php @@ -187,6 +187,7 @@ class ajax_iohandler extends iohandler_base  			$tpl_ary['KEY'] = $input_name;  			$tpl_ary['S_EXPLAIN'] = false;  			$tpl_ary['DISABLED'] = isset($input_options['disabled']) ? $input_options['disabled'] : false; +			$tpl_ary['IS_SECONDARY'] = isset($input_options['is_secondary']) ? $input_options['is_secondary'] : false;  			if (isset($input_options['default']))  			{ @@ -218,6 +219,11 @@ class ajax_iohandler extends iohandler_base  			$this->template->assign_block_vars($block_name, $tpl_ary);  		} +		if (isset($form['database_update_submit']) && !$form['database_update_submit']['disabled']) +		{ +			$this->template->assign_var('FORM_TITLE', $this->language->lang('UPDATE_CONTINUE_UPDATE_PROCESS')); +		} +  		$this->template->assign_var('S_NOT_ONLY_BUTTON_FORM', $not_button_form);  		if (!$not_button_form) diff --git a/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php b/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php index 1792a3b723..8151a24f2d 100644 --- a/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php +++ b/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php @@ -103,8 +103,8 @@ class diff_files extends task_base  		$old_path = $this->update_helper->get_path_to_old_update_files();  		$new_path = $this->update_helper->get_path_to_new_update_files(); -		$files_to_diff = $this->installer_config->get('update_files', array()); -		$files_to_diff = $files_to_diff['update_with_diff']; +		$update_files = $this->installer_config->get('update_files', array()); +		$files_to_diff = $update_files['update_with_diff'];  		// Set progress bar  		$this->iohandler->set_task_count(count($files_to_diff), true); @@ -154,7 +154,6 @@ class diff_files extends task_base  				}  				$diff = new \diff3($file_contents[0], $file_contents[1], $file_contents[2]); -				unset($file_contents);  				// Handle conflicts  				if ($diff->get_num_conflicts() !== 0) @@ -162,12 +161,20 @@ class diff_files extends task_base  					$merge_conflicts[] = $filename;  				} -				// Save merged output -				$this->cache->put( -					'_file_' . md5($filename), -					base64_encode(implode("\n", $diff->merged_output())) -				); +				if ($diff->merged_output() !== $file_contents[1]) +				{ +					// Save merged output +					$this->cache->put( +						'_file_' . md5($filename), +						base64_encode(implode("\n", $diff->merged_output())) +					); +				} +				else +				{ +					unset($update_files['update_with_diff'][$key]); +				} +				unset($file_contents);  				unset($diff);  			}  			else @@ -199,6 +206,16 @@ class diff_files extends task_base  				$this->installer_config->set('merge_conflict_list', $merge_conflicts);  				$this->installer_config->set('file_diff_update_count', $progress_count); +				foreach ($update_files as $type => $files) +				{ +					if (empty($files)) +					{ +						unset($update_files[$type]); +					} +				} + +				$this->installer_config->set('update_files', $update_files); +  				// Request refresh  				throw new resource_limit_reached_exception();  			} @@ -206,6 +223,16 @@ class diff_files extends task_base  		$this->iohandler->finish_progress('ALL_FILES_DIFFED');  		$this->installer_config->set('merge_conflict_list', $merge_conflicts); + +		foreach ($update_files as $type => $files) +		{ +			if (empty($files)) +			{ +				unset($update_files[$type]); +			} +		} + +		$this->installer_config->set('update_files', $update_files);  	}  	/** diff --git a/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php b/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php index 21aa93b7ea..0b83e9a79d 100644 --- a/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php +++ b/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php @@ -99,13 +99,14 @@ class download_updated_files extends task_base  			// Add form to continue update  			$this->iohandler->add_user_form_group('UPDATE_CONTINUE_UPDATE_PROCESS', array(  				'update_recheck_files_submit'	=> array( -					'label'	=> 'UPDATE_RECHECK_UPDATE_FILES', -					'type'	=> 'submit', +					'label'			=> 'UPDATE_RECHECK_UPDATE_FILES', +					'type'			=> 'submit', +					'is_secondary'	=> empty($file_update_info),  				),  				'database_update_submit'	=> array(  					'label'		=> 'UPDATE_CONTINUE_UPDATE_PROCESS',  					'type'		=> 'submit', -					'disabled'	=> count($file_update_info) > 0, +					'disabled'	=> !empty($file_update_info),  				),  			)); diff --git a/phpBB/phpbb/search/fulltext_mysql.php b/phpBB/phpbb/search/fulltext_mysql.php index da1aad1c3a..c8df1951e3 100644 --- a/phpBB/phpbb/search/fulltext_mysql.php +++ b/phpBB/phpbb/search/fulltext_mysql.php @@ -591,6 +591,7 @@ class fulltext_mysql extends \phpbb\search\base  			WHERE MATCH ($sql_match) AGAINST ('" . $this->db->sql_escape(htmlspecialchars_decode($this->search_query)) . "' IN BOOLEAN MODE)  				$sql_where_options  			ORDER BY $sql_sort"; +		$this->db->sql_return_on_error(true);  		$result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);  		while ($row = $this->db->sql_fetchrow($result)) @@ -602,7 +603,7 @@ class fulltext_mysql extends \phpbb\search\base  		$id_ary = array_unique($id_ary);  		// if the total result count is not cached yet, retrieve it from the db -		if (!$result_count) +		if (!$result_count && count($id_ary))  		{  			$sql_found_rows = 'SELECT FOUND_ROWS() as result_count';  			$result = $this->db->sql_query($sql_found_rows); @@ -1004,6 +1005,11 @@ class fulltext_mysql extends \phpbb\search\base  			}  		} +		if (!isset($this->stats['post_text'])) +		{ +			$this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ADD FULLTEXT post_text (post_text)'); +		} +  		$this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);  		return false; @@ -1039,6 +1045,11 @@ class fulltext_mysql extends \phpbb\search\base  			$alter[] = 'DROP INDEX post_content';  		} +		if (isset($this->stats['post_text'])) +		{ +			$alter[] = 'DROP INDEX post_text'; +		} +  		if (sizeof($alter))  		{  			$this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter)); @@ -1059,7 +1070,7 @@ class fulltext_mysql extends \phpbb\search\base  			$this->get_stats();  		} -		return isset($this->stats['post_subject']) && isset($this->stats['post_content']); +		return isset($this->stats['post_subject']) && isset($this->stats['post_content']) && isset($this->stats['post_text']);  	}  	/** @@ -1103,6 +1114,10 @@ class fulltext_mysql extends \phpbb\search\base  				{  					$this->stats['post_subject'] = $row;  				} +				else if ($row['Key_name'] == 'post_text') +				{ +					$this->stats['post_text'] = $row; +				}  				else if ($row['Key_name'] == 'post_content')  				{  					$this->stats['post_content'] = $row; diff --git a/phpBB/phpbb/textformatter/s9e/bbcode_merger.php b/phpBB/phpbb/textformatter/s9e/bbcode_merger.php new file mode 100644 index 0000000000..72b1473751 --- /dev/null +++ b/phpBB/phpbb/textformatter/s9e/bbcode_merger.php @@ -0,0 +1,180 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\textformatter\s9e; + +use phpbb\textformatter\s9e\factory; +use s9e\TextFormatter\Configurator\Helpers\TemplateHelper; +use s9e\TextFormatter\Configurator\Items\UnsafeTemplate; + +class bbcode_merger +{ +	/** +	* @var \s9e\TextFormatter\Configurator $configurator Configurator instance used to inspect BBCodes +	*/ +	protected $configurator; + +	/** +	* @param \phpbb\textformatter\s9e\factory $factory +	*/ +	public function __construct(factory $factory) +	{ +		$this->configurator = $factory->get_configurator(); +	} + +	/** +	* Merge two BBCode definitions +	* +	* All of the arrays contain a "usage" element and a "template" element +	* +	* @param  array $without BBCode definition without an attribute +	* @param  array $with    BBCode definition with an attribute +	* @return array          Merged definition +	*/ +	public function merge_bbcodes(array $without, array $with) +	{ +		$without = $this->create_bbcode($without); +		$with    = $this->create_bbcode($with); + +		// Select the appropriate strategy for merging this BBCode +		if ($this->is_content_bbcode($without, $with)) +		{ +			$merged = $this->merge_content_bbcode($without, $with); +		} +		else +		{ +			$merged = $this->merge_optional_bbcode($without, $with); +		} + +		$merged['template'] = $this->normalize_template($merged['template']); + +		return $merged; +	} + +	/** +	* Create a custom BBCode for inspection +	* +	* @param  array $definition Original BBCode definition +	* @return array             Updated definition containing a BBCode object and a Tag +	*/ +	protected function create_bbcode(array $definition) +	{ +		$bbcode = $this->configurator->BBCodes->addCustom( +			$definition['usage'], +			new UnsafeTemplate($definition['template']) +		); + +		$definition['bbcode'] = $bbcode; +		$definition['tag']    = $this->configurator->tags[$bbcode->tagName]; + +		return $definition; +	} + +	/** +	* Indent given template for readability +	* +	* @param  string $template +	* @return string +	*/ +	protected function indent_template($template) +	{ +		$dom = TemplateHelper::loadTemplate($template); +		$dom->formatOutput = true; +		$template = TemplateHelper::saveTemplate($dom); + +		// Remove the first level of indentation if the template starts with whitespace +		if (preg_match('(^\\n +)', $template, $m)) +		{ +			$template = str_replace($m[0], "\n", $template); +		} + +		return trim($template); +	} + +	/** +	* Test whether the two definitions form a "content"-style BBCode +	* +	* Such BBCodes include the [URL] BBCode, which uses its text content as +	* attribute if none is provided +	* +	* @param  array $without BBCode definition without an attribute +	* @param  array $with    BBCode definition with an attribute +	* @return array          Merged definition +	*/ +	protected function is_content_bbcode(array $without, array $with) +	{ +		// Test whether we find the same non-TEXT token between "]" and "[" in the usage +		// as between ">" and "<" in the template +		return (preg_match('(\\]\\s*(\\{(?!TEXT)[^}]+\\})\\s*\\[)', $without['usage'], $m) +			&& preg_match('(>[^<]*?' . preg_quote($m[1]) . '[^>]*?<)s', $without['template'])); +	} + +	/** +	* Merge the two BBCode definitions of a "content"-style BBCode +	* +	* @param  array $without BBCode definition without an attribute +	* @param  array $with    BBCode definition with an attribute +	* @return array          Merged definition +	*/ +	protected function merge_content_bbcode(array $without, array $with) +	{ +		// Convert [X={X}] into [X={X;useContent}] +		$usage = preg_replace('(\\})', ';useContent}', $with['usage'], 1); + +		// Use the template from the definition that uses an attribute +		$template = $with['tag']->template; + +		return ['usage' => $usage, 'template' => $template]; +	} + +	/** +	* Merge the two BBCode definitions of a BBCode with an optional argument +	* +	* Such BBCodes include the [QUOTE] BBCode, which takes an optional argument +	* but otherwise does not behave differently +	* +	* @param  array $without BBCode definition without an attribute +	* @param  array $with    BBCode definition with an attribute +	* @return array          Merged definition +	*/ +	protected function merge_optional_bbcode(array $without, array $with) +	{ +		// Convert [X={X}] into [X={X?}] +		$usage = preg_replace('(\\})', '?}', $with['usage'], 1); + +		// Build a template for both versions +		$template = '<xsl:choose><xsl:when test="@' . $with['bbcode']->defaultAttribute . '">' . $with['tag']->template . '</xsl:when><xsl:otherwise>' . $without['tag']->template . '</xsl:otherwise></xsl:choose>'; + +		return ['usage' => $usage, 'template' => $template]; +	} + +	/** +	* Normalize a template +	* +	* @param  string $template +	* @return string +	*/ +	protected function normalize_template($template) +	{ +		// Normalize the template to simplify it +		$template = $this->configurator->templateNormalizer->normalizeTemplate($template); + +		// Convert xsl:value-of elements back to {L_} tokens where applicable +		$template = preg_replace('(<xsl:value-of select="\\$(L_\\w+)"/>)', '{$1}', $template); + +		// Beautify the template +		$template = $this->indent_template($template); + +		return $template; +	} +} diff --git a/phpBB/phpbb/textformatter/s9e/factory.php b/phpBB/phpbb/textformatter/s9e/factory.php index d5ad8283d9..1e85856898 100644 --- a/phpBB/phpbb/textformatter/s9e/factory.php +++ b/phpBB/phpbb/textformatter/s9e/factory.php @@ -78,7 +78,7 @@ class factory implements \phpbb\textformatter\cache_interface  		'b'     => '[B]{TEXT}[/B]',  		'code'  => '[CODE lang={IDENTIFIER;optional}]{TEXT}[/CODE]',  		'color' => '[COLOR={COLOR}]{TEXT}[/COLOR]', -		'email' => '[EMAIL={EMAIL;useContent} subject={TEXT;optional;postFilter=rawurlencode} body={TEXT;optional;postFilter=rawurlencode}]{TEXT}[/EMAIL]', +		'email' => '[EMAIL={EMAIL;useContent} subject={TEXT1;optional;postFilter=rawurlencode} body={TEXT2;optional;postFilter=rawurlencode}]{TEXT}[/EMAIL]',  		'flash' => '[FLASH={NUMBER1},{NUMBER2} width={NUMBER1;postFilter=#flashwidth} height={NUMBER2;postFilter=#flashheight} url={URL;useContent} /]',  		'i'     => '[I]{TEXT}[/I]',  		'img'   => '[IMG src={IMAGEURL;useContent}]', @@ -266,12 +266,13 @@ class factory implements \phpbb\textformatter\cache_interface  			->addParameterByName('logger')  			->addParameterByName('max_img_height')  			->addParameterByName('max_img_width') -			->markAsSafeAsURL(); +			->markAsSafeAsURL() +			->setJS('UrlFilter.filter');  		// Add default BBCodes  		foreach ($this->get_default_bbcodes($configurator) as $bbcode)  		{ -			$configurator->BBCodes->addCustom($bbcode['usage'], $bbcode['template']); +			$configurator->BBCodes->addCustom($bbcode['usage'], new UnsafeTemplate($bbcode['template']));  		}  		if (isset($configurator->tags['QUOTE']))  		{ @@ -355,8 +356,6 @@ class factory implements \phpbb\textformatter\cache_interface  		$configurator->registeredVars['max_img_width'] = 0;  		// Load the Emoji plugin and modify its tag's template to obey viewsmilies -		$configurator->Emoji->omitImageSize(); -		$configurator->Emoji->useSVG();  		$tag = $configurator->Emoji->getTag();  		$tag->template = '<xsl:choose><xsl:when test="$S_VIEWSMILIES">' . str_replace('class="emoji"', 'class="emoji smilies"', $tag->template) . '</xsl:when><xsl:otherwise><xsl:value-of select="."/></xsl:otherwise></xsl:choose>'; diff --git a/phpBB/phpbb/textformatter/s9e/parser.php b/phpBB/phpbb/textformatter/s9e/parser.php index 05ddfffa11..3698dca224 100644 --- a/phpBB/phpbb/textformatter/s9e/parser.php +++ b/phpBB/phpbb/textformatter/s9e/parser.php @@ -13,7 +13,7 @@  namespace phpbb\textformatter\s9e; -use s9e\TextFormatter\Parser\BuiltInFilters; +use s9e\TextFormatter\Parser\AttributeFilters\UrlFilter;  use s9e\TextFormatter\Parser\Logger;  /** @@ -196,7 +196,7 @@ class parser implements \phpbb\textformatter\parser_interface  	public function get_errors()  	{  		$errors = array(); -		foreach ($this->parser->getLogger()->get() as $entry) +		foreach ($this->parser->getLogger()->getLogs() as $entry)  		{  			list(, $msg, $context) = $entry; @@ -365,7 +365,7 @@ class parser implements \phpbb\textformatter\parser_interface  	static public function filter_img_url($url, array $url_config, Logger $logger, $max_height, $max_width)  	{  		// Validate the URL -		$url = BuiltInFilters::filterUrl($url, $url_config, $logger); +		$url = UrlFilter::filter($url, $url_config, $logger);  		if ($url === false)  		{  			return false; diff --git a/phpBB/phpbb/textreparser/base.php b/phpBB/phpbb/textreparser/base.php index 27d7bc1f27..2ee6ea2cb3 100644 --- a/phpBB/phpbb/textreparser/base.php +++ b/phpBB/phpbb/textreparser/base.php @@ -153,8 +153,8 @@ abstract class base implements reparser_interface  		{  			// Look for the closing tag inside of a e element, in an element of the same name, e.g.  			// <e>[/url]</e></URL> -			$match = '<e>[/' . $bbcode . ']</e></' . strtoupper($bbcode) . '>'; -			if (strpos($record['text'], $match) !== false) +			$match = '<e>[/' . $bbcode . ']</e></' . $bbcode . '>'; +			if (stripos($record['text'], $match) !== false)  			{  				return true;  			} | 
