diff options
62 files changed, 840 insertions, 205 deletions
| diff --git a/.travis.yml b/.travis.yml index b7b17f2f19..e68ba5f501 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,9 +22,12 @@ matrix:        env: DB=mysqli      - php: 5.6        env: DB=mysqli +    - php: 7.0 +      env: DB=mysqli      - php: hhvm        env: DB=mysqli    allow_failures: +    - php: 7.0      - php: hhvm    fast_finish: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..6996ca22d3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,6 @@ +## CONTRIBUTE + +1. [Create an account on phpBB.com](http://www.phpbb.com/community/ucp.php?mode=register) +2. [Create a ticket (unless there already is one)](http://tracker.phpbb.com/secure/CreateIssue!default.jspa) +3. Read our [Coding guidelines](https://wiki.phpbb.com/Coding_guidelines) and [Git Contribution Guidelines](http://wiki.phpbb.com/Git); if you're new to git, also read [the introduction guide](http://wiki.phpbb.com/display/DEV/Working+with+Git) +4. Send us a pull request diff --git a/build/sami-all.conf.php b/build/sami-all.conf.php index 68350fee8f..fb1a269206 100644 --- a/build/sami-all.conf.php +++ b/build/sami-all.conf.php @@ -18,13 +18,13 @@ $config['versions'] = Sami\Version\GitVersionCollection::create(__DIR__ . '/../'  	This would be nice, but currently causes various problems that need  	debugging.  	->addFromTags('release-3.0.*') -	->add('develop-olympus', '3.0-next (olympus)') +	->add('3.0.x', '3.0-next (olympus)')  	->addFromTags('release-3.1.*') -	->add('develop-ascraeus', '3.1-next (ascraeus)') -	->add('develop') +	->add('3.1.x', '3.1-next (ascraeus)') +	->add('master')  	*/ -	->add('develop-olympus') -	->add('develop-ascraeus') +	->add('3.0.x') +	->add('3.1.x')  ;  return new Sami\Sami($iterator, $config); diff --git a/composer.phar b/composer.pharBinary files differ index b00eef5a3e..3481b599b7 100755 --- a/composer.phar +++ b/composer.phar diff --git a/phpBB/adm/style/acp_users_profile.html b/phpBB/adm/style/acp_users_profile.html index d32348ff1c..573534fc95 100644 --- a/phpBB/adm/style/acp_users_profile.html +++ b/phpBB/adm/style/acp_users_profile.html @@ -2,6 +2,7 @@  	<fieldset>  		<legend>{L_USER_PROFILE}</legend> +	<!-- EVENT acp_users_profile_before -->  	<dl>  		<dt><label for="jabber">{L_UCP_JABBER}{L_COLON}</label></dt>  		<dd><input type="email" id="jabber" name="jabber" value="{JABBER}" /></dd> @@ -10,6 +11,7 @@  		<dt><label for="birthday">{L_BIRTHDAY}{L_COLON}</label><br /><span>{L_BIRTHDAY_EXPLAIN}</span></dt>  		<dd>{L_DAY}{L_COLON} <select id="birthday" name="bday_day">{S_BIRTHDAY_DAY_OPTIONS}</select> {L_MONTH}{L_COLON} <select name="bday_month">{S_BIRTHDAY_MONTH_OPTIONS}</select> {L_YEAR}{L_COLON} <select name="bday_year">{S_BIRTHDAY_YEAR_OPTIONS}</select></dd>  	</dl> +	<!-- EVENT acp_users_profile_after -->  	</fieldset>  	<!-- IF .profile_fields --> @@ -26,7 +28,7 @@  		<!-- END profile_fields -->  		</fieldset>  	<!-- ENDIF --> - +	<!-- EVENT acp_users_profile_custom_after -->  	<fieldset class="quick">  		<input class="button1" type="submit" name="update" value="{L_SUBMIT}" />  		{S_FORM_TOKEN} diff --git a/phpBB/adm/style/install_header.html b/phpBB/adm/style/install_header.html index c818a4fc6d..6f7f129d39 100644 --- a/phpBB/adm/style/install_header.html +++ b/phpBB/adm/style/install_header.html @@ -2,7 +2,7 @@  <html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">  <head>  <meta charset="utf-8"> -<meta name="viewport" content="width=device-width" /> +<meta name="viewport" content="width=device-width, initial-scale=1" />  <!-- IF META -->{META}<!-- ENDIF -->  <title>{PAGE_TITLE}</title> diff --git a/phpBB/adm/style/install_update_diff.html b/phpBB/adm/style/install_update_diff.html index 150ef37e0e..5f80084705 100644 --- a/phpBB/adm/style/install_update_diff.html +++ b/phpBB/adm/style/install_update_diff.html @@ -2,7 +2,7 @@  <html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">  <head>  <meta charset="utf-8"> -<meta name="viewport" content="width=device-width" /> +<meta name="viewport" content="width=device-width, initial-scale=1" />  <!-- IF META -->{META}<!-- ENDIF -->  <title>{PAGE_TITLE}</title> diff --git a/phpBB/adm/style/overall_header.html b/phpBB/adm/style/overall_header.html index f1f7eee282..ada88edff2 100644 --- a/phpBB/adm/style/overall_header.html +++ b/phpBB/adm/style/overall_header.html @@ -2,7 +2,7 @@  <html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">  <head>  <meta charset="utf-8"> -<meta name="viewport" content="width=device-width" /> +<meta name="viewport" content="width=device-width, initial-scale=1" />  <!-- IF META -->{META}<!-- ENDIF -->  <title>{PAGE_TITLE}</title> diff --git a/phpBB/adm/style/simple_header.html b/phpBB/adm/style/simple_header.html index d0b9bf62ed..f62a7a900e 100644 --- a/phpBB/adm/style/simple_header.html +++ b/phpBB/adm/style/simple_header.html @@ -2,6 +2,7 @@  <html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">  <head>  <meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1" />  <!-- IF META -->{META}<!-- ENDIF -->  <title>{PAGE_TITLE}</title> diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js index 6481a2e113..806db7d35f 100644 --- a/phpBB/assets/javascript/core.js +++ b/phpBB/assets/javascript/core.js @@ -408,7 +408,9 @@ phpbb.ajaxify = function(options) {  		$elements.find('input:submit').click(function () {  			var $this = $(this); -			$this.siblings('[data-clicked]').removeAttr('data-clicked'); +			// Remove data-clicked attribute from any submit button of form +			$this.parents('form:first').find('input:submit[data-clicked]').removeAttr('data-clicked'); +  			$this.attr('data-clicked', 'true');  		});  	} diff --git a/phpBB/docs/CREDITS.txt b/phpBB/docs/CREDITS.txt index 5c17787495..e3f2b325e8 100644 --- a/phpBB/docs/CREDITS.txt +++ b/phpBB/docs/CREDITS.txt @@ -24,9 +24,10 @@ phpBB Lead Developer:    naderman (Nils Adermann)  phpBB Developers:        bantu (Andreas Fischer)                           dhruv.goel92 (Dhruv Goel) +                         Elsensee (Oliver Schramm)                           marc1706 (Marc Alexander)                           nickvergessen (Joas Schilling) -                         nicofuma (Tristan Darricau) +                         Nicofuma (Tristan Darricau)                           prototech (Cesar Gallegos)  For a list of phpBB Team members, please see: diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md index 2926598aec..a76da95f7b 100644 --- a/phpBB/docs/events.md +++ b/phpBB/docs/events.md @@ -177,6 +177,27 @@ acp_ranks_list_header_before  * Purpose: Add content after the last header-column (but before the action column)  in the ranks list in the ACP +acp_users_profile_before +=== +* Locations: +    + adm/style/acp_users_profile.html +* Since: 3.1.4-RC1 +* Purpose: Add content before the profile details when editing a user in the ACP + +acp_users_profile_after +=== +* Locations: +    + adm/style/acp_users_profile.html +* Since: 3.1.4-RC1 +* Purpose: Add content after the profile details but before the custom profile fields when editing a user in the ACP + +acp_users_profile_custom_after +=== +* Locations: +    + adm/style/acp_users_profile.html +* Since: 3.1.4-RC1 +* Purpose: Add content after the the custom profile fields when editing a user in the ACP +  acp_simple_footer_after  ===  * Location: adm/style/simple_footer.html @@ -819,6 +840,14 @@ overall_header_head_append  * Since: 3.1.0-a1  * Purpose: Add asset calls directly before the `</head>` tag +overall_header_navbar_before +=== +* Locations: +    + styles/prosilver/template/overall_header.html +    + styles/subsilver2/template/overall_header.html +* Since: 3.1.4-RC1 +* Purpose: Add content before the navigation bar +  overall_header_navigation_append  ===  * Locations: @@ -859,6 +888,13 @@ overall_header_page_body_before  * Since: 3.1.0-b3  * Purpose: Add content after the page-header, but before the page-body +overall_header_searchbox_before +=== +* Locations: +    + styles/prosilver/template/overall_header.html +* Since: 3.1.4-RC1 +* Purpose: Add content before the search box in the header +  overall_header_stylesheets_after  ===  * Locations: diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php index 2873b48fa4..67fba1094d 100644 --- a/phpBB/includes/acp/acp_attachments.php +++ b/phpBB/includes/acp/acp_attachments.php @@ -153,7 +153,7 @@ class acp_attachments  						'img_create_thumbnail'		=> array('lang' => 'CREATE_THUMBNAIL',		'validate' => 'bool',	'type' => 'radio:yes_no', 'explain' => true),  						'img_max_thumb_width'		=> array('lang' => 'MAX_THUMB_WIDTH',		'validate' => 'int:0:999999999999999',	'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),  						'img_min_thumb_filesize'	=> array('lang' => 'MIN_THUMB_FILESIZE',	'validate' => 'int:0:999999999999999',	'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), -						'img_imagick'				=> array('lang' => 'IMAGICK_PATH',			'validate' => 'path',	'type' => 'text:20:200', 'explain' => true, 'append' => '  <span>[ <a href="' . $this->u_action . '&action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'), +						'img_imagick'				=> array('lang' => 'IMAGICK_PATH',			'validate' => 'absolute_path',	'type' => 'text:20:200', 'explain' => true, 'append' => '  <span>[ <a href="' . $this->u_action . '&action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'),  						'img_max'					=> array('lang' => 'MAX_IMAGE_SIZE',		'validate' => 'int:0:9999',	'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),  						'img_link'					=> array('lang' => 'IMAGE_LINK_SIZE',		'validate' => 'int:0:9999',	'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),  					) diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php index 89fdc8b863..0c9bc0deab 100644 --- a/phpBB/includes/acp/acp_extensions.php +++ b/phpBB/includes/acp/acp_extensions.php @@ -174,11 +174,6 @@ class acp_extensions  					trigger_error($user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING);  				} -				if ($phpbb_extension_manager->is_enabled($ext_name)) -				{ -					redirect($this->u_action); -				} -  				try  				{  					while ($phpbb_extension_manager->enable_step($ext_name)) diff --git a/phpBB/includes/acp/acp_search.php b/phpBB/includes/acp/acp_search.php index eddc6871f8..9ff999567a 100644 --- a/phpBB/includes/acp/acp_search.php +++ b/phpBB/includes/acp/acp_search.php @@ -449,7 +449,6 @@ class acp_search  		$search = null;  		$error = false; -		$search_options = '';  		foreach ($search_types as $type)  		{  			if ($this->init_search($type, $search, $error) || !method_exists($search, 'index_created')) diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index 3c957a7093..8c17fb6311 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -1414,6 +1414,18 @@ class acp_users  						$error[] = 'FORM_INVALID';  					} +					/** +					* Validate profile data in ACP before submitting to the database +					* +					* @event core.acp_users_profile_validate +					* @var	bool	submit		Flag indicating if submit button has been pressed +					* @var	array	data		Array with user profile data +					* @var	array	error		Array with the form errors +					* @since 3.1.4-RC1 +					*/ +					$vars = array('submit', 'data', 'error'); +					extract($phpbb_dispatcher->trigger_event('core.acp_users_profile_validate', compact($vars))); +  					if (!sizeof($error))  					{  						$sql_ary = array( @@ -1429,9 +1441,10 @@ class acp_users  						* @var	array	data		Array with user profile data  						* @var	int		user_id		The user id  						* @var	array	user_row	Array with the full user data +						* @var	array	sql_ary		Array with sql data  						* @since 3.1.4-RC1  						*/ -						$vars = array('cp_data', 'data', 'user_id', 'user_row'); +						$vars = array('cp_data', 'data', 'user_id', 'user_row', 'sql_ary');  						extract($phpbb_dispatcher->trigger_event('core.acp_users_profile_modify_sql_ary', compact($vars)));  						$sql = 'UPDATE ' . USERS_TABLE . ' diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index acb4690a48..573df9e55d 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -2920,19 +2920,6 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa  		// Special cases... determine  		switch ($result['status'])  		{ -			case LOGIN_ERROR_ATTEMPTS: - -				$captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); -				$captcha->init(CONFIRM_LOGIN); -				// $captcha->reset(); - -				$template->assign_vars(array( -					'CAPTCHA_TEMPLATE'			=> $captcha->get_template(), -				)); - -				$err = $user->lang[$result['error_msg']]; -			break; -  			case LOGIN_ERROR_PASSWORD_CONVERT:  				$err = sprintf(  					$user->lang[$result['error_msg']], @@ -2943,6 +2930,17 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa  				);  			break; +			case LOGIN_ERROR_ATTEMPTS: + +				$captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); +				$captcha->init(CONFIRM_LOGIN); +				// $captcha->reset(); + +				$template->assign_vars(array( +					'CAPTCHA_TEMPLATE'			=> $captcha->get_template(), +				)); +			// no break; +  			// Username, password, etc...  			default:  				$err = $user->lang[$result['error_msg']]; diff --git a/phpBB/includes/functions_acp.php b/phpBB/includes/functions_acp.php index e30c6da505..a53a54368e 100644 --- a/phpBB/includes/functions_acp.php +++ b/phpBB/includes/functions_acp.php @@ -550,6 +550,9 @@ function validate_config_vars($config_vars, &$cfg_array, &$error)  				$cfg_array[$config_name] = trim($destination); +			// Absolute file path +			case 'absolute_path': +			case 'absolute_path_writable':  			// Path being relative (still prefixed by phpbb_root_path), but with the ability to escape the root dir...  			case 'path':  			case 'wpath': @@ -568,20 +571,22 @@ function validate_config_vars($config_vars, &$cfg_array, &$error)  					break;  				} -				if (!file_exists($phpbb_root_path . $cfg_array[$config_name])) +				$path = in_array($config_definition['validate'], array('wpath', 'path', 'rpath', 'rwpath')) ? $phpbb_root_path . $cfg_array[$config_name] : $cfg_array[$config_name]; + +				if (!file_exists($path))  				{  					$error[] = sprintf($user->lang['DIRECTORY_DOES_NOT_EXIST'], $cfg_array[$config_name]);  				} -				if (file_exists($phpbb_root_path . $cfg_array[$config_name]) && !is_dir($phpbb_root_path . $cfg_array[$config_name])) +				if (file_exists($path) && !is_dir($path))  				{  					$error[] = sprintf($user->lang['DIRECTORY_NOT_DIR'], $cfg_array[$config_name]);  				}  				// Check if the path is writable -				if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath') +				if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath' || $config_definition['validate'] === 'absolute_path_writable')  				{ -					if (file_exists($phpbb_root_path . $cfg_array[$config_name]) && !phpbb_is_writable($phpbb_root_path . $cfg_array[$config_name])) +					if (file_exists($path) && !phpbb_is_writable($path))  					{  						$error[] = sprintf($user->lang['DIRECTORY_NOT_WRITABLE'], $cfg_array[$config_name]);  					} diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index b016659541..79f9db2f3f 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -618,7 +618,7 @@ function move_posts($post_ids, $topic_id, $auto_sync = true)  */  function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true)  { -	global $db, $config, $phpbb_container; +	global $db, $config, $phpbb_container, $phpbb_dispatcher;  	$approved_topics = 0;  	$forum_ids = $topic_ids = array(); @@ -672,6 +672,20 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s  	$table_ary = array(BOOKMARKS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, POLL_VOTES_TABLE, POLL_OPTIONS_TABLE, TOPICS_WATCH_TABLE, TOPICS_TABLE); +	/** +	 * Perform additional actions before topic(s) deletion +	 * +	 * @event core.delete_topics_before_query +	 * @var	array	table_ary	Array of tables from which all rows will be deleted that hold a topic_id occuring in topic_ids +	 * @var	array	topic_ids	Array of topic ids to delete +	 * @since 3.1.4-RC1 +	 */ +	$vars = array( +			'table_ary', +			'topic_ids', +	); +	extract($phpbb_dispatcher->trigger_event('core.delete_topics_before_query', compact($vars))); +  	foreach ($table_ary as $table)  	{  		$sql = "DELETE FROM $table @@ -680,6 +694,18 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s  	}  	unset($table_ary); +	/** +	 * Perform additional actions after topic(s) deletion +	 * +	 * @event core.delete_topics_after_query +	 * @var	array	topic_ids	Array of topic ids that were deleted +	 * @since 3.1.4-RC1 +	 */ +	$vars = array( +			'topic_ids', +	); +	extract($phpbb_dispatcher->trigger_event('core.delete_topics_after_query', compact($vars))); +  	$moved_topic_ids = array();  	// update the other forums diff --git a/phpBB/includes/functions_mcp.php b/phpBB/includes/functions_mcp.php index eb4fc6d44b..ed96dcf338 100644 --- a/phpBB/includes/functions_mcp.php +++ b/phpBB/includes/functions_mcp.php @@ -423,28 +423,6 @@ function phpbb_mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by  					AND t.topic_id = p.topic_id  					AND t.topic_visibility <> p.post_visibility'; -			/** -			* This event allows you to control the SQL query to retrieve the list of unapproved and deleted posts -			* -			* @event core.mcp_sorting_unapproved_deleted_posts_query_before -			* @var	string	sql					The current SQL search string -			* @var	int		forum_id			The forum id of the posts the user is trying to access -			* @var	int		topic_id			The topic id of the posts the user is trying to access -			* @var	int		min_time			Integer with the minimum post time that the user is searching for -			* @var	int		visibility_const	Integer with one of the possible ITEM_* constant values -			* @var	string	where_sql			Extra information included in the WHERE clause. It must end with "WHERE" or "AND" or "OR" -			* @since 3.1.4-RC1 -			*/ -			$vars = array( -				'sql', -				'forum_id', -				'topic_id', -				'min_time', -				'visibility_const', -				'where_sql', -			); -			extract($phpbb_dispatcher->trigger_event('core.mcp_sorting_unapproved_deleted_posts_query_before', compact($vars))); -  			if ($min_time)  			{  				$sql .= ' AND post_time >= ' . $min_time; @@ -575,6 +553,56 @@ function phpbb_mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by  			break;  	} +	// Default total to -1 to allow editing by the event +	$total = -1; + +	/** +	* This event allows you to control the SQL query used to get the total number +	* of reports the user can access. +	* +	* This total is used for the pagination and for displaying the total number +	* of reports to the user +	* +	* +	* @event core.mcp_sorting_query_before +	* @var	string	sql					The current SQL search string +	* @var	string	mode				An id related to the module(s) the user is viewing +	* @var	string	type				Which kind of information is this being used for displaying. Posts, topics, etc... +	* @var	int		forum_id			The forum id of the posts the user is trying to access, if not 0 +	* @var	int		topic_id			The topic id of the posts the user is trying to access, if not 0 +	* @var	int		sort_days			The max age of the oldest report to be shown, in days +	* @var	string	sort_key			The way the user has decided to sort the data. +	*									The valid values must be in the keys of the sort_by_* variables +	* @var	string	sort_dir			Either 'd' for "DESC" or 'a' for 'ASC' in the SQL query +	* @var	int		limit_days			The possible max ages of the oldest report for the user to choose, in days. +	* @var	array	sort_by_sql			SQL text (values) for the possible names of the ways of sorting data (keys). +	* @var	array	sort_by_text		Language text (values) for the possible names of the ways of sorting data (keys). +	* @var	int		min_time			Integer with the minimum post time that the user is searching for +	* @var	int		limit_time_sql		Time limiting options used in the SQL query. +	* @var	int		total				The total number of reports that exist. Only set if you want to override the result +	* @var	string	where_sql			Extra information included in the WHERE clause. It must end with "WHERE" or "AND" or "OR". +	*									Set to "WHERE" and set total above -1 to override the total value +	* @since 3.1.4-RC1 +	*/ +	$vars = array( +		'sql', +		'mode', +		'type', +		'forum_id', +		'topic_id', +		'sort_days', +		'sort_key', +		'sort_dir', +		'limit_days', +		'sort_by_sql', +		'sort_by_text', +		'min_time', +		'limit_time_sql', +		'total', +		'where_sql', +	); +	extract($phpbb_dispatcher->trigger_event('core.mcp_sorting_query_before', compact($vars))); +  	if (!isset($sort_by_sql[$sort_key]))  	{  		$sort_key = $default_key; @@ -606,7 +634,7 @@ function phpbb_mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by  		$total = (int) $db->sql_fetchfield('total');  		$db->sql_freeresult($result);  	} -	else +	else if ($total < -1)  	{  		$total = -1;  	} diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index 1241b8bd0e..10f1a5b8c1 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -226,6 +226,31 @@ class mcp_main  			break;  			default: +				if ($quickmod) +				{ +					switch ($action) +					{ +						case 'lock': +						case 'unlock': +						case 'make_announce': +						case 'make_sticky': +						case 'make_global': +						case 'make_normal': +						case 'make_onindex': +						case 'move': +						case 'fork': +						case 'delete_topic': +							trigger_error('TOPIC_NOT_EXIST'); +						break; + +						case 'lock_post': +						case 'unlock_post': +						case 'delete_post': +							trigger_error('POST_NOT_EXIST'); +						break; +					} +				} +  				trigger_error('NO_MODE', E_USER_ERROR);  			break;  		} diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index a3cffe51e6..8347830d0f 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -259,6 +259,8 @@ function mcp_topic_view($id, $mode, $action)  		* @var	int		current_row_number	Number of the post on this page  		* @var	array	post_row			Template block array of the current post  		* @var	array	row					Array with original post and user data +		* @var	array	topic_info			Array with topic data +		* @var	int		total				Total posts count  		* @since 3.1.4-RC1  		*/  		$vars = array( @@ -270,6 +272,8 @@ function mcp_topic_view($id, $mode, $action)  			'current_row_number',  			'post_row',  			'row', +			'topic_info', +			'total',  		);  		extract($phpbb_dispatcher->trigger_event('core.mcp_topic_review_modify_row', compact($vars))); diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 04a2726d22..63e027cd66 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -21,6 +21,19 @@ if (!defined('IN_PHPBB'))  if (!class_exists('bbcode'))  { +	// The following lines are for extensions which include message_parser.php +	// while $phpbb_root_path and $phpEx are out of the script scope +	// which may lead to the 'Undefined variable' and 'failed to open stream' errors +	if (!isset($phpbb_root_path)) +	{ +		global $phpbb_root_path; +	} + +	if (!isset($phpEx)) +	{ +		global $phpEx; +	} +  	include($phpbb_root_path . 'includes/bbcode.' . $phpEx);  } diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index f3b59186a6..51018e3a5d 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -90,6 +90,32 @@ function compose_pm($id, $mode, $action, $user_folders = array())  	// we include the language file here  	$user->add_lang('viewtopic'); +	/** +	* Modify the default vars before composing a PM +	* +	* @event core.ucp_pm_compose_modify_data +	* @var	int		msg_id					post_id in the page request +	* @var	int		to_user_id				The id of whom the message is to +	* @var	int		to_group_id				The id of the group the message is to +	* @var	bool	submit					Whether the form has been submitted +	* @var	bool	preview					Whether the user is previewing the PM or not +	* @var	string	action					One of: post, reply, quote, forward, quotepost, edit, delete, smilies +	* @var	bool	delete					Whether the user is deleting the PM +	* @var	int		reply_to_all			Value of reply_to_all request variable. +	* @since 3.1.4-RC1 +	*/ +	$vars = array( +		'msg_id', +		'to_user_id', +		'to_group_id', +		'submit', +		'preview', +		'action', +		'delete', +		'reply_to_all', +	); +	extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_modify_data', compact($vars))); +  	// Output PM_TO box if message composing  	if ($action != 'edit')  	{ diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index 2c786a1d39..8d8d42e742 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -115,16 +115,16 @@ class ucp_profile  					}  					/** -					* Validate user data on editing profile in UCP +					* Validate user data on editing registration data in UCP  					* -					* @event core.ucp_profile_info_validate_data +					* @event core.ucp_profile_reg_details_validate  					* @var	array	data			Array with user profile data  					* @var	bool	submit			Flag indicating if submit button has been pressed  					* @var array	error			Array of any generated errors  					* @since 3.1.4-RC1  					*/  					$vars = array('data', 'submit', 'error'); -					extract($phpbb_dispatcher->trigger_event('core.ucp_profile_info_validate_data', compact($vars))); +					extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_validate', compact($vars)));  					if (!sizeof($error))  					{ @@ -365,6 +365,18 @@ class ucp_profile  						$error[] = 'FORM_INVALID';  					} +					/** +					* Validate user data on editing profile in UCP +					* +					* @event core.ucp_profile_validate_profile_info +					* @var	array	data			Array with user profile data +					* @var	bool	submit			Flag indicating if submit button has been pressed +					* @var array	error			Array of any generated errors +					* @since 3.1.4-RC1 +					*/ +					$vars = array('data', 'submit', 'error'); +					extract($phpbb_dispatcher->trigger_event('core.ucp_profile_validate_profile_info', compact($vars))); +  					if (!sizeof($error))  					{  						$data['notify'] = $user->data['user_notify_type']; diff --git a/phpBB/phpbb/avatar/driver/local.php b/phpBB/phpbb/avatar/driver/local.php index 8888686b2d..36087f8ba0 100644 --- a/phpBB/phpbb/avatar/driver/local.php +++ b/phpBB/phpbb/avatar/driver/local.php @@ -23,8 +23,10 @@ class local extends \phpbb\avatar\driver\driver  	*/  	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(); +  		return array( -			'src' => $this->path_helper->get_web_root_path() . $this->config['avatar_gallery_path'] . '/' . $row['avatar'], +			'src' => $root_path . $this->config['avatar_gallery_path'] . '/' . $row['avatar'],  			'width' => $row['avatar_width'],  			'height' => $row['avatar_height'],  		); diff --git a/phpBB/phpbb/avatar/driver/upload.php b/phpBB/phpbb/avatar/driver/upload.php index 003b23659f..ee36243844 100644 --- a/phpBB/phpbb/avatar/driver/upload.php +++ b/phpBB/phpbb/avatar/driver/upload.php @@ -48,8 +48,10 @@ class upload extends \phpbb\avatar\driver\driver  	*/  	public function get_data($row, $ignore_config = false)  	{ +		$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $this->path_helper->get_web_root_path(); +  		return array( -			'src' => $this->path_helper->get_web_root_path() . 'download/file.' . $this->php_ext . '?avatar=' . $row['avatar'], +			'src' => $root_path . 'download/file.' . $this->php_ext . '?avatar=' . $row['avatar'],  			'width' => $row['avatar_width'],  			'height' => $row['avatar_height'],  		); diff --git a/phpBB/phpbb/cache/driver/file.php b/phpBB/phpbb/cache/driver/file.php index fd5bce4515..9a7c4aec7f 100644 --- a/phpBB/phpbb/cache/driver/file.php +++ b/phpBB/phpbb/cache/driver/file.php @@ -279,6 +279,7 @@ class file extends \phpbb\cache\driver\base  		if ($var_name[0] == '_')  		{  			global $phpEx; +			$var_name = $this->clean_varname($var_name);  			return file_exists($this->cache_dir . 'data' . $var_name . ".$phpEx");  		}  		else @@ -334,6 +335,7 @@ class file extends \phpbb\cache\driver\base  	{  		global $phpEx; +		$filename = $this->clean_varname($filename);  		$file = "{$this->cache_dir}$filename.$phpEx";  		$type = substr($filename, 0, strpos($filename, '_')); @@ -516,6 +518,7 @@ class file extends \phpbb\cache\driver\base  	{  		global $phpEx; +		$filename = $this->clean_varname($filename);  		$file = "{$this->cache_dir}$filename.$phpEx";  		$lock = new \phpbb\lock\flock($file); @@ -584,4 +587,15 @@ class file extends \phpbb\cache\driver\base  		return $return_value;  	} + +	/** +	* Replace slashes in the file name +	* +	* @param string $varname name of a cache variable +	* @return string $varname name that is safe to use as a filename +	*/ +	protected function clean_varname($varname) +	{ +		return str_replace('/', '-', $varname); +	}  } diff --git a/phpBB/phpbb/captcha/plugins/qa.php b/phpBB/phpbb/captcha/plugins/qa.php index a7ba994cc3..04052b3406 100644 --- a/phpBB/phpbb/captcha/plugins/qa.php +++ b/phpBB/phpbb/captcha/plugins/qa.php @@ -125,7 +125,7 @@ class qa  	*/  	public function is_available()  	{ -		global $config, $db, $phpbb_root_path, $phpEx, $user; +		global $config, $db, $user;  		// load language file for pretty display in the ACP dropdown  		$user->add_lang('captcha_qa'); @@ -263,7 +263,7 @@ class qa  	*/  	function garbage_collect($type = 0)  	{ -		global $db, $config; +		global $db;  		$sql = 'SELECT c.confirm_id  			FROM ' . $this->table_qa_confirm . ' c @@ -310,8 +310,6 @@ class qa  		$db_tool = new \phpbb\db\tools($db); -		$tables = array($this->table_captcha_questions, $this->table_captcha_answers, $this->table_qa_confirm); -  		$schemas = array(  				$this->table_captcha_questions		=> array (  					'COLUMNS' => array( @@ -366,7 +364,7 @@ class qa  	*/  	function validate()  	{ -		global $config, $db, $user; +		global $user;  		$error = ''; @@ -414,7 +412,7 @@ class qa  		if (!sizeof($this->question_ids))  		{ -			return false; +			return;  		}  		$this->confirm_id = md5(unique_id($user->ip));  		$this->question = (int) array_rand($this->question_ids); @@ -440,7 +438,7 @@ class qa  		if (!sizeof($this->question_ids))  		{ -			return false; +			return;  		}  		$this->question = (int) array_rand($this->question_ids); @@ -611,8 +609,8 @@ class qa  	*/  	function acp_page($id, &$module)  	{ -		global $db, $user, $auth, $template; -		global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; +		global $user, $template; +		global $config;  		$user->add_lang('acp/board');  		$user->add_lang('captcha_qa'); @@ -674,11 +672,7 @@ class qa  		else  		{  			// okay, show the editor -			$error = false; -			$input_question = request_var('question_text', '', true); -			$input_answers = request_var('answers', '', true); -			$input_lang = request_var('lang_iso', '', true); -			$input_strict = request_var('strict', false); +			$question_input = $this->acp_get_question_input();  			$langs = $this->get_languages();  			foreach ($langs as $lang => $entry) @@ -697,13 +691,11 @@ class qa  			{  				if ($question = $this->acp_get_question_data($question_id))  				{ -					$answers = (isset($input_answers[$lang])) ? $input_answers[$lang] : implode("\n", $question['answers']); -  					$template->assign_vars(array( -						'QUESTION_TEXT'		=> ($input_question) ? $input_question : $question['question_text'], -						'LANG_ISO'			=> ($input_lang) ? $input_lang : $question['lang_iso'], -						'STRICT'			=> (isset($_REQUEST['strict'])) ? $input_strict : $question['strict'], -						'ANSWERS'			=> $answers, +						'QUESTION_TEXT'		=> ($question_input['question_text']) ? $question_input['question_text'] : $question['question_text'], +						'LANG_ISO'			=> ($question_input['lang_iso']) ? $question_input['lang_iso'] : $question['lang_iso'], +						'STRICT'			=> (isset($_REQUEST['strict'])) ? $question_input['strict'] : $question['strict'], +						'ANSWERS'			=> implode("\n", $question['answers']),  					));  				}  				else @@ -714,18 +706,16 @@ class qa  			else  			{  				$template->assign_vars(array( -					'QUESTION_TEXT'		=> $input_question, -					'LANG_ISO'			=> $input_lang, -					'STRICT'			=> $input_strict, -					'ANSWERS'			=> $input_answers, +					'QUESTION_TEXT'		=> $question_input['question_text'], +					'LANG_ISO'			=> $question_input['lang_iso'], +					'STRICT'			=> $question_input['strict'], +					'ANSWERS'			=> (is_array($question_input['answers'])) ? implode("\n", $question_input['answers']) : '',  				));  			}  			if ($submit && check_form_key($form_key))  			{ -				$data = $this->acp_get_question_input(); - -				if (!$this->validate_input($data)) +				if (!$this->validate_input($question_input))  				{  					$template->assign_vars(array(  						'S_ERROR'			=> true, @@ -735,11 +725,11 @@ class qa  				{  					if ($question_id)  					{ -						$this->acp_update_question($data, $question_id); +						$this->acp_update_question($question_input, $question_id);  					}  					else  					{ -						$this->acp_add_question($data); +						$this->acp_add_question($question_input);  					}  					add_log('admin', 'LOG_CONFIG_VISUAL'); @@ -819,6 +809,8 @@ class qa  			return $question;  		} + +		return false;  	}  	/** @@ -827,13 +819,21 @@ class qa  	function acp_get_question_input()  	{  		$answers = utf8_normalize_nfc(request_var('answers', '', true)); + +		// Convert answers into array and filter if answers are set +		if (strlen($answers)) +		{ +			$answers = array_filter(array_map('trim', explode("\n", $answers)), function ($value) { +				return $value !== ''; +			}); +		} +  		$question = array(  			'question_text'	=> request_var('question_text', '', true),  			'strict'		=> request_var('strict', false),  			'lang_iso'		=> request_var('lang_iso', ''), -			'answers'		=> (strlen($answers)) ? explode("\n", $answers) : '', +			'answers'		=> $answers,  		); -  		return $question;  	} diff --git a/phpBB/phpbb/content_visibility.php b/phpBB/phpbb/content_visibility.php index 700009da6a..0ba0489cb7 100644 --- a/phpBB/phpbb/content_visibility.php +++ b/phpBB/phpbb/content_visibility.php @@ -237,7 +237,7 @@ class content_visibility  			if (!sizeof($forum_ids))  			{  				// The user can see all posts/topics in all specified forums -				return $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums); +				return $where_sql . $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums) . ')';  			}  			else  			{ @@ -248,8 +248,8 @@ class content_visibility  		else  		{  			// The user is just a normal user -			return $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ' -				AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids, false, true); +			return $where_sql . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ' +				AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids, false, true) . ')';  		}  		$where_sql .= '(' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ' diff --git a/phpBB/phpbb/db/migration/data/v310/avatars.php b/phpBB/phpbb/db/migration/data/v310/avatars.php index 2698adeed5..9b03a8fa94 100644 --- a/phpBB/phpbb/db/migration/data/v310/avatars.php +++ b/phpBB/phpbb/db/migration/data/v310/avatars.php @@ -17,7 +17,29 @@ class avatars extends \phpbb\db\migration\migration  {  	public function effectively_installed()  	{ -		return isset($this->config['allow_avatar_gravatar']); +		// Get current avatar type of guest user +		$sql = 'SELECT user_avatar_type +			FROM ' . $this->table_prefix . 'users +			WHERE user_id = ' . ANONYMOUS; +		$result = $this->db->sql_query($sql); +		$backup_type = $this->db->sql_fetchfield('user_avatar_type'); +		$this->db->sql_freeresult($result); + +		// Try to set avatar type to string +		$sql = 'UPDATE ' . $this->table_prefix . "users +			SET user_avatar_type = 'avatar.driver.upload' +			WHERE user_id = " . ANONYMOUS; +		$this->db->sql_return_on_error(true); +		$effectively_installed = $this->db->sql_query($sql); +		$this->db->sql_return_on_error(); + +		// Restore avatar type of guest user to previous state +		$sql = 'UPDATE ' . $this->table_prefix . "users +			SET user_avatar_type = '{$backup_type}' +			WHERE user_id = " . ANONYMOUS; +		$this->db->sql_query($sql); + +		return $effectively_installed !== false;  	}  	static public function depends_on() diff --git a/phpBB/phpbb/plupload/plupload.php b/phpBB/phpbb/plupload/plupload.php index 3c686a552f..fcce5b3bd8 100644 --- a/phpBB/phpbb/plupload/plupload.php +++ b/phpBB/phpbb/plupload/plupload.php @@ -326,7 +326,7 @@ class plupload  		$tmp_file = $this->temporary_filepath($upload['tmp_name']); -		if (!move_uploaded_file($upload['tmp_name'], $tmp_file)) +		if (!phpbb_is_writable($this->temporary_directory) || !move_uploaded_file($upload['tmp_name'], $tmp_file))  		{  			$this->emit_error(103, 'PLUPLOAD_ERR_MOVE_UPLOADED');  		} diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php index 93ea46ca60..4d02dd1cbf 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -823,6 +823,13 @@ class fulltext_native extends \phpbb\search\base  			);  		} +		// if using mysql and the total result count is not calculated yet, get it from the db +		if (!$total_results && $is_mysql) +		{ +			// Also count rows for the query as if there was not LIMIT. Add SQL_CALC_FOUND_ROWS to SQL +			$sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT']; +		} +  		$sql_array['WHERE'] = implode(' AND ', $sql_where);  		$sql_array['GROUP_BY'] = ($group_by) ? (($type == 'posts') ? 'p.post_id' : 'p.topic_id') . ', ' . $sort_by_sql[$sort_key] : '';  		$sql_array['ORDER_BY'] = $sql_sort; @@ -838,19 +845,9 @@ class fulltext_native extends \phpbb\search\base  		}  		$this->db->sql_freeresult($result); -		// if we use mysql and the total result count is not cached yet, retrieve it from the db  		if (!$total_results && $is_mysql)  		{ -			// Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it -			$sql_array_copy = $sql_array; -			$sql_array_copy['SELECT'] = 'SQL_CALC_FOUND_ROWS p.post_id '; - -			$sql_calc = $this->db->sql_build_query('SELECT', $sql_array_copy); -			unset($sql_array_copy); - -			$this->db->sql_query($sql_calc); -			$this->db->sql_freeresult($result); - +			// Get the number of results as calculated by MySQL  			$sql_count = 'SELECT FOUND_ROWS() as total_results';  			$result = $this->db->sql_query($sql_count);  			$total_results = (int) $this->db->sql_fetchfield('total_results'); diff --git a/phpBB/posting.php b/phpBB/posting.php index ac412c0c73..f0446cf2db 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -330,14 +330,17 @@ switch ($mode)  		{  			$is_authed = true;  		} -	break; + +	// no break;  	case 'soft_delete': -		if ($user->data['is_registered'] && $phpbb_content_visibility->can_soft_delete($forum_id, $post_data['poster_id'], $post_data['post_edit_locked'])) +		if (!$is_authed && $user->data['is_registered'] && $phpbb_content_visibility->can_soft_delete($forum_id, $post_data['poster_id'], $post_data['post_edit_locked']))  		{ +			// Fall back to soft_delete if we have no permissions to delete posts but to soft delete them  			$is_authed = true; +			$mode = 'soft_delete';  		} -		else +		else if (!$is_authed)  		{  			// Display the same error message for softdelete we use for delete  			$mode = 'delete'; @@ -1517,9 +1520,13 @@ if (!sizeof($error) && $preview)  			'L_MAX_VOTES'		=> $user->lang('MAX_OPTIONS_SELECT', (int) $post_data['poll_max_options']),  		)); -		$parse_poll->message = implode("\n", $post_data['poll_options']); -		$parse_poll->format_display($post_data['enable_bbcode'], $post_data['enable_urls'], $post_data['enable_smilies']); -		$preview_poll_options = explode('<br />', $parse_poll->message); +		$preview_poll_options = array(); +		foreach ($post_data['poll_options'] as $poll_option) +		{ +			$parse_poll->message = $poll_option; +			$parse_poll->format_display($post_data['enable_bbcode'], $post_data['enable_urls'], $post_data['enable_smilies']); +			$preview_poll_options[] = $parse_poll->message; +		}  		unset($parse_poll);  		foreach ($preview_poll_options as $key => $option) diff --git a/phpBB/styles/prosilver/template/forum_fn.js b/phpBB/styles/prosilver/template/forum_fn.js index aabc5679f6..7a377a4973 100644 --- a/phpBB/styles/prosilver/template/forum_fn.js +++ b/phpBB/styles/prosilver/template/forum_fn.js @@ -376,12 +376,19 @@ function parseDocument($container) {  		function resize() {  			var width = 0, -				diff = $left.outerWidth(true) - $left.width(); +				diff = $left.outerWidth(true) - $left.width(), +				minWidth = Math.max($this.width() / 3, 240), +				maxWidth;  			$right.each(function() { -				width += $(this).outerWidth(true); +				var $this = $(this); +				if ($this.is(':visible')) { +					width += $this.outerWidth(true); +				}  			}); -			$left.css('max-width', Math.floor($this.width() - width - diff) + 'px'); + +			maxWidth = $this.width() - width - diff; +			$left.css('max-width', Math.floor(Math.max(maxWidth, minWidth)) + 'px');  		}  		resize(); @@ -410,7 +417,13 @@ function parseDocument($container) {  		// Function that checks breadcrumbs  		function check() {  			var height = $this.height(), -				width = $body.width(); +				width; + +			// Test max-width set in code for .navlinks above +			width = parseInt($this.css('max-width')); +			if (!width) { + 				width = $body.width(); +			}  			maxHeight = parseInt($this.css('line-height'));  			$links.each(function() { diff --git a/phpBB/styles/prosilver/template/mcp_logs.html b/phpBB/styles/prosilver/template/mcp_logs.html index eaa3838f17..4f74085968 100644 --- a/phpBB/styles/prosilver/template/mcp_logs.html +++ b/phpBB/styles/prosilver/template/mcp_logs.html @@ -22,10 +22,10 @@  	<table class="table1">  	<thead>  	<tr> -		<th>{L_USERNAME}</th> -		<th style="text-align: center">{L_IP}</th> -		<th style="text-align: center">{L_TIME}</th> -		<th>{L_ACTION}</th> +		<th class="name">{L_USERNAME}</th> +		<th class="center">{L_IP}</th> +		<th class="center">{L_TIME}</th> +		<th class="name">{L_ACTION}</th>  		<!-- IF S_CLEAR_ALLOWED --><th>{L_MARK}</th><!-- ENDIF -->  	</tr>  	</thead> @@ -34,8 +34,8 @@  		<!-- BEGIN log -->  		<!-- IF log.S_ROW_COUNT is even --><tr class="bg1"><!-- ELSE --><tr class="bg2"><!-- ENDIF -->  			<td>{log.USERNAME}</td> -			<td style="text-align: center">{log.IP}</td> -			<td style="text-align: center">{log.DATE}</td> +			<td class="center">{log.IP}</td> +			<td class="center">{log.DATE}</td>  			<td>{log.ACTION}<br />  			{log.DATA}  		</td> diff --git a/phpBB/styles/prosilver/template/mcp_notes_user.html b/phpBB/styles/prosilver/template/mcp_notes_user.html index ec317b141a..3e8d47eb9d 100644 --- a/phpBB/styles/prosilver/template/mcp_notes_user.html +++ b/phpBB/styles/prosilver/template/mcp_notes_user.html @@ -65,9 +65,9 @@  	<table class="table1">  	<thead>  	<tr> -		<th>{L_REPORT_BY}</th> -		<th style="text-align: center">{L_IP}</th> -		<th style="text-align: center">{L_TIME}</th> +		<th class="name reportby">{L_REPORT_BY}</th> +		<th class="center">{L_IP}</th> +		<th class="center">{L_TIME}</th>  		<th>{L_ACTION_NOTE}</th>  		<!-- IF S_CLEAR_ALLOWED --><th>{L_MARK}</th><!-- ENDIF -->  	</tr> @@ -76,11 +76,11 @@  	<!-- BEGIN usernotes -->  	<!-- IF usernotes.S_ROW_COUNT is even --><tr class="bg1"><!-- ELSE --><tr class="bg2"><!-- ENDIF -->  		<td>{usernotes.REPORT_BY}</td> -		<td style="text-align: center">{usernotes.IP}</td> -		<td style="text-align: center">{usernotes.REPORT_AT}</td> +		<td class="center">{usernotes.IP}</td> +		<td class="center">{usernotes.REPORT_AT}</td>  		<td>{usernotes.ACTION}</td> -		<!-- IF S_CLEAR_ALLOWED --><td style="width: 5%; text-align: center;"><input type="checkbox" name="marknote[]" id="note-{usernotes.ID}" value="{usernotes.ID}" /></td><!-- ENDIF --> +		<!-- IF S_CLEAR_ALLOWED --><td class="center" style="width: 5%;"><input type="checkbox" name="marknote[]" id="note-{usernotes.ID}" value="{usernotes.ID}" /></td><!-- ENDIF -->  	</tr>  	<!-- BEGINELSE -->  	<tr> diff --git a/phpBB/styles/prosilver/template/memberlist_email.html b/phpBB/styles/prosilver/template/memberlist_email.html index 1bfd83e3a1..4a9f764d07 100644 --- a/phpBB/styles/prosilver/template/memberlist_email.html +++ b/phpBB/styles/prosilver/template/memberlist_email.html @@ -40,21 +40,21 @@  			</dl>  		<!-- ELSEIF S_CONTACT_ADMIN-->  			<dl> -				<dt><label>{L_RECIPIENT}:</label></dt> +				<dt><label>{L_RECIPIENT}{L_COLON}</label></dt>  				<dd><strong>{L_ADMINISTRATOR}</strong></dd>  			</dl>  			<!-- IF not S_IS_REGISTERED -->  			<dl> -				<dt><label for="email">{L_SENDER_EMAIL_ADDRESS}:</label></dt> +				<dt><label for="email">{L_SENDER_EMAIL_ADDRESS}{L_COLON}</label></dt>  				<dd><input class="inputbox autowidth" type="text" name="email" id="email" size="50" maxlength="100" tabindex="1" value="{EMAIL}" /></dd>  			</dl>  			<dl> -				<dt><label for="name">{L_SENDER_NAME}:</label></dt> +				<dt><label for="name">{L_SENDER_NAME}{L_COLON}</label></dt>  				<dd><input class="inputbox autowidth" type="text" name="name" id="name" size="50" tabindex="2" value="{NAME}" /></dd>  			</dl>  			<!-- ENDIF -->  			<dl> -				<dt><label for="subject">{L_SUBJECT}:</label></dt> +				<dt><label for="subject">{L_SUBJECT}{L_COLON}</label></dt>  				<dd><input class="inputbox autowidth" type="text" name="subject" id="subject" size="50" tabindex="3" value="{SUBJECT}" /></dd>  			</dl>  		<!-- ELSE --> diff --git a/phpBB/styles/prosilver/template/navbar_footer.html b/phpBB/styles/prosilver/template/navbar_footer.html index 4a9275c898..b5a705d567 100644 --- a/phpBB/styles/prosilver/template/navbar_footer.html +++ b/phpBB/styles/prosilver/template/navbar_footer.html @@ -1,4 +1,4 @@ -<div class="navbar"> +<div class="navbar" role="navigation">  	<div class="inner">  	<ul id="nav-footer" class="linklist bulletin" role="menubar"> diff --git a/phpBB/styles/prosilver/template/overall_footer.html b/phpBB/styles/prosilver/template/overall_footer.html index 6f35d0e80b..8749ce60e8 100644 --- a/phpBB/styles/prosilver/template/overall_footer.html +++ b/phpBB/styles/prosilver/template/overall_footer.html @@ -3,7 +3,7 @@  <!-- EVENT overall_footer_page_body_after --> -<div id="page-footer"> +<div id="page-footer" role="contentinfo">  	<!-- INCLUDE navbar_footer.html -->  	<div class="copyright"> diff --git a/phpBB/styles/prosilver/template/overall_header.html b/phpBB/styles/prosilver/template/overall_header.html index 121094f6e0..e0c8e51d25 100644 --- a/phpBB/styles/prosilver/template/overall_header.html +++ b/phpBB/styles/prosilver/template/overall_header.html @@ -2,7 +2,7 @@  <html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">  <head>  <meta charset="utf-8" /> -<meta name="viewport" content="width=device-width" /> +<meta name="viewport" content="width=device-width, initial-scale=1" />  {META}  <title><!-- IF UNREAD_NOTIFICATIONS_COUNT -->({UNREAD_NOTIFICATIONS_COUNT}) <!-- ENDIF --><!-- IF not S_VIEWTOPIC and not S_VIEWFORUM -->{SITENAME} - <!-- ENDIF --><!-- IF S_IN_MCP -->{L_MCP} - <!-- ELSEIF S_IN_UCP -->{L_UCP} - <!-- ENDIF -->{PAGE_TITLE}<!-- IF S_VIEWTOPIC or S_VIEWFORUM --> - {SITENAME}<!-- ENDIF --></title> @@ -59,7 +59,7 @@  <div id="wrap">  	<a id="top" class="anchor" accesskey="t"></a>  	<div id="page-header"> -		<div class="headerbar"> +		<div class="headerbar" role="banner">  			<div class="inner">  			<div id="site-description"> @@ -69,8 +69,9 @@  				<p class="skiplink"><a href="#start_here">{L_SKIP}</a></p>  			</div> +			<!-- EVENT overall_header_searchbox_before -->  			<!-- IF S_DISPLAY_SEARCH and not S_IN_SEARCH --> -			<div id="search-box" class="search-box search-header"> +			<div id="search-box" class="search-box search-header" role="search">  				<form action="{U_SEARCH}" method="get" id="search">  				<fieldset>  					<input name="keywords" id="keywords" type="search" maxlength="128" title="{L_SEARCH_KEYWORDS}" class="inputbox search tiny" size="20" value="{SEARCH_WORDS}" placeholder="{L_SEARCH_MINI}" /> @@ -84,14 +85,14 @@  			</div>  		</div> - +		<!-- EVENT overall_header_navbar_before -->  		<!-- INCLUDE navbar_header.html -->  	</div>  	<!-- EVENT overall_header_page_body_before -->  	<a id="start_here" class="anchor"></a> -	<div id="page-body"> +	<div id="page-body" role="main">  		<!-- IF S_BOARD_DISABLED and S_USER_LOGGED_IN and (U_MCP or U_ACP) -->  		<div id="information" class="rules">  			<div class="inner"> diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html index 2767eb85a3..f76afe3767 100644 --- a/phpBB/styles/prosilver/template/search_results.html +++ b/phpBB/styles/prosilver/template/search_results.html @@ -19,7 +19,7 @@  	<div class="action-bar top">  	<!-- IF TOTAL_MATCHES > 0 --> -		<div class="search-box"> +		<div class="search-box" role="search">  			<form method="post" action="{S_SEARCH_ACTION}">  			<fieldset>  				<input class="inputbox search tiny" type="search" name="add_keywords" id="add_keywords" value="" placeholder="{L_SEARCH_IN_RESULTS}" /> diff --git a/phpBB/styles/prosilver/template/simple_footer.html b/phpBB/styles/prosilver/template/simple_footer.html index d5d0f45fa9..123f8992f2 100644 --- a/phpBB/styles/prosilver/template/simple_footer.html +++ b/phpBB/styles/prosilver/template/simple_footer.html @@ -1,6 +1,6 @@  	</div> -	<div class="copyright">{CREDIT_LINE} +	<div class="copyright" role="contentinfo">{CREDIT_LINE}  		<!-- IF TRANSLATION_INFO --><br />{TRANSLATION_INFO}<!-- ENDIF -->  		<!-- IF DEBUG_OUTPUT --><br />{DEBUG_OUTPUT}<!-- ENDIF -->  	</div> diff --git a/phpBB/styles/prosilver/template/simple_header.html b/phpBB/styles/prosilver/template/simple_header.html index a0c7bc68bb..ab4f855a97 100644 --- a/phpBB/styles/prosilver/template/simple_header.html +++ b/phpBB/styles/prosilver/template/simple_header.html @@ -2,7 +2,7 @@  <html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">  <head>  <meta charset="utf-8" /> -<meta name="viewport" content="width=device-width" /> +<meta name="viewport" content="width=device-width, initial-scale=1" />  {META}  <title>{SITENAME} • <!-- IF S_IN_MCP -->{L_MCP} • <!-- ELSEIF S_IN_UCP -->{L_UCP} • <!-- ENDIF -->{PAGE_TITLE}</title> @@ -36,4 +36,4 @@  <div id="wrap">  	<a id="top" class="anchor" accesskey="t"></a> -	<div id="page-body"> +	<div id="page-body" role="main"> diff --git a/phpBB/styles/prosilver/template/ucp_profile_autologin_keys.html b/phpBB/styles/prosilver/template/ucp_profile_autologin_keys.html index 6fec0b8aed..65909b7068 100644 --- a/phpBB/styles/prosilver/template/ucp_profile_autologin_keys.html +++ b/phpBB/styles/prosilver/template/ucp_profile_autologin_keys.html @@ -10,19 +10,19 @@  		<table class="table1">  			<thead>  				<tr> -					<th>{L_LOGIN_KEY}</th> -					<th>{L_IP}</th> -					<th>{L_LOGIN_TIME}</th> -					<th class="mark">{L_MARK}</th> +					<th class="name">{L_LOGIN_KEY}</th> +					<th class="center">{L_IP}</th> +					<th class="center">{L_LOGIN_TIME}</th> +					<th class="center mark">{L_MARK}</th>  				</tr>  			</thead>  			<tbody>  			<!-- BEGIN sessions -->  				<!-- IF sessions.S_ROW_COUNT is even --><tr class="bg1"><!-- ELSE --><tr class="bg2"><!-- ENDIF -->  					<td><label for="{sessions.KEY}">{sessions.KEY}</label></td> -					<td style="text-align: center">{sessions.IP}</td> -					<td style="text-align: center">{sessions.LOGIN_TIME}</td> -					<td style="text-align: center" class="mark"><input type="checkbox" name="keys[]" value="{sessions.KEY}" id="{sessions.KEY}" /></td> +					<td class="center">{sessions.IP}</td> +					<td class="center">{sessions.LOGIN_TIME}</td> +					<td class="center mark"><input type="checkbox" name="keys[]" value="{sessions.KEY}" id="{sessions.KEY}" /></td>  				</tr>  			<!-- BEGINELSE -->  				<tr><td colspan="4" class="bg1" style="text-align: center">{L_PROFILE_NO_AUTOLOGIN_KEYS}</td></tr> diff --git a/phpBB/styles/prosilver/template/viewforum_body.html b/phpBB/styles/prosilver/template/viewforum_body.html index 43e994f1f9..a0a0cd547a 100644 --- a/phpBB/styles/prosilver/template/viewforum_body.html +++ b/phpBB/styles/prosilver/template/viewforum_body.html @@ -50,7 +50,7 @@  	<!-- ENDIF -->  	<!-- IF S_DISPLAY_SEARCHBOX --> -		<div class="search-box"> +		<div class="search-box" role="search">  			<form method="get" id="forum-search" action="{S_SEARCHBOX_ACTION}">  			<fieldset>  				<input class="inputbox search tiny" type="search" name="keywords" id="search_keywords" size="20" placeholder="{L_SEARCH_FORUM}" /> diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html index d39645cbe2..5b8078877e 100644 --- a/phpBB/styles/prosilver/template/viewtopic_body.html +++ b/phpBB/styles/prosilver/template/viewtopic_body.html @@ -42,7 +42,7 @@  	<!-- INCLUDE viewtopic_topic_tools.html -->  	<!-- IF S_DISPLAY_SEARCHBOX --> -		<div class="search-box"> +		<div class="search-box" role="search">  			<form method="get" id="topic-search" action="{S_SEARCHBOX_ACTION}">  			<fieldset>  				<input class="inputbox search tiny"  type="search" name="keywords" id="search_keywords" size="20" placeholder="{L_SEARCH_TOPIC}" /> diff --git a/phpBB/styles/prosilver/theme/bidi.css b/phpBB/styles/prosilver/theme/bidi.css index 889110e3fc..f3468ebcf2 100644 --- a/phpBB/styles/prosilver/theme/bidi.css +++ b/phpBB/styles/prosilver/theme/bidi.css @@ -182,8 +182,7 @@  /* Misc layout styles  ---------------------------------------- */ -/* column[1-2] styles are containers for two column layouts -   Also see tweaks.css */ +/* column[1-2] styles are containers for two column layouts */  .rtl .column1 {  	float: right;  	clear: right; @@ -313,6 +312,13 @@ li.breadcrumbs span:first-child > a {  	padding-right: 19px;  } +/* Notification mark read link */ +.rtl .dropdown-extended a.mark_read { +	border-radius: 0 3px 3px 0; +	left: 0; +	right: auto; +} +  .rtl a.top {  	float: left;  } @@ -596,9 +602,6 @@ li.breadcrumbs span:first-child > a {  /**  * buttons.css  */ -/* Rollover buttons -   Based on: http://wellstyled.com/css-nopreload-rollovers.html -----------------------------------------*/  .rtl .dropdown-select {  	padding-left: 24px;  	padding-right: 8px; @@ -976,10 +979,6 @@ li.breadcrumbs span:first-child > a {  	padding-left: 0;  } -/** -* tweaks.css -*/ -  /* Form button styles  ---------------------------------------- */ diff --git a/phpBB/styles/prosilver/theme/buttons.css b/phpBB/styles/prosilver/theme/buttons.css index d600e76b44..f9a520369e 100644 --- a/phpBB/styles/prosilver/theme/buttons.css +++ b/phpBB/styles/prosilver/theme/buttons.css @@ -1,13 +1,11 @@  /* Button Styles  ---------------------------------------- */ -/* Rollover buttons -   Based on: http://wellstyled.com/css-nopreload-rollovers.html -----------------------------------------*/  .button {  	cursor: pointer;  	display: inline-block;  	height: 18px; +	line-height: 18px;  	font-size: 13px;  	white-space: nowrap;  	border: 1px solid transparent; diff --git a/phpBB/styles/prosilver/theme/common.css b/phpBB/styles/prosilver/theme/common.css index 9da24b6ef9..c0cc2bb2dd 100644 --- a/phpBB/styles/prosilver/theme/common.css +++ b/phpBB/styles/prosilver/theme/common.css @@ -53,9 +53,7 @@ html {  }  body { -	/* Text-Sizing with ems: http://www.clagnut.com/blog/348/ */  	font-family: Verdana, Helvetica, Arial, sans-serif; -	/*font-size: 62.5%;			 This sets the default font size to be equivalent to 10px */  	font-size: 10px;  	line-height: normal;  	margin: 0; @@ -113,7 +111,6 @@ img {  }  hr { -	/* Also see tweaks.css */  	border: 0 solid transparent;  	border-top-width: 1px;  	height: 1px; @@ -671,6 +668,8 @@ table.table1 tbody th {  /* Specific column styles */  table.table1 .name		{ text-align: left; } +table.table1 .center		{ text-align: center; } +table.table1 .reportby	{ width: 15%; }  table.table1 .posts		{ text-align: center; width: 7%; }  table.table1 .joined	{ text-align: left; width: 15%; }  table.table1 .active	{ text-align: left; width: 15%; } @@ -711,8 +710,7 @@ table.info tbody th {  /* Misc layout styles  ---------------------------------------- */ -/* column[1-2] styles are containers for two column layouts -   Also see tweaks.css */ +/* column[1-2] styles are containers for two column layouts */  .column1 {  	float: left;  	clear: left; diff --git a/phpBB/styles/prosilver/theme/content.css b/phpBB/styles/prosilver/theme/content.css index e73f8c9d54..380b285b83 100644 --- a/phpBB/styles/prosilver/theme/content.css +++ b/phpBB/styles/prosilver/theme/content.css @@ -259,7 +259,6 @@ dd.option {  }  .postbody h3 img { -	/* Also see tweaks.css */  	vertical-align: bottom;  } @@ -510,7 +509,6 @@ blockquote .codebox {  }  .codebox code { -	/* Also see tweaks.css */  	overflow: auto;  	display: block;  	height: auto; @@ -693,7 +691,6 @@ fieldset.polls dd div {  /* Poster profile block  ----------------------------------------*/  .postprofile { -	/* Also see tweaks.css */  	margin: 5px 0 10px 0;  	min-height: 80px;  	border: 1px solid transparent; diff --git a/phpBB/styles/subsilver2/template/overall_header.html b/phpBB/styles/subsilver2/template/overall_header.html index 225a7d85ff..f3693eb865 100644 --- a/phpBB/styles/subsilver2/template/overall_header.html +++ b/phpBB/styles/subsilver2/template/overall_header.html @@ -152,7 +152,7 @@ function marklist(id, name, state)  		</tr>  		</table>  	</div> - +	<!-- EVENT overall_header_navbar_before -->  	<div id="menubar">  		<table width="100%" cellspacing="0">  		<tr> diff --git a/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html b/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html index 3f63319b59..087ae89743 100644 --- a/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html +++ b/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html @@ -16,9 +16,9 @@  </tr>  <tr>  	<th>{L_LOGIN_KEY}</th> -	<th>{L_IP}</th> -	<th>{L_LOGIN_TIME}</th> -	<th>{L_MARK}</th> +	<th class="center">{L_IP}</th> +	<th class="center">{L_LOGIN_TIME}</th> +	<th class="center">{L_MARK}</th>  </tr>  <!-- BEGIN sessions -->  	<!-- IF sessions.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF --> diff --git a/phpBB/styles/subsilver2/theme/stylesheet.css b/phpBB/styles/subsilver2/theme/stylesheet.css index 3c7ff23db5..7764020567 100644 --- a/phpBB/styles/subsilver2/theme/stylesheet.css +++ b/phpBB/styles/subsilver2/theme/stylesheet.css @@ -322,6 +322,10 @@ th {  	padding: 7px 5px;  } +th.center { +	text-align: center; +} +  td {  	padding: 2px;  } diff --git a/phpBB/viewforum.php b/phpBB/viewforum.php index 92ac9171cb..cd55114bad 100644 --- a/phpBB/viewforum.php +++ b/phpBB/viewforum.php @@ -391,15 +391,29 @@ $sql_array = array(  /**  * Event to modify the SQL query before the topic data is retrieved  * +* It may also be used to override the above assigned template vars +*  * @event core.viewforum_get_topic_data  * @var	array	forum_data			Array with forum data  * @var	array	sql_array			The SQL array to get the data of all topics +* @var	array	forum_id			The forum_id whose topics are being listed +* @var	array	topics_count		The total number of topics for display +* @var	array	sort_days			The oldest topic displayable in elapsed days +* @var	array	sort_key			The sorting by. It is one of the first character of (in low case): +*									Author, Post time, Replies, Subject, Views +* @var	array	sort_dir			Either "a" for ascending or "d" for descending  * @since 3.1.0-a1  * @change 3.1.0-RC4 Added forum_data var +* @change 3.1.4-RC1 Added forum_id, topics_count, sort_days, sort_key and sort_dir vars  */  $vars = array(  	'forum_data',  	'sql_array', +	'forum_id', +	'topics_count', +	'sort_days', +	'sort_key', +	'sort_dir',  );  extract($phpbb_dispatcher->trigger_event('core.viewforum_get_topic_data', compact($vars))); diff --git a/phpBB/web.config b/phpBB/web.config index a73c328626..99a1fe6023 100644 --- a/phpBB/web.config +++ b/phpBB/web.config @@ -1,6 +1,18 @@  <?xml version="1.0" encoding="UTF-8"?>  <configuration>  	<system.webServer> +		<rewrite> +			<rules> +				<rule name="Extension Routes" stopProcessing="true"> +					<match url="^(.*)$" ignoreCase="true" /> +					<conditions> +						<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" /> +						<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" /> +					</conditions> +					<action type="Rewrite" url="app.php" appendQueryString="true" /> +				</rule> +			</rules> +		</rewrite>  		<security>  			<requestFiltering>  				<hiddenSegments> diff --git a/tests/captcha/qa_test.php b/tests/captcha/qa_test.php new file mode 100644 index 0000000000..1f2f9f3070 --- /dev/null +++ b/tests/captcha/qa_test.php @@ -0,0 +1,94 @@ +<?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. + * + */ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + +class phpbb_captcha_qa_test extends \phpbb_database_test_case +{ +	protected $request; + +	/** @var \phpbb\captcha\plugins\qa */ +	protected $qa; + +	public function getDataSet() +	{ +		return $this->createXMLDataSet(dirname(__FILE__) . '/../fixtures/empty.xml'); +	} + +	public function setUp() +	{ +		global $db; + +		$db = $this->new_dbal(); + +		parent::setUp(); + +		$this->request = new \phpbb_mock_request(); +		request_var(false, false, false, false, $this->request); +		$this->qa = new \phpbb\captcha\plugins\qa('phpbb_captcha_questions', 'phpbb_captcha_answers', 'phpbb_qa_confirm'); +	} + +	public function test_is_installed() +	{ +		$this->assertFalse($this->qa->is_installed()); + +		$this->qa->install(); + +		$this->assertTrue($this->qa->is_installed()); +	} + +	public function test_set_get_name() +	{ +		$this->assertNull($this->qa->get_service_name()); +		$this->qa->set_name('foobar'); +		$this->assertSame('foobar', $this->qa->get_service_name()); +	} + +	public function data_acp_get_question_input() +	{ +		return array( +			array("foobar\ntest\nyes", array( +				'question_text'	=> '', +				'strict'	=> false, +				'lang_iso'	=> '', +				'answers'	=> array('foobar', 'test', 'yes') +			)), +			array("foobar\ntest\n \nyes", array( +				'question_text'	=> '', +				'strict'	=> false, +				'lang_iso'	=> '', +				'answers'	=> array( +					0 => 'foobar', +					1 => 'test', +					3 => 'yes', +				) +			)), +			array('', array( +				'question_text'	=> '', +				'strict'	=> false, +				'lang_iso'	=> '', +				'answers'	=> '', +			)), +		); +	} + +	/** +	 * @dataProvider data_acp_get_question_input +	 */ +	public function test_acp_get_question_input($value, $expected) +	{ +		$this->request->overwrite('answers', $value); + +		$this->assertEquals($expected, $this->qa->acp_get_question_input()); +	} +} diff --git a/tests/functional/acp_attachments_test.php b/tests/functional/acp_attachments_test.php new file mode 100644 index 0000000000..8e810a508a --- /dev/null +++ b/tests/functional/acp_attachments_test.php @@ -0,0 +1,78 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +/** + * @group functional + */ +class phpbb_functional_acp_attachments_test extends phpbb_functional_test_case +{ +	public function data_imagick_path_linux() +	{ +		return array( +			array('/usr/bin', 'Configuration updated successfully'), +			array('/usr/foobar', 'The entered path “/usr/foobar” does not exist.'), +			array('/usr/bin/which', 'The entered path “/usr/bin/which” is not a directory.'), +		); +	} + +	/** +	 * @dataProvider data_imagick_path_linux +	 */ +	public function test_imagick_path_linux($imagick_path, $expected) +	{ +		if (strtolower(substr(PHP_OS, 0, 5)) !== 'linux') +		{ +			$this->markTestSkipped('Unable to test linux specific paths on other OS.'); +		} + +		$this->login(); +		$this->admin_login(); + +		$crawler = self::request('GET', 'adm/index.php?i=attachments&mode=attach&sid=' . $this->sid); + +		$form = $crawler->selectButton('Submit')->form(array('config[img_imagick]'	=> $imagick_path)); + +		$crawler = self::submit($form); +		$this->assertContains($expected, $crawler->filter('#main')->text()); +	} + +	public function data_imagick_path_windows() +	{ +		return array( +			array('C:\Windows', 'Configuration updated successfully'), +			array('C:\Windows\foobar1', 'The entered path “C:\Windows\foobar1” does not exist.'), +			array('C:\Windows\explorer.exe', 'The entered path “C:\Windows\explorer.exe” is not a directory.'), +		); +	} + +	/** +	 * @dataProvider data_imagick_path_windows +	 */ +	public function test_imagick_path_windows($imagick_path, $expected) +	{ +		if (strtolower(substr(PHP_OS, 0, 3)) !== 'win') +		{ +			$this->markTestSkipped('Unable to test windows specific paths on other OS.'); +		} + +		$this->login(); +		$this->admin_login(); + +		$crawler = self::request('GET', 'adm/index.php?i=attachments&mode=attach&sid=' . $this->sid); + +		$form = $crawler->selectButton('Submit')->form(array('config[img_imagick]'	=> $imagick_path)); + +		$crawler = self::submit($form); +		$this->assertContains($expected, $crawler->filter('#main')->text()); +	} +} diff --git a/tests/functional/common_avatar_test_case.php b/tests/functional/common_avatar_test_case.php index 7278f23bcc..924eb1273c 100644 --- a/tests/functional/common_avatar_test_case.php +++ b/tests/functional/common_avatar_test_case.php @@ -62,7 +62,7 @@ abstract class phpbb_functional_common_avatar_test_case extends phpbb_functional  		{  			if (is_array($value))  			{ -				$form[$key]->$value[0]($value[1]); +				$form[$key]->{$value[0]}($value[1]);  			}  			else  			{ diff --git a/tests/functional/visibility_softdelete_test.php b/tests/functional/visibility_softdelete_test.php index 794f0cde68..39efc99a35 100644 --- a/tests/functional/visibility_softdelete_test.php +++ b/tests/functional/visibility_softdelete_test.php @@ -42,6 +42,19 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'forum_perm_from'	=> 2,  		));  		$crawler = self::submit($form); + +		// Create second user which does not have m_delete permission +		$this->add_lang('acp/permissions'); + +		$second_user = $this->create_user('no m_delete moderator'); +		$this->add_user_group("GLOBAL_MODERATORS", 'no m_delete moderator', true); + +		// Set m_delete to never +		$crawler = self::request('GET', "adm/index.php?i=acp_permissions&icat=16&mode=setting_user_global&user_id[0]=$second_user&type=m_&sid={$this->sid}"); +		$form = $crawler->selectButton($this->lang('APPLY_PERMISSIONS'))->form(); +		$data = array("setting[$second_user][0][m_delete]" => ACL_NEVER); +		$form->setValues($data); +		$crawler = self::submit($form);  	}  	public function test_create_post() @@ -98,6 +111,23 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'forum_topics_softdeleted'	=> 0,  			'forum_last_post_id'		=> $this->data['posts']['Re: Soft Delete Topic #1-#2'],  		), 'after replying'); + +		// Test creating another reply +		$post3 = $this->create_post($this->data['forums']['Soft Delete #1'], $post['topic_id'], 'Re: Soft Delete Topic #1-#3', 'This is another test post posted by the testing framework.'); +		$crawler = self::request('GET', "viewtopic.php?t={$post3['topic_id']}&sid={$this->sid}"); + +		$this->assertContains('Re: Soft Delete Topic #1-#3', $crawler->filter('html')->text()); +		$this->data['posts']['Re: Soft Delete Topic #1-#3'] = (int) $post3['post_id']; + +		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array( +			'forum_posts_approved'		=> 3, +			'forum_posts_unapproved'	=> 0, +			'forum_posts_softdeleted'	=> 0, +			'forum_topics_approved'		=> 1, +			'forum_topics_unapproved'	=> 0, +			'forum_topics_softdeleted'	=> 0, +			'forum_last_post_id'		=> $this->data['posts']['Re: Soft Delete Topic #1-#3'], +		), 'after replying a second time');  	}  	public function test_softdelete_post() @@ -114,21 +144,22 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'posts' => array(  				'Soft Delete Topic #1',  				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3',  			),  		));  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array( -			'forum_posts_approved'		=> 2, +			'forum_posts_approved'		=> 3,  			'forum_posts_unapproved'	=> 0,  			'forum_posts_softdeleted'	=> 0,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, -			'forum_last_post_id'		=> $this->data['posts']['Re: Soft Delete Topic #1-#2'], +			'forum_last_post_id'		=> $this->data['posts']['Re: Soft Delete Topic #1-#3'],  		), 'before softdelete');  		$this->add_lang('posting'); -		$crawler = self::request('GET', "posting.php?mode=delete&f={$this->data['forums']['Soft Delete #1']}&p={$this->data['posts']['Re: Soft Delete Topic #1-#2']}&sid={$this->sid}"); +		$crawler = self::request('GET', "posting.php?mode=delete&f={$this->data['forums']['Soft Delete #1']}&p={$this->data['posts']['Re: Soft Delete Topic #1-#3']}&sid={$this->sid}");  		$this->assertContainsLang('DELETE_PERMANENTLY', $crawler->text());  		$form = $crawler->selectButton('Yes')->form(); @@ -136,19 +167,69 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assertContainsLang('POST_DELETED', $crawler->text());  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array( -			'forum_posts_approved'		=> 1, +			'forum_posts_approved'		=> 2,  			'forum_posts_unapproved'	=> 0,  			'forum_posts_softdeleted'	=> 1,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, -			'forum_last_post_id'		=> $this->data['posts']['Soft Delete Topic #1'], +			'forum_last_post_id'		=> $this->data['posts']['Re: Soft Delete Topic #1-#2'],  		), 'after softdelete');  		$crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Soft Delete Topic #1']}&sid={$this->sid}");  		$this->assertContains($this->lang('POST_DISPLAY', '', ''), $crawler->text());  	} +	public function test_softdelete_post_no_m_delete() +	{ +		$this->login('no m_delete moderator'); +		$this->load_ids(array( +			'forums' => array( +				'Soft Delete #1', +				'Soft Delete #2', +			), +			'topics' => array( +				'Soft Delete Topic #1', +			), +			'posts' => array( +				'Soft Delete Topic #1', +				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3', +			), +		)); + +		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array( +			'forum_posts_approved'		=> 2, +			'forum_posts_unapproved'	=> 0, +			'forum_posts_softdeleted'	=> 1, +			'forum_topics_approved'		=> 1, +			'forum_topics_unapproved'	=> 0, +			'forum_topics_softdeleted'	=> 0, +			'forum_last_post_id'		=> $this->data['posts']['Re: Soft Delete Topic #1-#2'], +		), 'before softdelete without m_delete'); + +		$this->add_lang('posting'); +		$crawler = self::request('GET', "posting.php?mode=delete&f={$this->data['forums']['Soft Delete #1']}&p={$this->data['posts']['Re: Soft Delete Topic #1-#2']}&sid={$this->sid}"); +		$this->assertNotContainsLang('DELETE_PERMANENTLY', $crawler->text()); + +		$form = $crawler->selectButton('Yes')->form(); +		$crawler = self::submit($form); +		$this->assertContainsLang('POST_DELETED', $crawler->text()); + +		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array( +			'forum_posts_approved'		=> 1, +			'forum_posts_unapproved'	=> 0, +			'forum_posts_softdeleted'	=> 2, +			'forum_topics_approved'		=> 1, +			'forum_topics_unapproved'	=> 0, +			'forum_topics_softdeleted'	=> 0, +			'forum_last_post_id'		=> $this->data['posts']['Soft Delete Topic #1'], +		), 'after softdelete without m_delete'); + +		$crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Soft Delete Topic #1']}&sid={$this->sid}"); +		$this->assertContains($this->lang('POST_DISPLAY', '', ''), $crawler->text()); +	} +  	public function test_move_softdeleted_post()  	{  		$this->login(); @@ -163,13 +244,14 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'posts' => array(  				'Soft Delete Topic #1',  				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3',  			),  		));  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, @@ -212,7 +294,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #2'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, @@ -234,6 +316,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'posts' => array(  				'Soft Delete Topic #1',  				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3'  			),  		)); @@ -250,7 +333,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #2'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, @@ -283,7 +366,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #2'], array(  			'forum_posts_approved'		=> 0,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 2, +			'forum_posts_softdeleted'	=> 3,  			'forum_topics_approved'		=> 0,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 1, @@ -305,6 +388,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'posts' => array(  				'Soft Delete Topic #1',  				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3'  			),  		)); @@ -321,7 +405,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #2'], array(  			'forum_posts_approved'		=> 0,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 2, +			'forum_posts_softdeleted'	=> 3,  			'forum_topics_approved'		=> 0,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 1, @@ -344,7 +428,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 0,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 2, +			'forum_posts_softdeleted'	=> 3,  			'forum_topics_approved'		=> 0,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 1, @@ -376,13 +460,14 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'posts' => array(  				'Soft Delete Topic #1',  				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3'  			),  		));  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 0,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 2, +			'forum_posts_softdeleted'	=> 3,  			'forum_topics_approved'		=> 0,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 1, @@ -417,7 +502,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, @@ -449,13 +534,14 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'posts' => array(  				'Soft Delete Topic #1',  				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3'  			),  		));  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, @@ -495,7 +581,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 0, +			'forum_posts_softdeleted'	=> 1,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, @@ -528,6 +614,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'posts' => array(  				'Soft Delete Topic #1',  				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3'  			),  		)); @@ -539,7 +626,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 1, @@ -562,13 +649,14 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'posts' => array(  				'Soft Delete Topic #1',  				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3'  			),  		));  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 1, @@ -603,7 +691,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, @@ -625,13 +713,14 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  			'posts' => array(  				'Soft Delete Topic #1',  				'Re: Soft Delete Topic #1-#2', +				'Re: Soft Delete Topic #1-#3'  			),  		));  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, @@ -660,7 +749,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #1'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, @@ -670,11 +759,11 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_  		$this->assert_forum_details($this->data['forums']['Soft Delete #2'], array(  			'forum_posts_approved'		=> 1,  			'forum_posts_unapproved'	=> 0, -			'forum_posts_softdeleted'	=> 1, +			'forum_posts_softdeleted'	=> 2,  			'forum_topics_approved'		=> 1,  			'forum_topics_unapproved'	=> 0,  			'forum_topics_softdeleted'	=> 0, -			'forum_last_post_id'		=> $this->data['posts']['Soft Delete Topic #1'] + 2, +			'forum_last_post_id'		=> $this->data['posts']['Soft Delete Topic #1'] + 3,  		), 'after forking #2');  	} diff --git a/tests/functions_acp/validate_config_vars_test.php b/tests/functions_acp/validate_config_vars_test.php index 3c9af4a889..4bf6ba3984 100644 --- a/tests/functions_acp/validate_config_vars_test.php +++ b/tests/functions_acp/validate_config_vars_test.php @@ -162,4 +162,91 @@ class phpbb_functions_acp_validate_config_vars_test extends phpbb_test_case  		$this->assertEquals($expected, $phpbb_error);  	} + +	public function data_validate_path_linux() +	{ +		return array( +			array('/usr/bin', 'absolute_path', true), +			array('/usr/bin/', 'absolute_path:50:200', true), +			array('/usr/bin/which', 'absolute_path', 'DIRECTORY_NOT_DIR'), +			array('/foo/bar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'), +			array('C:\Windows', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'), +			array('.', 'absolute_path', true), +			array('', 'absolute_path', true), +			array('mkdir /foo/bar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'), +			// Make sure above command didn't do anything +			array('/foo/bar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'), +		); +	} + +	/** +	 * @dataProvider data_validate_path_linux +	 */ +	public function test_validate_path_linux($path, $validation_type, $expected) +	{ +		if (strtolower(substr(PHP_OS, 0, 5)) !== 'linux') +		{ +			$this->markTestSkipped('Unable to test linux specific paths on other OS.'); +		} + +		$error = array(); +		$config_ary = array( +			'path' => $path, +		); + +		validate_config_vars(array( +				'path'	=> array('lang' => 'FOOBAR', 'validate' => $validation_type), +			), +			$config_ary, +			$error +		); +	} + +	public function data_validate_path_windows() +	{ +		return array( +			array('C:\Windows', 'absolute_path', true), +			array('C:\Windows\\', 'absolute_path:50:200', true), +			array('C:\Windows\explorer.exe', 'absolute_path', 'DIRECTORY_NOT_DIR'), +			array('C:\foobar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'), +			array('/usr/bin', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'), +			array('.', 'absolute_path', true), +			array('', 'absolute_path', true), +			array('mkdir C:\Windows\foobar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'), +			// Make sure above command didn't do anything +			array('C:\Windows\foobar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'), +		); +	} + +	/** +	 * @dataProvider data_validate_path_windows +	 */ +	public function test_validate_path_windows($path, $validation_type, $expected) +	{ +		if (strtolower(substr(PHP_OS, 0, 3)) !== 'win') +		{ +			$this->markTestSkipped('Unable to test windows specific paths on other OS.'); +		} + +		$error = array(); +		$config_ary = array( +			'path' => $path, +		); + +		validate_config_vars(array( +			'path'	=> array('lang' => 'FOOBAR', 'validate' => $validation_type), +		), +			$config_ary, +			$error +		); + +		if ($expected === true) +		{ +			$this->assertEmpty($error); +		} +		else +		{ +			$this->assertEquals(array($expected), $error); +		} +	}  } diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index b6769f08d0..844caa8f54 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -410,6 +410,18 @@ class phpbb_functional_test_case extends phpbb_test_case  		$form = $crawler->selectButton('Enable')->form();  		$crawler = self::submit($form);  		$this->add_lang('acp/extensions'); + +		$meta_refresh = $crawler->filter('meta[http-equiv="refresh"]'); + +		// Wait for extension to be fully enabled +		while (sizeof($meta_refresh)) +		{ +			preg_match('#url=.+/(adm+.+)#', $meta_refresh->attr('content'), $match); +			$url = $match[1]; +			$crawler = self::request('POST', $url); +			$meta_refresh = $crawler->filter('meta[http-equiv="refresh"]'); +		} +  		$this->assertContainsLang('EXTENSION_ENABLE_SUCCESS', $crawler->filter('div.successbox')->text());  		$this->logout(); | 
