diff --git a/.travis.yml b/.travis.yml index ae5afc33d7..0ac1464540 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,30 @@ language: php -php: - - 5.3.3 - - 5.3 - - 5.4 - - 5.5 - - 5.6 - - hhvm -env: - - DB=mysqli +matrix: + include: + - php: 5.3.3 + env: DB=mysqli + - php: 5.3 + env: DB=mysqli # MyISAM + - php: 5.4 + env: DB=mysqli + - php: 5.4 + env: DB=mysql + - php: 5.4 + env: DB=mariadb + - php: 5.4 + env: DB=postgres + - php: 5.4 + env: DB=sqlite3 + - php: 5.5 + env: DB=mysqli + - php: 5.6 + env: DB=mysqli + - php: hhvm + env: DB=mysql + allow_failures: + - php: hhvm + fast_finish: true services: - redis-server @@ -24,16 +40,3 @@ script: - phpBB/vendor/bin/phpunit --configuration travis/phpunit-$DB-travis.xml - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.5' -a '$DB' = 'mysqli' -a '$TRAVIS_PULL_REQUEST' != 'false' ]; then git-tools/commit-msg-hook-range.sh origin/$TRAVIS_BRANCH..FETCH_HEAD; fi" -matrix: - include: - - php: 5.4 - env: DB=mysql - - php: 5.4 - env: DB=mariadb - - php: 5.4 - env: DB=postgres - - php: 5.4 - env: DB=sqlite3 - allow_failures: - - php: hhvm - fast_finish: true diff --git a/phpBB/adm/style/acp_language.html b/phpBB/adm/style/acp_language.html index d32f6b7eac..4439f519e0 100644 --- a/phpBB/adm/style/acp_language.html +++ b/phpBB/adm/style/acp_language.html @@ -2,29 +2,7 @@ - - - « {L_BACK} - -

{L_SELECT_DOWNLOAD_FORMAT}

- -
- -
- {L_DOWNLOAD_AS} -
-
-
{RADIO_BUTTONS}
-
- -

- -

-
- -
- - + « {L_BACK} @@ -58,153 +36,32 @@ -

+ +

{L_MISSING_FILES}

- -
-

{L_MISSING_FILES}

-

{MISSING_FILES}

-
-

- - - -

{L_MISSING_LANG_VARIABLES}

- -

{L_MISSING_VARS_EXPLAIN}

- -
- - - - - - - - - - - - - - - {missing.TPL} - - -
{L_LANGUAGE_KEY}{L_LANGUAGE_VARIABLE}
{missing.FILE}
-
{S_FORM_TOKEN}
-
- -

- - - - -

{L_LANGUAGE_ENTRIES}

- -

{L_LANGUAGE_ENTRIES_EXPLAIN}

- -
- - -
- +
+ {L_MISSING_LANG_FILES} + + » {missing_files.FILE_NAME}
+
-
-   -
+ +

{L_MISSING_VARS_EXPLAIN}

-

 
 

- - - - - - - - - - - - - - - +
+ {L_MISSING_LANG_VARIABLES} + +
+
+ +
{missing_varfile.variable.VAR_NAME}
+ +
+ +
- - - - - - - - - - - - - - - {TPL} - - - - - -
{L_FILE_CONTENTS}
{L_LANGUAGE_KEY}{L_LANGUAGE_VARIABLE}
{PRINT_MESSAGE}
{L_FILE_FROM_STORAGE}
  
-   {L_UPLOAD_METHOD}{L_COLON}  id="method" checked="checked" value="{buttons.VALUE}" name="method" /> {buttons.VALUE} 
{S_FORM_TOKEN}  
- - - - - « {L_BACK} - -

{L_UPLOAD_SETTINGS}

- -
- - -
-

{L_CONNECTION_SUCCESS}

-
- -
-

{L_CONNECTION_FAILED}

-
- - -
- {L_UPLOAD_SETTINGS} -
-
-
{NAME}
-
- -
-

{data.EXPLAIN}
-
-
- -
- -
- {HIDDEN} - {S_FORM_TOKEN} - - -
-
-

{L_ACP_LANGUAGE_PACKS}

@@ -231,7 +88,7 @@ {lang.LOCAL_NAME} {lang.ISO} {lang.USED_BY} -  {L_DOWNLOAD} | {L_DELETE} + {L_DELETE} diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js index 9eba80542c..296c5b0ef9 100644 --- a/phpBB/assets/javascript/core.js +++ b/phpBB/assets/javascript/core.js @@ -15,7 +15,7 @@ var dark = $('#darkenwrapper'); var loadingIndicator = $('#loading_indicator'); var phpbbAlertTimer = null; -var isTouch = (window && typeof window.ontouchstart !== 'undefined'); +phpbb.isTouch = (window && typeof window.ontouchstart !== 'undefined'); /** * Display a loading screen @@ -1011,7 +1011,7 @@ phpbb.resizeTextArea = function(items, options) { resetCallback: function(item) { } }; - if (isTouch) return; + if (phpbb.isTouch) return; if (arguments.length > 1) { configuration = $.extend(configuration, options); diff --git a/phpBB/config/console.yml b/phpBB/config/console.yml index 1305a12101..56bf99390a 100644 --- a/phpBB/config/console.yml +++ b/phpBB/config/console.yml @@ -86,6 +86,7 @@ services: class: phpbb\console\command\extension\show arguments: - @ext.manager + - @log tags: - { name: console.command } diff --git a/phpBB/docs/hook_system.html b/phpBB/docs/hook_system.html deleted file mode 100644 index 638b8ac290..0000000000 --- a/phpBB/docs/hook_system.html +++ /dev/null @@ -1,883 +0,0 @@ - - - - - - -phpBB3 • Hook System - - - - - - - -
- - - - - -
- -

Hook System

- - - -
- -

1. Introduction

- -
-
- -
- -

What is it?

- -

The hook system allows applicaton and mod developers to hook into phpBB's or their own functions.

- -

Pre-defined hookable phpBB3 functions

- -

In phpBB3 there are four functions you are able to hook into with your custom functions:

- -

phpbb_user_session_handler(); which is called within phpbb_user::setup after the session and the user object is correctly initialized.
-append_sid($url, $params = false, $is_amp = true, $session_id = false); which is called for building urls (appending the session id)
-$template->display($handle, $template); which is called directly before outputting the (not-yet-compiled) template.
-exit_handler(); which is called at the very end of phpBB3's execution.

- -

Please note: The $template->display hook takes a $template argument, which is the template instance being used, which should be used instead of the global.

- -

There are also valid external constants you may want to use if you embed phpBB3 into your application:

- -
-PHPBB_MSG_HANDLER (overwrite message handler)
-PHPBB_DB_NEW_LINK (overwrite new_link parameter for sql_connect)
-PHPBB_ROOT_PATH   (overwrite $phpbb_root_path)
-PHPBB_ADMIN_PATH  (overwrite $phpbb_admin_path)
-PHPBB_USE_BOARD_URL_PATH (use generate_board_url() for image paths instead of $phpbb_root_path)
-
- -

If the PHPBB_USE_BOARD_URL_PATH constant is set to true, phpBB uses generate_board_url() (this will return the boards url with the script path included) on all instances where web-accessible images are loaded. The exact locations are:

- -
    -
  • /includes/user.php - phpbb_user::img()
  • -
  • /includes/functions_content.php - smiley_text()
  • -
- -

Path locations for the following template variables are affected by this too:

- -
    -
  • {T_ASSETS_PATH} - assets
  • -
  • {T_THEME_PATH} - styles/xxx/theme
  • -
  • {T_TEMPLATE_PATH} - styles/xxx/template
  • -
  • {T_SUPER_TEMPLATE_PATH} - styles/xxx/template
  • -
  • {T_IMAGESET_PATH} - styles/xxx/imageset
  • -
  • {T_IMAGESET_LANG_PATH} - styles/xxx/imageset/yy
  • -
  • {T_IMAGES_PATH} - images/
  • -
  • {T_SMILIES_PATH} - $config['smilies_path']/
  • -
  • {T_AVATAR_PATH} - $config['avatar_path']/
  • -
  • {T_AVATAR_GALLERY_PATH} - $config['avatar_gallery_path']/
  • -
  • {T_ICONS_PATH} - $config['icons_path']/
  • -
  • {T_RANKS_PATH} - $config['ranks_path']/
  • -
  • {T_UPLOAD_PATH} - $config['upload_path']/
  • -
  • {T_STYLESHEET_LINK} - styles/xxx/theme/stylesheet.css (or link to style.php if css is parsed dynamically)
  • -
  • New template variable {BOARD_URL} for the board url + script path.
  • -
- - -
- - - -
-
- -

2. Allow hooks in functions/methods

- -
-
- -
- -

The following examples explain how phpBB3 utilize the in-build hook system. You will be more interested in registering your hooks, but showing you this may help you understand the system better along the way.

- -

First of all, this is how a function need to be layed out if you want to allow it to be hookable...

- -
-function my_own_function($my_first_parameter, $my_second_parameter)
-{
-	global $phpbb_hook;
-
-	if ($phpbb_hook->call_hook(__FUNCTION__, $my_first_parameter, $my_second_parameter))
-	{
-		if ($phpbb_hook->hook_return(__FUNCTION__))
-		{
-			return $phpbb_hook->hook_return_result(__FUNCTION__);
-		}
-	}
-
-	[YOUR CODE HERE]
-}
-
- -

Above, the call_hook function should always be mapping your function call... in regard to the number of parameters passed.

- -

This is how you could make a method being hookable...

- -
-class my_hookable_object
-{
-	function hook_me($my_first_parameter, $my_second_parameter)
-	{
-		global $phpbb_hook;
-
-		if ($phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $my_first_parameter, $my_second_parameter))
-		{
-			if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))
-			{
-				return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__));
-			}
-		}
-
-		[YOUR CODE HERE]
-	}
-}
-
- -

The only difference about calling it is the way you define the first parameter. For a function it is only __FUNCTION__, for a method it is array(__CLASS__, __FUNCTION__). In PHP4 __CLASS__ is always returning the class in lowercase.

- -

Now, in phpBB there are some pre-defined hooks available, but how do you make your own hookable function available (and therefore allowing others to hook into it)? For this, there is the add_hook() method:

- -
-// Adding your own hookable function:
-$phpbb_hook->add_hook('my_own_function');
-
-// Adding your own hookable method:
-$phpbb_hook->add_hook(array('my_hookable_object', 'hook_me'));
-
- -

You are also able to remove the possibility of hooking a function/method by calling $phpbb_hook->remove_hook() with the same parameters as add_hook().
-This comes in handy if you want to force some hooks not to be called - at all.

- -
- - - -
-
- -

3. Registering hooks

- -
-
- -
- -

Registering hooks

- -

Now to actually defining your functions which should be called. For this we take the append_sid() function as an example (this function is able to be hooked by default). We create two classes, one being static and a function:

- -
-class my_append_sid_class
-{
-	// Our functions
-	function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
-	{
-		// Get possible previous results
-		$result = $hook->previous_hook_result('append_sid');
-
-		return $result['result'] . '<br />And i was the second one.';
-	}
-}
-
-// Yet another class :o
-class my_second_append_sid_class
-{
-	function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
-	{
-		// Get possible previous results
-		$result = $hook->previous_hook_result('append_sid');
-
-		echo $result['result'] . '<br />I was called as the third one.';
-	}
-}
-
-// And a normal function
-function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
-{
-	// Get possible previous results
-	$result = $hook->previous_hook_result('append_sid');
-
-	return 'I was called as the first one';
-}
-
-// Initializing the second class
-$my_second_append_sid_class = new my_second_append_sid_class();
-
- -

Make sure you add the same parameters to your function as is defined for the hookable function with one exception: The first variable is always &$hook... this is the hook object itself you are able to operate on.

- -

Now we register the hooks one by one with the $phpbb_hook->register() method:

- -
-// Now, we register our append_sid "replacements" in a stacked way...
-// Registering the function (this is called first)
-$phpbb_hook->register('append_sid', 'my_append_sid');
-
-// Registering the first class
-$phpbb_hook->register('append_sid', array('my_append_sid_class', 'my_append_sid'));
-$phpbb_hook->register('append_sid', array(&$my_second_append_sid_class, 'my_append_sid'));
-
- -

With this you are even able to make your own functions that are already hooked itself being hooked again...

- -
-// Registering hook, which will be called
-$phpbb_hook->register('append_sid', 'my_own_append_sid');
-
-// Add hook to our called hook function
-$phpbb_hook->add_hook('my_own_append_sid');
-
-// Register added hook
-$phpbb_hook->register('my_own_append_sid', 'also_my_own_append_sid');
-
- -

Special treatment/chains

- -

The register method is able to take a third argument to specify a special 'chain' mode. The valid modes are first, last and standalone

- -

$phpbb_hook->register('append_sid', 'my_own_append_sid', 'first') would make sure that the function is called in the beginning of the chain. It is possible that more than one function is called within the first block - here the FIFO principle is used.

- -

$phpbb_hook->register('append_sid', 'my_own_append_sid', 'last') would make sure that the function is called at the very end of the chain. It is possible that more than one function is called within the last block - here the FIFO principle is used.

- -

$phpbb_hook->register('append_sid', 'my_own_append_sid', 'standalone') makes sure only the defined function is called. All other functions are removed from the chain and no other functions are added to it later on. If two applications try to trigger the standalone mode a PHP notice will be printed and the second function being discarded.

- -

Only allowing hooks for some objects

- -

Because the hook system is not able to differate between initialized objects and only operate on the class, you need to solve this on the code level.

- -

One possibility would be to use a property:

- -
-class my_hookable_object
-{
-	function blabla()
-	{
-	}
-}
-
-class my_hookable_object2 extends my_hookable_object
-{
-	var $call_hook = true;
-
-	function hook_me($my_first_parameter, $my_second_parameter)
-	{
-		if ($this->call_hook)
-		{
-			global $phpbb_hook;
-
-			if ($phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $my_first_parameter, $my_second_parameter))
-			{
-				if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))
-				{
-					return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__));
-				}
-			}
-		}
-
-		return 'not hooked';
-	}
-}
-
-function hooking(&$hook, $first, $second)
-{
-	return 'hooked';
-}
-
-$first_object = new my_hookable_object2();
-$second_object = new my_hookable_object2();
-
-$phpbb_hook->add_hook(array('my_hookable_object2', 'hook_me'));
-
-$phpbb_hook->register(array('my_hookable_object2', 'hook_me'), 'hooking');
-
-// Do not call the hook for $first_object
-$first_object->call_hook = false;
-
-echo $first_object->hook_me('first', 'second') . '<br />';
-echo $second_object->hook_me('first', 'second') . '<br />';
-
- -

OUTPUT:

- -
-not hooked
-hooked
-
- -

A different possibility would be using a function variable (which could be left out on passing the function variables to the hook):

- -
-class my_hookable_object
-{
-	function blabla()
-	{
-	}
-}
-
-class my_hookable_object2 extends my_hookable_object
-{
-	function hook_me($my_first_parameter, $my_second_parameter, $hook_me = true)
-	{
-		if ($hook_me)
-		{
-			global $phpbb_hook;
-
-			if ($phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $my_first_parameter, $my_second_parameter))
-			{
-				if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__)))
-				{
-					return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__));
-				}
-			}
-		}
-
-		return 'not hooked';
-	}
-}
-
-function hooking(&$hook, $first, $second)
-{
-	return 'hooked';
-}
-
-$first_object = new my_hookable_object2();
-$second_object = new my_hookable_object2();
-
-$phpbb_hook->add_hook(array('my_hookable_object2', 'hook_me'));
-
-$phpbb_hook->register(array('my_hookable_object2', 'hook_me'), 'hooking');
-
-echo $first_object->hook_me('first', 'second', false) . '<br />';
-echo $second_object->hook_me('first', 'second') . '<br />';
-		
- -

OUTPUT:

- -
-not hooked
-hooked
-		
- -
- - - -
-
- -

4. Result returning

- -
-
- -
- -

Generally, the distinction has to be made if a function returns the result obtained from the called function or continue the execution. Based on the needs of the application this may differ. Therefore, the function returns the results only if the called hook function is returning a result.

- -

Case 1 - Returning the result

- -

Imagine the following function supporting hooks:

- -
-function append_sid($url, $params = false, $is_amp = true, $session_id = false)
-{
-	global $_SID, $_EXTRA_URL, $phpbb_hook;
-
-	// Developers using the hook function need to globalise the $_SID and $_EXTRA_URL on their own and also handle it appropiatly.
-	// They could mimick most of what is within this function
-	if ($phpbb_hook->call_hook(__FUNCTION__, $url, $params, $is_amp, $session_id))
-	{
-		if ($phpbb_hook->hook_return(__FUNCTION__))
-		{
-			return $phpbb_hook->hook_return_result(__FUNCTION__);
-		}
-	}
-
-	[...]
-}
-
- -

Now, the following function is yours. Since you return a value, the append_sid() function itself is returning it as is:

- -
-// The function called
-function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
-{
-	// Get possible previous results
-	$result = $hook->previous_hook_result('append_sid');
-
-	return 'Since i return something the append_sid() function will return my result.';
-}
-
- -

To be able to get the results returned from functions higher in the change the previous_hook_result() method should always be used, it returns an array('result' => [your result]) construct.

- -

Case 2 - Not Returning any result

- -

Sometimes applications want to return nothing and therefore force the underlying function to continue it's execution:

- -
-function append_sid($url, $params = false, $is_amp = true, $session_id = false)
-{
-	global $_SID, $_EXTRA_URL, $phpbb_hook;
-
-	// Developers using the hook function need to globalise the $_SID and $_EXTRA_URL on their own and also handle it appropiatly.
-	// They could mimick most of what is within this function
-	if ($phpbb_hook->call_hook(__FUNCTION__, $url, $params, $is_amp, $session_id))
-	{
-		if ($phpbb_hook->hook_return(__FUNCTION__))
-		{
-			return $phpbb_hook->hook_return_result(__FUNCTION__);
-		}
-	}
-
-	[...]
-}
-
-// The function called
-function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
-{
-	// Get possible previous results
-	$result = $hook->previous_hook_result('append_sid');
-
-	[...]
-
-	// I only rewrite some variables, but return nothing. Therefore, the append_sid() function will not return my (non)result.
-}
-
- -

Please Note: The decision to return or not return is solely made of the very last function call within the hook chain. An example:

- -
-// The function called
-function my_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
-{
-	// Get possible previous results
-	$result = $hook->previous_hook_result('append_sid');
-
-	// $result is not filled
-
-	return 'FILLED';
-}
-
-// This function is registered too and gets executed after my_append_sid()
-function my_own_append_sid(&$hook, $url, $params = false, $is_amp = true, $session_id = false)
-{
-	$result = $hook->previous_hook_result('append_sid');
-
-	// $result is actually filled with $result['result'] = 'FILLED'
-	// But i return nothing, therefore append_sid() continues it's execution.
-}
-
-// The way both functions are registered.
-$phpbb_hook->register('append_sid', 'my_append_sid');
-$phpbb_hook->register('append_sid', 'my_own_append_sid');
-
- -
- - - -
-
- -

5. Embedding your hook files/classes/methods

- -
-
- -
- -

There are basically two methods you are able to choose from:

- -

1) Add a file to includes/hooks/. The file need to be prefixed by hook_. This file is included within common.php, you are able to register your hooks, include other files or functions, etc. It is advised to only include other files if needed (within a function call for example).

- -

Please be aware that you need to purge your cache within the ACP to make your newly placed file available to phpBB3.

- -

2) The second method is meant for those wanting to wrap phpBB3 without placing a custom file to the hooks directory. This is mostly done by including phpBB's files within the application file. To be able to register your hooks you need to create a function within your application:

- -
-// My function which gets executed within the hooks constuctor
-function phpbb_hook_register(&$hook)
-{
-	$hook->register('append_sid', 'my_append_sid');
-}
-
-[...]
-
- -

You should get the idea. ;)

- -
- - - -
-
- -

6. Copyright and disclaimer

- -
-
- -
- -

phpBB is free software, released under the terms of the GNU General Public License, version 2 (GPL-2.0). Copyright © phpBB Limited. For full copyright and license information, please see the docs/CREDITS.txt file.

- -
- - - -
-
- - -
- -
- -
- - - diff --git a/phpBB/includes/acp/acp_language.php b/phpBB/includes/acp/acp_language.php index 2f8e781e3b..60e338ae7c 100644 --- a/phpBB/includes/acp/acp_language.php +++ b/phpBB/includes/acp/acp_language.php @@ -31,22 +31,13 @@ class acp_language function main($id, $mode) { - global $config, $db, $user, $auth, $template, $cache; - global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix; - global $safe_mode, $file_uploads; - global $request; + global $config, $db, $user, $template; + global $phpbb_root_path, $phpEx, $request; include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx); - $this->default_variables(); - // Check and set some common vars - $action = (isset($_POST['update_details'])) ? 'update_details' : ''; - $action = (isset($_POST['download_file'])) ? 'download_file' : $action; - $action = (isset($_POST['upload_file'])) ? 'upload_file' : $action; - $action = (isset($_POST['upload_data'])) ? 'upload_data' : $action; - $action = (isset($_POST['submit_file'])) ? 'submit_file' : $action; $action = (isset($_POST['remove_store'])) ? 'details' : $action; $submit = (empty($action) && !isset($_POST['update']) && !isset($_POST['test_connection'])) ? false : true; @@ -56,11 +47,6 @@ class acp_language add_form_key('acp_lang'); $lang_id = request_var('id', 0); - if (isset($_POST['missing_file'])) - { - $missing_file = request_var('missing_file', array('' => 0)); - $request->overwrite('language_file', array_shift(array_keys($missing_file))); - } $selected_lang_file = request_var('language_file', '|common.' . $phpEx); @@ -69,113 +55,12 @@ class acp_language $this->language_directory = basename($this->language_directory); $this->language_file = basename($this->language_file); - // detect language file type - if ($this->language_directory == 'email') - { - $language_file_type = 'email'; - $request_default = ''; - } - else if (strpos($this->language_file, 'help_') === 0) - { - $language_file_type = 'help'; - $request_default = array(0 => array(0 => '')); - } - else - { - $language_file_type = 'normal'; - $request_default = array('' => ''); - } - $user->add_lang('acp/language'); $this->tpl_name = 'acp_language'; $this->page_title = 'ACP_LANGUAGE_PACKS'; - if ($submit && $action == 'upload_data' && request_var('test_connection', '')) - { - $test_connection = false; - $action = 'upload_file'; - $method = request_var('method', ''); - - include_once($phpbb_root_path . 'includes/functions_transfer.' . $phpEx); - - switch ($method) - { - case 'ftp': - $transfer = new ftp( - request_var('host', ''), - request_var('username', ''), - htmlspecialchars_decode($request->untrimmed_variable('password', '')), - request_var('root_path', ''), - request_var('port', ''), - request_var('timeout', '') - ); - break; - - case 'ftp_fsock': - $transfer = new ftp_fsock( - request_var('host', ''), - request_var('username', ''), - htmlspecialchars_decode($request->untrimmed_variable('password', '')), - request_var('root_path', ''), - request_var('port', ''), - request_var('timeout', '') - ); - break; - - default: - trigger_error($user->lang['INVALID_UPLOAD_METHOD'], E_USER_ERROR); - break; - } - - $test_connection = $transfer->open_session(); - $transfer->close_session(); - } - switch ($action) { - case 'upload_file': - - include_once($phpbb_root_path . 'includes/functions_transfer.' . $phpEx); - - $method = request_var('method', ''); - - if (!class_exists($method)) - { - trigger_error('Method does not exist.', E_USER_ERROR); - } - - $requested_data = call_user_func(array($method, 'data')); - foreach ($requested_data as $data => $default) - { - $template->assign_block_vars('data', array( - 'DATA' => $data, - 'NAME' => $user->lang[strtoupper($method . '_' . $data)], - 'EXPLAIN' => $user->lang[strtoupper($method . '_' . $data) . '_EXPLAIN'], - 'DEFAULT' => $request->variable($data, (string) $default), - )); - } - - $hidden_data = build_hidden_fields(array( - 'file' => $this->language_file, - 'dir' => $this->language_directory, - 'language_file' => $selected_lang_file, - 'method' => $method) - ); - - $hidden_data .= build_hidden_fields(array('entry' => $request->variable('entry', $request_default, true, \phpbb\request\request_interface::POST))); - - $template->assign_vars(array( - 'S_UPLOAD' => true, - 'NAME' => $method, - 'U_ACTION' => $this->u_action . "&id=$lang_id&action=upload_data", - 'U_BACK' => $this->u_action . "&id=$lang_id&action=details&language_file=" . urlencode($selected_lang_file), - 'HIDDEN' => $hidden_data, - - 'S_CONNECTION_SUCCESS' => (request_var('test_connection', '') && $test_connection === true) ? true : false, - 'S_CONNECTION_FAILED' => (request_var('test_connection', '') && $test_connection !== true) ? true : false - )); - break; - case 'update_details': if (!$submit || !check_form_key($form_name)) @@ -210,259 +95,6 @@ class acp_language trigger_error($user->lang['LANGUAGE_DETAILS_UPDATED'] . adm_back_link($this->u_action)); break; - case 'submit_file': - case 'download_file': - case 'upload_data': - - if (!$submit || !check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING); - } - - $entry_value = $request->variable('entry', $request_default, true, \phpbb\request\request_interface::POST); - - if (!$lang_id || !$entry_value) - { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (!$this->language_file || (!$this->language_directory && !in_array($this->language_file, $this->main_files))) - { - trigger_error($user->lang['NO_FILE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql = 'SELECT * - FROM ' . LANG_TABLE . " - WHERE lang_id = $lang_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // Before we attempt to write anything let's check if the admin really chose a correct filename - switch ($this->language_directory) - { - case 'email': - // Get email templates - $email_files = filelist($phpbb_root_path . 'language/' . $row['lang_iso'], 'email', 'txt'); - $email_files = $email_files['email/']; - - if (!in_array($this->language_file, $email_files)) - { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); - } - break; - - case 'acp': - // Get acp files - $acp_files = filelist($phpbb_root_path . 'language/' . $row['lang_iso'], 'acp', $phpEx); - $acp_files = $acp_files['acp/']; - - if (!in_array($this->language_file, $acp_files)) - { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); - } - break; - - case 'mods': - // Get mod files - $mods_files = filelist($phpbb_root_path . 'language/' . $row['lang_iso'], 'mods', $phpEx); - $mods_files = (isset($mods_files['mods/'])) ? $mods_files['mods/'] : array(); - - if (!in_array($this->language_file, $mods_files)) - { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); - } - break; - - default: - if (!in_array($this->language_file, $this->main_files)) - { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); - } - break; - } - - if (!$safe_mode) - { - $mkdir_ary = array('language', 'language/' . $row['lang_iso']); - - if ($this->language_directory) - { - $mkdir_ary[] = 'language/' . $row['lang_iso'] . '/' . $this->language_directory; - } - - foreach ($mkdir_ary as $dir) - { - $dir = $phpbb_root_path . 'store/' . $dir; - - if (!is_dir($dir)) - { - if (!@mkdir($dir, 0777)) - { - trigger_error("Could not create directory $dir", E_USER_ERROR); - } - @chmod($dir, 0777); - } - } - } - - // Get target filename for storage folder - $filename = $this->get_filename($row['lang_iso'], $this->language_directory, $this->language_file, true, true); - $fp = @fopen($phpbb_root_path . $filename, 'wb'); - - if (!$fp) - { - trigger_error(sprintf($user->lang['UNABLE_TO_WRITE_FILE'], $filename) . adm_back_link($this->u_action . '&id=' . $lang_id . '&action=details&language_file=' . urlencode($selected_lang_file)), E_USER_WARNING); - } - - if ($language_file_type == 'email') - { - // Email Template - $entry = $this->prepare_lang_entry(htmlspecialchars_decode($entry_value), false); - fwrite($fp, $entry); - } - else - { - $name = (($this->language_directory) ? $this->language_directory . '_' : '') . $this->language_file; - $header = str_replace(array('{FILENAME}', '{LANG_NAME}', '{CHANGED}', '{AUTHOR}'), array($name, $row['lang_english_name'], date('Y-m-d', time()), $row['lang_author']), $this->language_file_header); - - if ($language_file_type == 'help') - { - // Help File - $header .= '$help = array(' . "\n"; - fwrite($fp, $header); - - foreach ($entry_value as $key => $value) - { - if (!is_array($value)) - { - continue; - } - - $entry = "\tarray(\n"; - - foreach ($value as $_key => $_value) - { - $entry .= "\t\t" . (int) $_key . "\t=> '" . $this->prepare_lang_entry(htmlspecialchars_decode($_value)) . "',\n"; - } - - $entry .= "\t),\n"; - fwrite($fp, $entry); - } - - $footer = ");\n\n?>"; - fwrite($fp, $footer); - } - else if ($language_file_type == 'normal') - { - // Language File - $header .= $this->lang_header; - fwrite($fp, $header); - - foreach ($entry_value as $key => $value) - { - $entry = $this->format_lang_array(htmlspecialchars_decode($key), htmlspecialchars_decode($value)); - fwrite($fp, $entry); - } - - $footer = "));\n\n?>"; - fwrite($fp, $footer); - } - } - - fclose($fp); - - if ($action == 'download_file') - { - header('Pragma: no-cache'); - header('Content-Type: application/octetstream; name="' . $this->language_file . '"'); - header('Content-disposition: attachment; filename=' . $this->language_file); - - $fp = @fopen($phpbb_root_path . $filename, 'rb'); - while ($buffer = fread($fp, 1024)) - { - echo $buffer; - } - fclose($fp); - - add_log('admin', 'LOG_LANGUAGE_FILE_SUBMITTED', $this->language_file); - - exit; - } - else if ($action == 'upload_data') - { - $sql = 'SELECT lang_iso - FROM ' . LANG_TABLE . " - WHERE lang_id = $lang_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $file = request_var('file', ''); - $dir = request_var('dir', ''); - - $selected_lang_file = $dir . '|' . $file; - - $old_file = '/' . $this->get_filename($row['lang_iso'], $dir, $file, false, true); - $lang_path = 'language/' . $row['lang_iso'] . '/' . (($dir) ? $dir . '/' : ''); - - include_once($phpbb_root_path . 'includes/functions_transfer.' . $phpEx); - $method = request_var('method', ''); - - if ($method != 'ftp' && $method != 'ftp_fsock') - { - trigger_error($user->lang['INVALID_UPLOAD_METHOD'], E_USER_ERROR); - } - - $transfer = new $method( - request_var('host', ''), - request_var('username', ''), - htmlspecialchars_decode($request->untrimmed_variable('password', '')), - request_var('root_path', ''), - request_var('port', ''), - request_var('timeout', '') - ); - - if (($result = $transfer->open_session()) !== true) - { - trigger_error($user->lang[$result] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id . '&language_file=' . urlencode($selected_lang_file)), E_USER_WARNING); - } - - $transfer->rename($lang_path . $file, $lang_path . $file . '.bak'); - $result = $transfer->copy_file('store/' . $lang_path . $file, $lang_path . $file); - - if ($result === false) - { - // If failed, try to rename again and print error out... - $transfer->delete_file($lang_path . $file); - $transfer->rename($lang_path . $file . '.bak', $lang_path . $file); - - trigger_error($user->lang['UPLOAD_FAILED'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id . '&language_file=' . urlencode($selected_lang_file)), E_USER_WARNING); - } - - $transfer->close_session(); - - // Remove from storage folder - if (file_exists($phpbb_root_path . 'store/' . $lang_path . $file)) - { - @unlink($phpbb_root_path . 'store/' . $lang_path . $file); - } - - add_log('admin', 'LOG_LANGUAGE_FILE_REPLACED', $file); - - trigger_error($user->lang['UPLOAD_COMPLETED'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id . '&language_file=' . urlencode($selected_lang_file))); - } - - add_log('admin', 'LOG_LANGUAGE_FILE_SUBMITTED', $this->language_file); - $action = 'details'; - - // no break; - case 'details': if (!$lang_id) @@ -479,308 +111,82 @@ class acp_language $lang_entries = $db->sql_fetchrow($result); $db->sql_freeresult($result); + if (!$lang_entries) + { + trigger_error($user->lang['LANGUAGE_PACK_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); + } + $lang_iso = $lang_entries['lang_iso']; - $missing_vars = $missing_files = array(); - - // Get email templates - $email_files = filelist($phpbb_root_path . 'language/' . $config['default_lang'], 'email', 'txt'); - $email_files = $email_files['email/']; - - // Get acp files - $acp_files = filelist($phpbb_root_path . 'language/' . $config['default_lang'], 'acp', $phpEx); - $acp_files = $acp_files['acp/']; - - // Get mod files - $mods_files = filelist($phpbb_root_path . 'language/' . $config['default_lang'], 'mods', $phpEx); - $mods_files = (isset($mods_files['mods/'])) ? $mods_files['mods/'] : array(); - - // Check if our current filename matches the files - switch ($this->language_directory) - { - case 'email': - if (!in_array($this->language_file, $email_files)) - { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); - } - break; - - case 'acp': - if (!in_array($this->language_file, $acp_files)) - { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); - } - break; - - case 'mods': - if (!in_array($this->language_file, $mods_files)) - { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); - } - break; - - default: - if (!in_array($this->language_file, $this->main_files)) - { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); - } - } - - if (isset($_POST['remove_store'])) - { - $store_filename = $this->get_filename($lang_iso, $this->language_directory, $this->language_file, true, true); - - if (file_exists($phpbb_root_path . $store_filename)) - { - @unlink($phpbb_root_path . $store_filename); - } - } - - include_once($phpbb_root_path . 'includes/functions_transfer.' . $phpEx); - - $methods = transfer::methods(); - - foreach ($methods as $method) - { - $template->assign_block_vars('buttons', array( - 'VALUE' => $method - )); - } $template->assign_vars(array( 'S_DETAILS' => true, 'U_ACTION' => $this->u_action . "&action=details&id=$lang_id", 'U_BACK' => $this->u_action, + 'LANG_LOCAL_NAME' => $lang_entries['lang_local_name'], 'LANG_ENGLISH_NAME' => $lang_entries['lang_english_name'], - 'LANG_ISO' => $lang_entries['lang_iso'], + 'LANG_ISO' => $lang_iso, 'LANG_AUTHOR' => $lang_entries['lang_author'], - 'ALLOW_UPLOAD' => sizeof($methods) - ) - ); + 'L_MISSING_FILES' => $user->lang('THOSE_MISSING_LANG_FILES', $lang_entries['lang_local_name']), + 'L_MISSING_VARS_EXPLAIN' => $user->lang('THOSE_MISSING_LANG_VARIABLES', $lang_entries['lang_local_name']), + )); - // If current lang is different from the default lang, then first try to grab missing/additional vars + // If current lang is different from the default lang, then highlight missing files and variables if ($lang_iso != $config['default_lang']) { - $is_missing_var = false; - - foreach ($this->main_files as $file) + try { - if (file_exists($phpbb_root_path . $this->get_filename($lang_iso, '', $file))) - { - $missing_vars[$file] = $this->compare_language_files($config['default_lang'], $lang_iso, '', $file); - - if (sizeof($missing_vars[$file])) - { - $is_missing_var = true; - } - } - else - { - $missing_files[] = $this->get_filename($lang_iso, '', $file); - } + $iterator = new \RecursiveIteratorIterator( + new \phpbb\recursive_dot_prefix_filter_iterator( + new \RecursiveDirectoryIterator( + $phpbb_root_path . 'language/' . $config['default_lang'] . '/', + \FilesystemIterator::SKIP_DOTS + ) + ), + \RecursiveIteratorIterator::LEAVES_ONLY + ); + } + catch (\Exception $e) + { + return array(); } - // Now go through acp/mods directories - foreach ($acp_files as $file) + foreach ($iterator as $file_info) { - if (file_exists($phpbb_root_path . $this->get_filename($lang_iso, 'acp', $file))) - { - $missing_vars['acp/' . $file] = $this->compare_language_files($config['default_lang'], $lang_iso, 'acp', $file); + /** @var \RecursiveDirectoryIterator $file_info */ + $relative_path = $iterator->getInnerIterator()->getSubPathname(); + $relative_path = str_replace(DIRECTORY_SEPARATOR, '/', $relative_path); - if (sizeof($missing_vars['acp/' . $file])) + if (file_exists($phpbb_root_path . 'language/' . $lang_iso . '/' . $relative_path)) + { + if (substr($relative_path, 0 - strlen($phpEx)) === $phpEx) { - $is_missing_var = true; - } - } - else - { - $missing_files[] = $this->get_filename($lang_iso, 'acp', $file); - } - } + $missing_vars = $this->compare_language_files($config['default_lang'], $lang_iso, $relative_path); - if (sizeof($mods_files)) - { - foreach ($mods_files as $file) - { - if (file_exists($phpbb_root_path . $this->get_filename($lang_iso, 'mods', $file))) - { - $missing_vars['mods/' . $file] = $this->compare_language_files($config['default_lang'], $lang_iso, 'mods', $file); - - if (sizeof($missing_vars['mods/' . $file])) + if (!empty($missing_vars)) { - $is_missing_var = true; + $template->assign_block_vars('missing_varfile', array( + 'FILE_NAME' => $relative_path, + )); + + foreach ($missing_vars as $var) + { + $template->assign_block_vars('missing_varfile.variable', array( + 'VAR_NAME' => $var, + )); + } } } - else - { - $missing_files[] = $this->get_filename($lang_iso, 'mods', $file); - } } - } - - // More missing files... for example email templates? - foreach ($email_files as $file) - { - if (!file_exists($phpbb_root_path . $this->get_filename($lang_iso, 'email', $file))) + else { - $missing_files[] = $this->get_filename($lang_iso, 'email', $file); - } - } - - if (sizeof($missing_files)) - { - $template->assign_vars(array( - 'S_MISSING_FILES' => true, - 'L_MISSING_FILES' => sprintf($user->lang['THOSE_MISSING_LANG_FILES'], $lang_entries['lang_local_name']), - 'MISSING_FILES' => implode('
', $missing_files)) - ); - } - - if ($is_missing_var) - { - $template->assign_vars(array( - 'S_MISSING_VARS' => true, - 'L_MISSING_VARS_EXPLAIN' => sprintf($user->lang['THOSE_MISSING_LANG_VARIABLES'], $lang_entries['lang_local_name']), - 'U_MISSING_ACTION' => $this->u_action . "&action=$action&id=$lang_id") - ); - - foreach ($missing_vars as $file => $vars) - { - if (!sizeof($vars)) - { - continue; - } - - $template->assign_block_vars('missing', array( - 'FILE' => $file, - 'TPL' => $this->print_language_entries($vars, '', false), - 'KEY' => (strpos($file, '/') === false) ? '|' . $file : str_replace('/', '|', $file)) - ); + $template->assign_block_vars('missing_files', array( + 'FILE_NAME' => $relative_path, + )); } } } - - // Main language files - $s_lang_options = ''; - foreach ($this->main_files as $file) - { - if (strpos($file, 'help_') === 0) - { - continue; - } - - $prefix = (file_exists($phpbb_root_path . $this->get_filename($lang_iso, '', $file, true, true))) ? '* ' : ''; - - $selected = (!$this->language_directory && $this->language_file == $file) ? ' selected="selected"' : ''; - $s_lang_options .= ''; - } - - // Help Files - $s_lang_options .= ''; - foreach ($this->main_files as $file) - { - if (strpos($file, 'help_') !== 0) - { - continue; - } - - $prefix = (file_exists($phpbb_root_path . $this->get_filename($lang_iso, '', $file, true, true))) ? '* ' : ''; - - $selected = (!$this->language_directory && $this->language_file == $file) ? ' selected="selected"' : ''; - $s_lang_options .= ''; - } - - // Now every other language directory - $check_files = array('email', 'acp', 'mods'); - - foreach ($check_files as $check) - { - if (!sizeof(${$check . '_files'})) - { - continue; - } - - $s_lang_options .= ''; - - foreach (${$check . '_files'} as $file) - { - $prefix = (file_exists($phpbb_root_path . $this->get_filename($lang_iso, $check, $file, true, true))) ? '* ' : ''; - - $selected = ($this->language_directory == $check && $this->language_file == $file) ? ' selected="selected"' : ''; - $s_lang_options .= ''; - } - } - - // Get Language Entries - if saved within store folder, we take this one (with the option to remove it) - $lang = array(); - - $is_email_file = ($this->language_directory == 'email') ? true : false; - $is_help_file = (strpos($this->language_file, 'help_') === 0) ? true : false; - - $file_from_store = (file_exists($phpbb_root_path . $this->get_filename($lang_iso, $this->language_directory, $this->language_file, true, true))) ? true : false; - $no_store_filename = $this->get_filename($lang_iso, $this->language_directory, $this->language_file); - - if (!$file_from_store && !file_exists($phpbb_root_path . $no_store_filename)) - { - $print_message = sprintf($user->lang['MISSING_LANGUAGE_FILE'], $no_store_filename); - } - else - { - if ($is_email_file) - { - $lang = file_get_contents($phpbb_root_path . $this->get_filename($lang_iso, $this->language_directory, $this->language_file, $file_from_store)); - } - else - { - $help = array(); - include($phpbb_root_path . $this->get_filename($lang_iso, $this->language_directory, $this->language_file, $file_from_store)); - - if ($is_help_file) - { - $lang = $help; - unset($help); - } - } - - $print_message = (($this->language_directory) ? $this->language_directory . '/' : '') . $this->language_file; - } - - // Normal language pack entries - $template->assign_vars(array( - 'U_ENTRY_ACTION' => $this->u_action . "&action=details&id=$lang_id#entries", - 'S_EMAIL_FILE' => $is_email_file, - 'S_FROM_STORE' => $file_from_store, - 'S_LANG_OPTIONS' => $s_lang_options, - 'PRINT_MESSAGE' => $print_message, - ) - ); - - if (!$is_email_file) - { - $tpl = ''; - $name = (($this->language_directory) ? $this->language_directory . '/' : '') . $this->language_file; - - if (isset($missing_vars[$name]) && sizeof($missing_vars[$name])) - { - $tpl .= $this->print_language_entries($missing_vars[$name], '* '); - } - - $tpl .= $this->print_language_entries($lang); - - $template->assign_var('TPL', $tpl); - unset($tpl); - } - else - { - $template->assign_vars(array( - 'LANG' => $lang) - ); - - unset($lang); - } - return; - break; case 'delete': @@ -830,7 +236,7 @@ class acp_language 'action' => $action, 'id' => $lang_id, ); - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); + confirm_box(false, $user->lang('DELETE_LANGUAGE_CONFIRM', $row['lang_english_name']), build_hidden_fields($s_hidden_fields)); } break; @@ -930,127 +336,6 @@ class acp_language trigger_error($message . adm_back_link($this->u_action)); break; - - case 'download': - - if (!$lang_id) - { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql = 'SELECT * - FROM ' . LANG_TABLE . ' - WHERE lang_id = ' . $lang_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $use_method = request_var('use_method', ''); - $methods = array('.tar'); - - $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib'); - foreach ($available_methods as $type => $module) - { - if (!@extension_loaded($module)) - { - continue; - } - - $methods[] = $type; - } - - // Let the user decide in which format he wants to have the pack - if (!$use_method) - { - $this->page_title = 'SELECT_DOWNLOAD_FORMAT'; - - $radio_buttons = ''; - foreach ($methods as $method) - { - $radio_buttons .= ''; - } - - $template->assign_vars(array( - 'S_SELECT_METHOD' => true, - 'U_BACK' => $this->u_action, - 'U_ACTION' => $this->u_action . "&action=$action&id=$lang_id", - 'RADIO_BUTTONS' => $radio_buttons) - ); - - return; - } - - if (!in_array($use_method, $methods)) - { - $use_method = '.tar'; - } - - include_once($phpbb_root_path . 'includes/functions_compress.' . $phpEx); - - if ($use_method == '.zip') - { - $compress = new compress_zip('w', $phpbb_root_path . 'store/lang_' . $row['lang_iso'] . $use_method); - } - else - { - $compress = new compress_tar('w', $phpbb_root_path . 'store/lang_' . $row['lang_iso'] . $use_method, $use_method); - } - - // Get email templates - $email_templates = filelist($phpbb_root_path . 'language/' . $row['lang_iso'], 'email', 'txt'); - $email_templates = $email_templates['email/']; - - // Get acp files - $acp_files = filelist($phpbb_root_path . 'language/' . $row['lang_iso'], 'acp', $phpEx); - $acp_files = $acp_files['acp/']; - - // Get mod files - $mod_files = filelist($phpbb_root_path . 'language/' . $row['lang_iso'], 'mods', $phpEx); - $mod_files = (isset($mod_files['mods/'])) ? $mod_files['mods/'] : array(); - - // Add main files - $this->add_to_archive($compress, $this->main_files, $row['lang_iso']); - - // Add search files if they exist... - if (file_exists($phpbb_root_path . 'language/' . $row['lang_iso'] . '/search_ignore_words.' . $phpEx)) - { - $this->add_to_archive($compress, array("search_ignore_words.$phpEx"), $row['lang_iso']); - } - - if (file_exists($phpbb_root_path . 'language/' . $row['lang_iso'] . '/search_synonyms.' . $phpEx)) - { - $this->add_to_archive($compress, array("search_synonyms.$phpEx"), $row['lang_iso']); - } - - // Write files in folders - $this->add_to_archive($compress, $email_templates, $row['lang_iso'], 'email'); - $this->add_to_archive($compress, $acp_files, $row['lang_iso'], 'acp'); - $this->add_to_archive($compress, $mod_files, $row['lang_iso'], 'mods'); - - // Write ISO File - $iso_src = htmlspecialchars_decode($row['lang_english_name']) . "\n"; - $iso_src .= htmlspecialchars_decode($row['lang_local_name']) . "\n"; - $iso_src .= htmlspecialchars_decode($row['lang_author']); - $compress->add_data($iso_src, 'language/' . $row['lang_iso'] . '/iso.txt'); - - // index.htm files - $compress->add_data('', 'language/' . $row['lang_iso'] . '/index.htm'); - $compress->add_data('', 'language/' . $row['lang_iso'] . '/email/index.htm'); - $compress->add_data('', 'language/' . $row['lang_iso'] . '/acp/index.htm'); - - if (sizeof($mod_files)) - { - $compress->add_data('', 'language/' . $row['lang_iso'] . '/mods/index.htm'); - } - - $compress->close(); - - $compress->download('lang_' . $row['lang_iso']); - @unlink($phpbb_root_path . 'store/lang_' . $row['lang_iso'] . $use_method); - - exit; - - break; } $sql = 'SELECT user_lang, COUNT(user_lang) AS lang_count @@ -1143,291 +428,31 @@ class acp_language unset($new_ary); } - - /** - * Set default language variables/header - */ - function default_variables() - { - global $phpEx; - - $this->language_file_header = 'lang_header = ' -$lang = array_merge($lang, array( -'; - - // Language files in language root directory - $this->main_files = array("captcha_qa.$phpEx", "captcha_recaptcha.$phpEx", "common.$phpEx", "groups.$phpEx", "install.$phpEx", "mcp.$phpEx", "memberlist.$phpEx", "posting.$phpEx", "search.$phpEx", "ucp.$phpEx", "viewforum.$phpEx", "viewtopic.$phpEx", "help_bbcode.$phpEx", "help_faq.$phpEx"); - } - - /** - * Get filename/location of language file - */ - function get_filename($lang_iso, $directory, $filename, $check_store = false, $only_return_filename = false) - { - global $phpbb_root_path, $safe_mode; - - $check_filename = "language/$lang_iso/" . (($directory) ? $directory . '/' : '') . $filename; - - if ($check_store) - { - $check_store_filename = ($safe_mode) ? "store/langfile_{$lang_iso}" . (($directory) ? '_' . $directory : '') . "_{$filename}" : "store/language/$lang_iso/" . (($directory) ? $directory . '/' : '') . $filename; - - if (!$only_return_filename && file_exists($phpbb_root_path . $check_store_filename)) - { - return $check_store_filename; - } - else if ($only_return_filename) - { - return $check_store_filename; - } - } - - return $check_filename; - } - - /** - * Add files to archive - */ - function add_to_archive(&$compress, $filelist, $lang_iso, $directory = '') - { - global $phpbb_root_path; - - foreach ($filelist as $file) - { - // Get source filename - $source = $this->get_filename($lang_iso, $directory, $file, true); - $destination = 'language/' . $lang_iso . '/' . (($directory) ? $directory . '/' : '') . $file; - - // Add file to archive - $compress->add_custom_file($phpbb_root_path . $source, $destination); - } - } - - /** - * Little helper to add some hardcoded template bits - */ - function add_input_field() - { - $keys = func_get_args(); - - $non_static = array_shift($keys); - $value = utf8_normalize_nfc(array_shift($keys)); - - if (!$non_static) - { - return '' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . ''; - } - - // If more then 270 characters, then we present a textarea, else an input field - $textarea = (utf8_strlen($value) > 270) ? true : false; - $tpl = ''; - - $tpl .= ($textarea) ? '' : '" />'; - - return $tpl; - } - - /** - * Print language entries - */ - function print_language_entries(&$lang_ary, $key_prefix = '', $input_field = true) - { - $tpl = ''; - - foreach ($lang_ary as $key => $value) - { - if (is_array($value)) - { - // Write key - $tpl .= ' - - ' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . ' - '; - - foreach ($value as $_key => $_value) - { - if (is_array($_value)) - { - // Write key - $tpl .= ' - - ' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '   ' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . ' - '; - - foreach ($_value as $__key => $__value) - { - // Write key - $tpl .= ' - - ' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '' . htmlspecialchars($__key, ENT_COMPAT, 'UTF-8') . ' - '; - - $tpl .= $this->add_input_field($input_field, $__value, $key, $_key, $__key); - - $tpl .= ' - '; - } - } - else - { - // Write key - $tpl .= ' - - ' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . ' - '; - - $tpl .= $this->add_input_field($input_field, $_value, $key, $_key); - - $tpl .= ' - '; - } - } - - $tpl .= ' - -   - '; - } - else - { - // Write key - $tpl .= ' - - ' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . ' - '; - - $tpl .= $this->add_input_field($input_field, $value, $key); - - $tpl .= ' - '; - } - } - - return $tpl; - } - /** * Compare two language files */ - function compare_language_files($source_lang, $dest_lang, $directory, $file) + function compare_language_files($source_lang, $dest_lang, $file) { - global $phpbb_root_path, $phpEx; + global $phpbb_root_path; - $return_ary = array(); + $source_file = $phpbb_root_path . 'language/' . $source_lang . '/' . $file; + $dest_file = $phpbb_root_path . 'language/' . $dest_lang . '/' . $file; - $lang = array(); - include("{$phpbb_root_path}language/{$source_lang}/" . (($directory) ? $directory . '/' : '') . $file); - $lang_entry_src = $lang; - - $lang = array(); - - if (!file_exists($phpbb_root_path . $this->get_filename($dest_lang, $directory, $file, true))) + if (!file_exists($dest_file)) { return array(); } - include($phpbb_root_path . $this->get_filename($dest_lang, $directory, $file, true)); + $lang = array(); + include($source_file); + $lang_entry_src = $lang; + $lang = array(); + include($dest_file); $lang_entry_dst = $lang; unset($lang); - $diff_array_keys = array_diff(array_keys($lang_entry_src), array_keys($lang_entry_dst)); - unset($lang_entry_dst); - - foreach ($diff_array_keys as $key) - { - $return_ary[$key] = $lang_entry_src[$key]; - } - - unset($lang_entry_src); - - return $return_ary; - } - - /** - * Return language string value for storage - */ - function prepare_lang_entry($text, $store = true) - { - $text = (STRIP) ? stripslashes($text) : $text; - - // Adjust for storage... - if ($store) - { - $text = str_replace("'", "\\'", str_replace('\\', '\\\\', $text)); - } - - return $text; - } - - /** - * Format language array for storage - */ - function format_lang_array($key, $value, $tabs = "\t") - { - $entry = ''; - - if (!is_array($value)) - { - $entry .= "{$tabs}'" . $this->prepare_lang_entry($key) . "'\t=> '" . $this->prepare_lang_entry($value) . "',\n"; - } - else - { - $_tabs = $tabs . "\t"; - $entry .= "\n{$tabs}'" . $this->prepare_lang_entry($key) . "'\t=> array(\n"; - - foreach ($value as $_key => $_value) - { - $entry .= $this->format_lang_array($_key, $_value, $_tabs); - } - - $entry .= "{$tabs}),\n\n"; - } - - return $entry; + return array_diff(array_keys($lang_entry_src), array_keys($lang_entry_dst)); } } diff --git a/phpBB/language/en/acp/language.php b/phpBB/language/en/acp/language.php index 20ad8c3ac0..f46e78efd4 100644 --- a/phpBB/language/en/acp/language.php +++ b/phpBB/language/en/acp/language.php @@ -40,26 +40,15 @@ $lang = array_merge($lang, array( 'ACP_FILES' => 'Admin language files', 'ACP_LANGUAGE_PACKS_EXPLAIN' => 'Here you are able to install/remove language packs. The default language pack is marked with an asterisk (*).', - 'EMAIL_FILES' => 'Email templates', + 'DELETE_LANGUAGE_CONFIRM' => 'Are you sure you wish to delete “%s”?', - 'FILE_CONTENTS' => 'File contents', - 'FILE_FROM_STORAGE' => 'File from storage folder', - - 'HELP_FILES' => 'Help files', - - 'INSTALLED_LANGUAGE_PACKS' => 'Installed language packs', - 'INVALID_LANGUAGE_PACK' => 'The selected language pack seems to be not valid. Please verify the language pack and upload it again if necessary.', - 'INVALID_UPLOAD_METHOD' => 'The selected upload method is not valid, please choose a different method.', + 'INSTALLED_LANGUAGE_PACKS' => 'Installed language packs', 'LANGUAGE_DETAILS_UPDATED' => 'Language details successfully updated.', - 'LANGUAGE_ENTRIES' => 'Language entries', - 'LANGUAGE_ENTRIES_EXPLAIN' => 'Here you are able to change existing language pack entries or not already translated ones.
Note: Once you changed a language file, the changes will be stored within a separate folder for you to download. The changes will not be seen by your users until you replace the original language files at your webspace (by uploading them).', - 'LANGUAGE_FILES' => 'Language files', - 'LANGUAGE_KEY' => 'Language key', 'LANGUAGE_PACK_ALREADY_INSTALLED' => 'This language pack is already installed.', - 'LANGUAGE_PACK_DELETED' => 'The language pack %s has been removed successfully. All users using this language have been reset to the boards default language.', + 'LANGUAGE_PACK_DELETED' => 'The language pack “%s” has been removed successfully. All users using this language have been reset to the board’s default language.', 'LANGUAGE_PACK_DETAILS' => 'Language pack details', - 'LANGUAGE_PACK_INSTALLED' => 'The language pack %s has been successfully installed.', + 'LANGUAGE_PACK_INSTALLED' => 'The language pack “%s” has been successfully installed.', 'LANGUAGE_PACK_CPF_UPDATE' => 'The custom profile fields’ language strings were copied from the default language. Please change them if necessary.', 'LANGUAGE_PACK_ISO' => 'ISO', 'LANGUAGE_PACK_LOCALNAME' => 'Local name', @@ -72,31 +61,16 @@ $lang = array_merge($lang, array( 'LANG_ISO_CODE' => 'ISO code', 'LANG_LOCAL_NAME' => 'Local name', - 'MISSING_LANGUAGE_FILE' => 'Missing language file: %s', + 'MISSING_LANG_FILES' => 'Missing language files', 'MISSING_LANG_VARIABLES' => 'Missing language variables', - 'MODS_FILES' => 'MODs language files', 'NO_FILE_SELECTED' => 'You haven’t specified a language file.', 'NO_LANG_ID' => 'You haven’t specified a language pack.', - 'NO_REMOVE_DEFAULT_LANG' => 'You are not able to remove the default language pack.
If you want to remove this language pack, change your boards default language first.', + 'NO_REMOVE_DEFAULT_LANG' => 'You are not able to remove the default language pack.
If you want to remove this language pack, change your board’s default language first.', 'NO_UNINSTALLED_LANGUAGE_PACKS' => 'No uninstalled language packs', - 'REMOVE_FROM_STORAGE_FOLDER' => 'Remove from storage folder', - - 'SELECT_DOWNLOAD_FORMAT' => 'Select download format', - 'SUBMIT_AND_DOWNLOAD' => 'Submit and download file', - 'SUBMIT_AND_UPLOAD' => 'Submit and upload file', - - 'THOSE_MISSING_LANG_FILES' => 'The following language files are missing from the %s language folder', - 'THOSE_MISSING_LANG_VARIABLES' => 'The following language variables are missing from the %s language pack', + 'THOSE_MISSING_LANG_FILES' => 'The following language files are missing from the “%s” language folder', + 'THOSE_MISSING_LANG_VARIABLES' => 'The following language variables are missing from the “%s” language pack', 'UNINSTALLED_LANGUAGE_PACKS' => 'Uninstalled language packs', - - 'UNABLE_TO_WRITE_FILE' => 'The file could not be written to %s.', - 'UPLOAD_COMPLETED' => 'The upload was completed successfully.', - 'UPLOAD_FAILED' => 'The upload failed for unknown reasons. You may need to replace the relevant file manually.', - 'UPLOAD_METHOD' => 'Upload method', - 'UPLOAD_SETTINGS' => 'Upload settings', - - 'WRONG_LANGUAGE_FILE' => 'Selected language file is invalid.', )); diff --git a/phpBB/phpbb/db/driver/mysql.php b/phpBB/phpbb/db/driver/mysql.php index 9b6d9962c9..569bd4f10a 100644 --- a/phpBB/phpbb/db/driver/mysql.php +++ b/phpBB/phpbb/db/driver/mysql.php @@ -210,7 +210,26 @@ class mysql extends \phpbb\db\driver\mysql_base */ function sql_affectedrows() { - return ($this->db_connect_id) ? @mysql_affected_rows($this->db_connect_id) : false; + if ($this->db_connect_id) + { + // We always want the number of matched rows + // instead of changed rows, when running an update. + // So when mysql_info() returns the number of matched rows + // we return that one instead of mysql_affected_rows() + $mysql_info = @mysql_info($this->db_connect_id); + if ($mysql_info !== false) + { + $match = array(); + preg_match('#^Rows matched: (\d)+ Changed: (\d)+ Warnings: (\d)+$#', $mysql_info, $match); + if (isset($match[1])) + { + return $match[1]; + } + } + + return @mysql_affected_rows($this->db_connect_id); + } + return false; } /** diff --git a/phpBB/phpbb/db/driver/mysqli.php b/phpBB/phpbb/db/driver/mysqli.php index da6dcbc776..58361ff0f8 100644 --- a/phpBB/phpbb/db/driver/mysqli.php +++ b/phpBB/phpbb/db/driver/mysqli.php @@ -60,7 +60,8 @@ class mysqli extends \phpbb\db\driver\mysql_base } } - $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket); + $this->db_connect_id = mysqli_init(); + @mysqli_real_connect($this->db_connect_id, $this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket, MYSQLI_CLIENT_FOUND_ROWS); if ($this->db_connect_id && $this->dbname != '') { diff --git a/phpBB/styles/prosilver/template/forum_fn.js b/phpBB/styles/prosilver/template/forum_fn.js index 1594d73517..a4ede51f4b 100644 --- a/phpBB/styles/prosilver/template/forum_fn.js +++ b/phpBB/styles/prosilver/template/forum_fn.js @@ -681,7 +681,7 @@ function parse_document(container) /** * Responsive link lists */ - container.find('.linklist:not(.navlinks, [data-skip-responsive]), .postbody ul.profile-icons:not([data-skip-responsive])').each(function() { + container.find('.linklist:not(.navlinks, [data-skip-responsive]), .postbody .post-buttons:not([data-skip-responsive])').each(function() { var $this = $(this), $body = $('body'), filterSkip = '.breadcrumbs, [data-skip-responsive]', @@ -769,6 +769,11 @@ function parse_document(container) menu.prepend(clone.not('.rightside')); menu.find('li.leftside, li.rightside').removeClass('leftside rightside'); menu.find('.inputbox').parents('li:first').css('white-space', 'normal'); + + if ($this.hasClass('post-buttons')) { + $('.button', menu).removeClass('button icon-button'); + $('.responsive-menu-link', item).addClass('button icon-button').prepend(''); + } copied = true; } else { @@ -914,6 +919,8 @@ function parse_document(container) $(document).ready(function() { // Swap .nojs and .hasjs $('#phpbb.nojs').toggleClass('nojs hasjs'); + $('#phpbb').toggleClass('hastouch', phpbb.isTouch); + $('#phpbb.hastouch').removeClass('notouch'); // Focus forms $('form[data-focus]:first').each(function() { diff --git a/phpBB/styles/prosilver/template/mcp_post.html b/phpBB/styles/prosilver/template/mcp_post.html index 2b4ebec5c8..10ec6f3ea9 100644 --- a/phpBB/styles/prosilver/template/mcp_post.html +++ b/phpBB/styles/prosilver/template/mcp_post.html @@ -50,13 +50,20 @@

{POST_SUBJECT}

- -