Merge pull request #4129 from marc1706/ticket/10824

[ticket/10824] Use composer.json in styles/languages
This commit is contained in:
Marc Alexander 2021-01-27 20:10:27 +01:00 committed by GitHub
commit c5b58e8b25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 668 additions and 362 deletions

View file

@ -24,6 +24,14 @@
<dt><label>{L_LANG_ISO_CODE}{L_COLON}</label></dt>
<dd><strong>{LANG_ISO}</strong></dd>
</dl>
<dl>
<dt><label>{{ lang('PHPBB_VERSION') ~ lang('COLON') }}</label></dt>
<dd><strong>{{ LANG_PHPBB_VERSION }}</strong></dd>
</dl>
<dl>
<dt><label>{{ lang('LANG_VERSION') ~ lang('COLON') }}</label></dt>
<dd><strong>{{ LANG_VERSION }}</strong></dd>
</dl>
<dl>
<dt><label for="lang_author">{L_LANG_AUTHOR}{L_COLON}</label></dt>
<dd><input type="text" id="lang_author" name="lang_author" value="{LANG_AUTHOR}" maxlength="255" /></dd>

View file

@ -127,7 +127,7 @@
<!-- IF styles_list.COMMENT != '' -->
<span class="error"><br />{styles_list.COMMENT}</span>
<!-- ENDIF -->
<!-- IF not styles_list.STYLE_ID and styles_list.COMMENT == '' -->
<!-- IF not styles_list.STYLE_ID and styles_list.COMMENT == '' and not styles_list.STYLE_INVALID -->
<span class="style-path"><br />{L_STYLE_PATH}{L_COLON} {styles_list.STYLE_PATH_FULL}</span>
<!-- ENDIF -->
</td>

View file

@ -19,48 +19,116 @@ if (!defined('IN_PHPBB'))
exit;
}
use phpbb\config\config;
use phpbb\db\driver\driver_interface;
use phpbb\event\dispatcher;
use phpbb\language\language;
use phpbb\language\language_file_helper;
use phpbb\log\log_interface;
use phpbb\request\request_interface;
use phpbb\template\template;
use phpbb\user;
class acp_language
{
var $u_action;
var $main_files;
var $language_header = '';
var $lang_header = '';
var $language_file = '';
var $language_directory = '';
function main($id, $mode)
/** @var config Config class */
protected $config;
/** @var driver_interface DBAL driver */
protected $db;
/** @var dispatcher Event dispatcher */
protected $dispatcher;
/** @var language Language class */
protected $language;
/** @var language_file_helper Language file helper */
protected $language_helper;
/** @var log_interface Logging class */
protected $log;
/** @var request_interface */
protected $request;
/** @var template Template class */
protected $template;
/** @var user User class */
protected $user;
/** @var string phpBB root path */
protected $phpbb_root_path;
/** @var string PHP file extension */
protected $php_ext;
/** @var string Page title */
public $page_title = 'ACP_LANGUAGE_PACKS';
/** @var string Template name */
public $tpl_name = 'acp_language';
/**
* acp_language constructor
*/
public function __construct()
{
global $config, $db, $user, $template, $phpbb_log, $phpbb_container;
global $phpbb_root_path, $phpEx, $request, $phpbb_dispatcher;
$this->config = $config;
$this->db = $db;
$this->dispatcher = $phpbb_dispatcher;
$this->language = $phpbb_container->get('language');
$this->language_helper = $phpbb_container->get('language.helper.language_file');
$this->log = $phpbb_log;
$this->request = $request;
$this->template = $template;
$this->user = $user;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $phpEx;
}
/**
* Main handler for acp_language
*
* @param int $id Module ID
* @param string $mode Module mode
*/
public function main($id, $mode)
{
if (!function_exists('validate_language_iso_name'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
}
// Check and set some common vars
$action = (isset($_POST['update_details'])) ? 'update_details' : '';
$action = (isset($_POST['remove_store'])) ? 'details' : $action;
$action = $this->request->is_set_post('update_details') ? 'update_details' : '';
$action = $this->request->is_set_post('remove_store') ? 'details' : $action;
$submit = (empty($action) && !isset($_POST['update']) && !isset($_POST['test_connection'])) ? false : true;
$action = (empty($action)) ? $request->variable('action', '') : $action;
$submit = (empty($action) && !$this->request->is_set_post('update') && !$this->request->is_set_post('test_connection')) ? false : true;
$action = (empty($action)) ? $this->request->variable('action', '') : $action;
$form_name = 'acp_lang';
add_form_key('acp_lang');
$lang_id = $request->variable('id', 0);
$lang_id = $this->request->variable('id', 0);
$selected_lang_file = $request->variable('language_file', '|common.' . $phpEx);
$selected_lang_file = $this->request->variable('language_file', '|common.' . $this->php_ext);
list($this->language_directory, $this->language_file) = explode('|', $selected_lang_file);
$this->language_directory = basename($this->language_directory);
$this->language_file = basename($this->language_file);
$user->add_lang('acp/language');
$this->tpl_name = 'acp_language';
$this->page_title = 'ACP_LANGUAGE_PACKS';
$this->language->add_lang('acp/language');
switch ($action)
{
@ -68,41 +136,41 @@ class acp_language
if (!$submit || !check_form_key($form_name))
{
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('FORM_INVALID'). adm_back_link($this->u_action), E_USER_WARNING);
}
if (!$lang_id)
{
trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->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);
$result = $this->db->sql_query($sql);
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
$sql_ary = array(
'lang_english_name' => $request->variable('lang_english_name', $row['lang_english_name']),
'lang_local_name' => $request->variable('lang_local_name', $row['lang_local_name'], true),
'lang_author' => $request->variable('lang_author', $row['lang_author'], true),
'lang_english_name' => $this->request->variable('lang_english_name', $row['lang_english_name']),
'lang_local_name' => $this->request->variable('lang_local_name', $row['lang_local_name'], true),
'lang_author' => $this->request->variable('lang_author', $row['lang_author'], true),
);
$db->sql_query('UPDATE ' . LANG_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
$this->db->sql_query('UPDATE ' . LANG_TABLE . '
SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . '
WHERE lang_id = ' . $lang_id);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_LANGUAGE_PACK_UPDATED', false, array($sql_ary['lang_english_name']));
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_LANGUAGE_PACK_UPDATED', false, array($sql_ary['lang_english_name']));
trigger_error($user->lang['LANGUAGE_DETAILS_UPDATED'] . adm_back_link($this->u_action));
trigger_error($this->language->lang('LANGUAGE_DETAILS_UPDATED') . adm_back_link($this->u_action));
break;
case 'details':
if (!$lang_id)
{
trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('NO_LANG_ID') . adm_back_link($this->u_action), E_USER_WARNING);
}
$this->page_title = 'LANGUAGE_PACK_DETAILS';
@ -110,39 +178,52 @@ class acp_language
$sql = 'SELECT *
FROM ' . LANG_TABLE . '
WHERE lang_id = ' . $lang_id;
$result = $db->sql_query($sql);
$lang_entries = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$result = $this->db->sql_query($sql);
$lang_entries = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
if (!$lang_entries)
{
trigger_error($user->lang['LANGUAGE_PACK_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('LANGUAGE_PACK_NOT_EXIST') . adm_back_link($this->u_action), E_USER_WARNING);
}
$lang_iso = $lang_entries['lang_iso'];
$template->assign_vars(array(
'S_DETAILS' => true,
'U_ACTION' => $this->u_action . "&amp;action=details&amp;id=$lang_id",
'U_BACK' => $this->u_action,
try
{
$lang_cfg = $this->language_helper->get_language_data_from_composer_file($this->phpbb_root_path . 'language/' . $lang_iso . '/composer.json');
}
catch (\DomainException $e)
{
trigger_error($this->language->lang('LANGUAGE_PACK_NOT_EXIST') . adm_back_link($this->u_action), E_USER_WARNING);
}
'LANG_LOCAL_NAME' => $lang_entries['lang_local_name'],
'LANG_ENGLISH_NAME' => $lang_entries['lang_english_name'],
'LANG_ISO' => $lang_iso,
'LANG_AUTHOR' => $lang_entries['lang_author'],
'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']),
$this->language->add_lang('acp/extensions');
$this->template->assign_vars(array(
'S_DETAILS' => true,
'U_ACTION' => $this->u_action . "&amp;action=details&amp;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_iso,
'LANG_VERSION' => $lang_cfg['version'],
'LANG_PHPBB_VERSION' => $lang_cfg['phpbb_version'],
'LANG_AUTHOR' => $lang_entries['lang_author'],
'L_MISSING_FILES' => $this->language->lang('THOSE_MISSING_LANG_FILES', $lang_entries['lang_local_name']),
'L_MISSING_VARS_EXPLAIN' => $this->language->lang('THOSE_MISSING_LANG_VARIABLES', $lang_entries['lang_local_name']),
));
// If current lang is different from the default lang, then highlight missing files and variables
if ($lang_iso != $config['default_lang'])
if ($lang_iso != $this->config['default_lang'])
{
try
{
$iterator = new \RecursiveIteratorIterator(
new \phpbb\recursive_dot_prefix_filter_iterator(
new \RecursiveDirectoryIterator(
$phpbb_root_path . 'language/' . $config['default_lang'] . '/',
$this->phpbb_root_path . 'language/' . $this->config['default_lang'] . '/',
\FilesystemIterator::SKIP_DOTS
)
),
@ -160,21 +241,21 @@ class acp_language
$relative_path = $iterator->getInnerIterator()->getSubPathname();
$relative_path = str_replace(DIRECTORY_SEPARATOR, '/', $relative_path);
if (file_exists($phpbb_root_path . 'language/' . $lang_iso . '/' . $relative_path))
if (file_exists($this->phpbb_root_path . 'language/' . $lang_iso . '/' . $relative_path))
{
if (substr($relative_path, 0 - strlen($phpEx)) === $phpEx)
if (substr($relative_path, -strlen($this->php_ext)) === $this->php_ext)
{
$missing_vars = $this->compare_language_files($config['default_lang'], $lang_iso, $relative_path);
$missing_vars = $this->compare_language_files($this->config['default_lang'], $lang_iso, $relative_path);
if (!empty($missing_vars))
{
$template->assign_block_vars('missing_varfile', array(
$this->template->assign_block_vars('missing_varfile', array(
'FILE_NAME' => $relative_path,
));
foreach ($missing_vars as $var)
{
$template->assign_block_vars('missing_varfile.variable', array(
$this->template->assign_block_vars('missing_varfile.variable', array(
'VAR_NAME' => $var,
));
}
@ -183,7 +264,7 @@ class acp_language
}
else
{
$template->assign_block_vars('missing_files', array(
$this->template->assign_block_vars('missing_files', array(
'FILE_NAME' => $relative_path,
));
}
@ -196,40 +277,40 @@ class acp_language
if (!$lang_id)
{
trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->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);
$result = $this->db->sql_query($sql);
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
if ($row['lang_iso'] == $config['default_lang'])
if ($row['lang_iso'] == $this->config['default_lang'])
{
trigger_error($user->lang['NO_REMOVE_DEFAULT_LANG'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('NO_REMOVE_DEFAULT_LANG') . adm_back_link($this->u_action), E_USER_WARNING);
}
if (confirm_box(true))
{
$db->sql_query('DELETE FROM ' . LANG_TABLE . ' WHERE lang_id = ' . $lang_id);
$this->db->sql_query('DELETE FROM ' . LANG_TABLE . ' WHERE lang_id = ' . $lang_id);
$sql = 'UPDATE ' . USERS_TABLE . "
SET user_lang = '" . $db->sql_escape($config['default_lang']) . "'
WHERE user_lang = '" . $db->sql_escape($row['lang_iso']) . "'";
$db->sql_query($sql);
SET user_lang = '" . $this->db->sql_escape($this->config['default_lang']) . "'
WHERE user_lang = '" . $this->db->sql_escape($row['lang_iso']) . "'";
$this->db->sql_query($sql);
// We also need to remove the translated entries for custom profile fields - we want clean tables, don't we?
$sql = 'DELETE FROM ' . PROFILE_LANG_TABLE . ' WHERE lang_id = ' . $lang_id;
$db->sql_query($sql);
$this->db->sql_query($sql);
$sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . ' WHERE lang_id = ' . $lang_id;
$db->sql_query($sql);
$this->db->sql_query($sql);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_LANGUAGE_PACK_DELETED', false, array($row['lang_english_name']));
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_LANGUAGE_PACK_DELETED', false, array($row['lang_english_name']));
$delete_message = sprintf($user->lang['LANGUAGE_PACK_DELETED'], $row['lang_english_name']);
$delete_message = $this->language->lang('LANGUAGE_PACK_DELETED', $row['lang_english_name']);
$lang_iso = $row['lang_iso'];
/**
* Run code after language deleted
@ -240,7 +321,7 @@ class acp_language
* @since 3.2.2-RC1
*/
$vars = array('lang_iso', 'delete_message');
extract($phpbb_dispatcher->trigger_event('core.acp_language_after_delete', compact($vars)));
extract($this->dispatcher->trigger_event('core.acp_language_after_delete', compact($vars)));
trigger_error($delete_message . adm_back_link($this->u_action));
}
@ -252,49 +333,48 @@ class acp_language
'action' => $action,
'id' => $lang_id,
);
confirm_box(false, $user->lang('DELETE_LANGUAGE_CONFIRM', $row['lang_english_name']), build_hidden_fields($s_hidden_fields));
confirm_box(false, $this->language->lang('DELETE_LANGUAGE_CONFIRM', $row['lang_english_name']), build_hidden_fields($s_hidden_fields));
}
break;
case 'install':
if (!check_link_hash($request->variable('hash', ''), 'acp_language'))
if (!check_link_hash($this->request->variable('hash', ''), 'acp_language'))
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING);
}
$lang_iso = $request->variable('iso', '');
$lang_iso = $this->request->variable('iso', '');
$lang_iso = basename($lang_iso);
if (!$lang_iso || !file_exists("{$phpbb_root_path}language/$lang_iso/iso.txt"))
if (!$lang_iso || !file_exists("{$this->phpbb_root_path}language/$lang_iso/composer.json"))
{
trigger_error($user->lang['LANGUAGE_PACK_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('LANGUAGE_PACK_NOT_EXIST') . adm_back_link($this->u_action), E_USER_WARNING);
}
$file = file("{$phpbb_root_path}language/$lang_iso/iso.txt");
$lang_pack = array(
'iso' => $lang_iso,
'name' => trim(htmlspecialchars($file[0], ENT_COMPAT)),
'local_name'=> trim(htmlspecialchars($file[1], ENT_COMPAT, 'UTF-8')),
'author' => trim(htmlspecialchars($file[2], ENT_COMPAT, 'UTF-8'))
);
unset($file);
try
{
$lang_pack = $this->language_helper->get_language_data_from_composer_file("{$this->phpbb_root_path}language/$lang_iso/composer.json");
}
catch (\DomainException $e)
{
trigger_error($this->language->lang('LANGUAGE_PACK_NOT_EXIST') . adm_back_link($this->u_action), E_USER_WARNING);
}
$sql = 'SELECT lang_iso
FROM ' . LANG_TABLE . "
WHERE lang_iso = '" . $db->sql_escape($lang_iso) . "'";
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
WHERE lang_iso = '" . $this->db->sql_escape($lang_iso) . "'";
$result = $this->db->sql_query($sql);
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
if ($row)
{
trigger_error($user->lang['LANGUAGE_PACK_ALREADY_INSTALLED'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('LANGUAGE_PACK_ALREADY_INSTALLED') . adm_back_link($this->u_action), E_USER_WARNING);
}
if (!$lang_pack['name'] || !$lang_pack['local_name'])
{
trigger_error($user->lang['INVALID_LANGUAGE_PACK'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('INVALID_LANGUAGE_PACK') . adm_back_link($this->u_action), E_USER_WARNING);
}
// Add language pack
@ -306,16 +386,16 @@ class acp_language
'lang_author' => $lang_pack['author']
);
$db->sql_query('INSERT INTO ' . LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
$lang_id = $db->sql_nextid();
$this->db->sql_query('INSERT INTO ' . LANG_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary));
$lang_id = $this->db->sql_nextid();
// Now let's copy the default language entries for custom profile fields for this new language - makes admin's life easier.
$sql = 'SELECT lang_id
FROM ' . LANG_TABLE . "
WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'";
$result = $db->sql_query($sql);
$default_lang_id = (int) $db->sql_fetchfield('lang_id');
$db->sql_freeresult($result);
WHERE lang_iso = '" . $this->db->sql_escape($this->config['default_lang']) . "'";
$result = $this->db->sql_query($sql);
$default_lang_id = (int) $this->db->sql_fetchfield('lang_id');
$this->db->sql_freeresult($result);
// We want to notify the admin that custom profile fields need to be updated for the new language.
$notify_cpf_update = false;
@ -327,33 +407,33 @@ class acp_language
$sql = 'SELECT field_id, lang_name, lang_explain, lang_default_value
FROM ' . PROFILE_LANG_TABLE . '
WHERE lang_id = ' . $default_lang_id;
$result = $db->sql_query($sql);
$result = $this->db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
while ($row = $this->db->sql_fetchrow($result))
{
$row['lang_id'] = $lang_id;
$db->sql_query('INSERT INTO ' . PROFILE_LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $row));
$this->db->sql_query('INSERT INTO ' . PROFILE_LANG_TABLE . ' ' . $this->db->sql_build_array('INSERT', $row));
$notify_cpf_update = true;
}
$db->sql_freeresult($result);
$this->db->sql_freeresult($result);
$sql = 'SELECT field_id, option_id, field_type, lang_value
FROM ' . PROFILE_FIELDS_LANG_TABLE . '
WHERE lang_id = ' . $default_lang_id;
$result = $db->sql_query($sql);
$result = $this->db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
while ($row = $this->db->sql_fetchrow($result))
{
$row['lang_id'] = $lang_id;
$db->sql_query('INSERT INTO ' . PROFILE_FIELDS_LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $row));
$this->db->sql_query('INSERT INTO ' . PROFILE_FIELDS_LANG_TABLE . ' ' . $this->db->sql_build_array('INSERT', $row));
$notify_cpf_update = true;
}
$db->sql_freeresult($result);
$this->db->sql_freeresult($result);
$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_LANGUAGE_PACK_INSTALLED', false, array($lang_pack['name']));
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_LANGUAGE_PACK_INSTALLED', false, array($lang_pack['name']));
$message = sprintf($user->lang['LANGUAGE_PACK_INSTALLED'], $lang_pack['name']);
$message .= ($notify_cpf_update) ? '<br /><br />' . $user->lang['LANGUAGE_PACK_CPF_UPDATE'] : '';
$message = $this->language->lang('LANGUAGE_PACK_INSTALLED', $lang_pack['name']);
$message .= ($notify_cpf_update) ? '<br /><br />' . $this->language->lang('LANGUAGE_PACK_CPF_UPDATE') : '';
trigger_error($message . adm_back_link($this->u_action));
break;
@ -362,28 +442,28 @@ class acp_language
$sql = 'SELECT user_lang, COUNT(user_lang) AS lang_count
FROM ' . USERS_TABLE . '
GROUP BY user_lang';
$result = $db->sql_query($sql);
$result = $this->db->sql_query($sql);
$lang_count = array();
while ($row = $db->sql_fetchrow($result))
while ($row = $this->db->sql_fetchrow($result))
{
$lang_count[$row['user_lang']] = $row['lang_count'];
}
$db->sql_freeresult($result);
$this->db->sql_freeresult($result);
$sql = 'SELECT *
FROM ' . LANG_TABLE . '
ORDER BY lang_english_name';
$result = $db->sql_query($sql);
$result = $this->db->sql_query($sql);
$installed = array();
while ($row = $db->sql_fetchrow($result))
while ($row = $this->db->sql_fetchrow($result))
{
$installed[] = $row['lang_iso'];
$tagstyle = ($row['lang_iso'] == $config['default_lang']) ? '*' : '';
$tagstyle = ($row['lang_iso'] == $this->config['default_lang']) ? '*' : '';
$template->assign_block_vars('lang', array(
$this->template->assign_block_vars('lang', array(
'U_DETAILS' => $this->u_action . "&amp;action=details&amp;id={$row['lang_id']}",
'U_DOWNLOAD' => $this->u_action . "&amp;action=download&amp;id={$row['lang_id']}",
'U_DELETE' => $this->u_action . "&amp;action=delete&amp;id={$row['lang_id']}",
@ -395,13 +475,11 @@ class acp_language
'USED_BY' => (isset($lang_count[$row['lang_iso']])) ? $lang_count[$row['lang_iso']] : 0,
));
}
$db->sql_freeresult($result);
$this->db->sql_freeresult($result);
$new_ary = $iso = array();
/** @var \phpbb\language\language_file_helper $language_helper */
$language_helper = $phpbb_container->get('language.helper.language_file');
$iso = $language_helper->get_available_languages();
$iso = $this->language_helper->get_available_languages();
foreach ($iso as $lang_array)
{
@ -419,7 +497,7 @@ class acp_language
{
foreach ($new_ary as $iso => $lang_ary)
{
$template->assign_block_vars('notinst', array(
$this->template->assign_block_vars('notinst', array(
'ISO' => htmlspecialchars($lang_ary['iso'], ENT_COMPAT),
'LOCAL_NAME' => htmlspecialchars($lang_ary['local_name'], ENT_COMPAT, 'UTF-8'),
'NAME' => htmlspecialchars($lang_ary['name'], ENT_COMPAT, 'UTF-8'),
@ -436,10 +514,8 @@ class acp_language
*/
function compare_language_files($source_lang, $dest_lang, $file)
{
global $phpbb_root_path;
$source_file = $phpbb_root_path . 'language/' . $source_lang . '/' . $file;
$dest_file = $phpbb_root_path . 'language/' . $dest_lang . '/' . $file;
$source_file = $this->phpbb_root_path . 'language/' . $source_lang . '/' . $file;
$dest_file = $this->phpbb_root_path . 'language/' . $dest_lang . '/' . $file;
if (!file_exists($dest_file))
{

View file

@ -38,8 +38,8 @@ class acp_styles
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbb\user */
protected $user;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbb\template\template */
protected $template;
@ -67,10 +67,10 @@ class acp_styles
public function main($id, $mode)
{
global $db, $user, $phpbb_admin_path, $phpbb_root_path, $phpEx, $template, $request, $cache, $auth, $config, $phpbb_dispatcher, $phpbb_container;
global $db, $phpbb_admin_path, $phpbb_root_path, $phpEx, $template, $request, $cache, $auth, $config, $phpbb_dispatcher, $phpbb_container;
$this->db = $db;
$this->user = $user;
$this->language = $phpbb_container->get('language');
$this->template = $template;
$this->request = $request;
$this->cache = $cache;
@ -89,7 +89,7 @@ class acp_styles
'mode' => $mode,
);
$this->user->add_lang('acp/styles');
$this->language->add_lang('acp/styles');
$this->tpl_name = 'acp_styles';
$this->page_title = 'ACP_CAT_STYLES';
@ -114,7 +114,7 @@ class acp_styles
if (!$is_valid_request)
{
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING);
}
}
@ -183,7 +183,7 @@ class acp_styles
$this->show_available();
return;
}
trigger_error($this->user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('NO_MODE') . adm_back_link($this->u_action), E_USER_WARNING);
}
/**
@ -205,7 +205,7 @@ class acp_styles
{
if (in_array($dir, $this->reserved_style_names))
{
$messages[] = $this->user->lang('STYLE_NAME_RESERVED', htmlspecialchars($dir, ENT_COMPAT));
$messages[] = $this->language->lang('STYLE_NAME_RESERVED', htmlspecialchars($dir, ENT_COMPAT));
continue;
}
@ -225,12 +225,12 @@ class acp_styles
$found = true;
$installed_names[] = $style['style_name'];
$installed_dirs[] = $style['style_path'];
$messages[] = sprintf($this->user->lang['STYLE_INSTALLED'], htmlspecialchars($style['style_name'], ENT_COMPAT));
$messages[] = $this->language->lang('STYLE_INSTALLED', htmlspecialchars($style['style_name'], ENT_COMPAT));
}
}
if (!$found)
{
$messages[] = sprintf($this->user->lang['STYLE_NOT_INSTALLED'], htmlspecialchars($dir, ENT_COMPAT));
$messages[] = $this->language->lang('STYLE_NOT_INSTALLED', htmlspecialchars($dir, ENT_COMPAT));
}
}
@ -243,11 +243,11 @@ class acp_styles
// Show message
if (!count($messages))
{
trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('NO_MATCHING_STYLES_FOUND') . adm_back_link($this->u_action), E_USER_WARNING);
}
$message = implode('<br />', $messages);
$message .= '<br /><br /><a href="' . $this->u_base_action . '&amp;mode=style' . '">&laquo; ' . $this->user->lang('STYLE_INSTALLED_RETURN_INSTALLED_STYLES') . '</a>';
$message .= '<br /><br /><a href="' . $this->u_base_action . '&amp;mode=install' . '">&raquo; ' . $this->user->lang('STYLE_INSTALLED_RETURN_UNINSTALLED_STYLES') . '</a>';
$message .= '<br /><br /><a href="' . $this->u_base_action . '&amp;mode=style' . '">&laquo; ' . $this->language->lang('STYLE_INSTALLED_RETURN_INSTALLED_STYLES') . '</a>';
$message .= '<br /><br /><a href="' . $this->u_base_action . '&amp;mode=install' . '">&raquo; ' . $this->language->lang('STYLE_INSTALLED_RETURN_UNINSTALLED_STYLES') . '</a>';
trigger_error($message, E_USER_NOTICE);
}
@ -269,7 +269,7 @@ class acp_styles
if ($prosilver_id && in_array($prosilver_id, $ids))
{
trigger_error($this->user->lang('UNINSTALL_PROSILVER') . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('UNINSTALL_PROSILVER') . adm_back_link($this->u_action), E_USER_WARNING);
}
// Check if confirmation box was submitted
@ -286,7 +286,7 @@ class acp_styles
'ids' => $ids
));
$this->template->assign_var('S_CONFIRM_DELETE', true);
confirm_box(false, $this->user->lang['CONFIRM_UNINSTALL_STYLES'], $s_hidden, 'acp_styles.html');
confirm_box(false, $this->language->lang('CONFIRM_UNINSTALL_STYLES'), $s_hidden, 'acp_styles.html');
// Canceled - show styles list
$this->frontend();
@ -311,11 +311,11 @@ class acp_styles
{
if (!$id)
{
trigger_error($this->user->lang['INVALID_STYLE_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('INVALID_STYLE_ID') . adm_back_link($this->u_action), E_USER_WARNING);
}
if ($id == $default)
{
trigger_error($this->user->lang['UNINSTALL_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('UNINSTALL_DEFAULT') . adm_back_link($this->u_action), E_USER_WARNING);
}
$uninstalled[$id] = false;
}
@ -342,20 +342,20 @@ class acp_styles
$messages[] = $result;
continue;
}
$messages[] = sprintf($this->user->lang['STYLE_UNINSTALLED'], $style['style_name']);
$messages[] = $this->language->lang('STYLE_UNINSTALLED', $style['style_name']);
$uninstalled[] = $style['style_name'];
// Attempt to delete files
if ($delete_files)
{
$messages[] = sprintf($this->user->lang[$this->delete_style_files($style['style_path']) ? 'DELETE_STYLE_FILES_SUCCESS' : 'DELETE_STYLE_FILES_FAILED'], $style['style_name']);
$messages[] = $this->language->lang($this->delete_style_files($style['style_path']) ? 'DELETE_STYLE_FILES_SUCCESS' : 'DELETE_STYLE_FILES_FAILED', $style['style_name']);
}
}
if (empty($messages))
{
// Nothing to uninstall?
trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('NO_MATCHING_STYLES_FOUND') . adm_back_link($this->u_action), E_USER_WARNING);
}
// Log action
@ -405,7 +405,7 @@ class acp_styles
{
if ($id == $this->default_style)
{
trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('DEACTIVATE_DEFAULT') . adm_back_link($this->u_action), E_USER_WARNING);
}
}
@ -438,7 +438,7 @@ class acp_styles
$id = $this->request->variable('id', 0);
if (!$id)
{
trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('NO_MATCHING_STYLES_FOUND') . adm_back_link($this->u_action), E_USER_WARNING);
}
// Get all styles
@ -458,11 +458,11 @@ class acp_styles
if ($style === false)
{
trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('NO_MATCHING_STYLES_FOUND') . adm_back_link($this->u_action), E_USER_WARNING);
}
// Read style configuration file
$style_cfg = $this->read_style_cfg($style['style_path']);
$style_cfg = $this->read_style_composer_file($style['style_path']);
// Find all available parent styles
$list = $this->find_possible_parents($styles, $id);
@ -476,7 +476,7 @@ class acp_styles
{
if (!check_form_key($form_key))
{
trigger_error($this->user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING);
}
$update = array(
@ -491,13 +491,13 @@ class acp_styles
{
if (!strlen($update['style_name']))
{
trigger_error($this->user->lang['STYLE_ERR_STYLE_NAME'] . adm_back_link($update_action), E_USER_WARNING);
trigger_error($this->language->lang('STYLE_ERR_STYLE_NAME') . adm_back_link($update_action), E_USER_WARNING);
}
foreach ($styles as $row)
{
if ($row['style_name'] == $update['style_name'])
{
trigger_error($this->user->lang['STYLE_ERR_NAME_EXIST'] . adm_back_link($update_action), E_USER_WARNING);
trigger_error($this->language->lang('STYLE_ERR_NAME_EXIST') . adm_back_link($update_action), E_USER_WARNING);
}
}
}
@ -523,7 +523,7 @@ class acp_styles
}
if (!$found)
{
trigger_error($this->user->lang['STYLE_ERR_INVALID_PARENT'] . adm_back_link($update_action), E_USER_WARNING);
trigger_error($this->language->lang('STYLE_ERR_INVALID_PARENT') . adm_back_link($update_action), E_USER_WARNING);
}
}
else
@ -541,7 +541,7 @@ class acp_styles
{
if (!$update['style_active'] && $this->default_style == $style['style_id'])
{
trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($update_action), E_USER_WARNING);
trigger_error($this->language->lang('DEACTIVATE_DEFAULT') . adm_back_link($update_action), E_USER_WARNING);
}
}
else
@ -579,7 +579,7 @@ class acp_styles
{
if (!$style['style_active'])
{
trigger_error($this->user->lang['STYLE_DEFAULT_CHANGE_INACTIVE'] . adm_back_link($update_action), E_USER_WARNING);
trigger_error($this->language->lang('STYLE_DEFAULT_CHANGE_INACTIVE') . adm_back_link($update_action), E_USER_WARNING);
}
$this->config->set('default_style', $id);
$this->cache->purge();
@ -611,13 +611,12 @@ class acp_styles
'STYLE_ID' => $style['style_id'],
'STYLE_NAME' => htmlspecialchars($style['style_name'], ENT_COMPAT),
'STYLE_PATH' => htmlspecialchars($style['style_path'], ENT_COMPAT),
'STYLE_VERSION' => htmlspecialchars($style_cfg['style_version'], ENT_COMPAT),
'STYLE_VERSION' => htmlspecialchars($style_cfg['version'], ENT_COMPAT),
'STYLE_COPYRIGHT' => strip_tags($style['style_copyright']),
'STYLE_PARENT' => $style['style_parent_id'],
'S_STYLE_ACTIVE' => $style['style_active'],
'S_STYLE_DEFAULT' => ($style['style_id'] == $this->default_style)
)
);
));
}
/**
@ -630,7 +629,7 @@ class acp_styles
if (!count($styles))
{
trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('NO_MATCHING_STYLES_FOUND') . adm_back_link($this->u_action), E_USER_WARNING);
}
usort($styles, array($this, 'sort_styles'));
@ -657,7 +656,7 @@ class acp_styles
{
if (empty($style['_shown']))
{
$style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($style['style_parent_tree'], ENT_COMPAT));
$style['_note'] = $this->language->lang('REQUIRES_STYLE', htmlspecialchars($style['style_parent_tree'], ENT_COMPAT));
$this->list_style($style, 0);
}
}
@ -665,13 +664,13 @@ class acp_styles
// Add buttons
$this->template->assign_block_vars('extra_actions', array(
'ACTION_NAME' => 'activate',
'L_ACTION' => $this->user->lang['STYLE_ACTIVATE'],
'L_ACTION' => $this->language->lang('STYLE_ACTIVATE'),
)
);
$this->template->assign_block_vars('extra_actions', array(
'ACTION_NAME' => 'deactivate',
'L_ACTION' => $this->user->lang['STYLE_DEACTIVATE'],
'L_ACTION' => $this->language->lang('STYLE_DEACTIVATE'),
)
);
@ -679,7 +678,7 @@ class acp_styles
{
$this->template->assign_block_vars('extra_actions', array(
'ACTION_NAME' => 'uninstall',
'L_ACTION' => $this->user->lang['STYLE_UNINSTALL'],
'L_ACTION' => $this->language->lang('STYLE_UNINSTALL'),
)
);
}
@ -696,7 +695,7 @@ class acp_styles
// Show styles
if (empty($styles))
{
trigger_error($this->user->lang['NO_UNINSTALLED_STYLE'] . adm_back_link($this->u_base_action), E_USER_NOTICE);
trigger_error($this->language->lang('NO_UNINSTALLED_STYLE') . adm_back_link($this->u_base_action), E_USER_NOTICE);
}
usort($styles, array($this, 'sort_styles'));
@ -711,6 +710,12 @@ class acp_styles
// Show styles
foreach ($styles as &$style)
{
if (!$style['_available'] && !empty($style['_invalid']))
{
$this->list_invalid($style);
continue;
}
// Check if style has a parent style in styles list
$has_parent = false;
if ($style['_inherit_name'] != '')
@ -745,7 +750,7 @@ class acp_styles
{
$this->template->assign_block_vars('extra_actions', array(
'ACTION_NAME' => 'install',
'L_ACTION' => $this->user->lang['INSTALL_STYLES'],
'L_ACTION' => $this->language->lang('INSTALL_STYLES'),
)
);
}
@ -787,22 +792,33 @@ class acp_styles
// Style is already installed
continue;
}
$cfg = $this->read_style_cfg($dir);
if ($cfg === false)
try
{
// Invalid style.cfg
$style_data = $this->read_style_composer_file($dir);
}
catch (\DomainException $e)
{
// Invalid composer.json
$style = array(
'_available' => false,
'_invalid' => true,
'style_path' => $dir,
);
$styles[] = $style;
continue;
}
// Style should be available for installation
$parent = $cfg['parent'];
$parent = $style_data['extra']['parent-style'];
$style = array(
'style_id' => 0,
'style_name' => $cfg['name'],
'style_copyright' => $cfg['copyright'],
'style_name' => $style_data['extra']['display-name'],
'style_copyright' => $style_data['license'],
'style_active' => 0,
'style_path' => $dir,
'bbcode_bitfield' => $cfg['template_bitfield'],
'bbcode_bitfield' => $style_data['extra']['template-bitfield'],
'style_parent_id' => 0,
'style_parent_tree' => '',
// Extra values for styles list
@ -826,7 +842,7 @@ class acp_styles
{
// Parent style is not installed yet
$style['_available'] = false;
$style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($parent, ENT_COMPAT));
$style['_note'] = $this->language->lang('REQUIRES_STYLE', htmlspecialchars($parent, ENT_COMPAT));
}
}
@ -949,7 +965,7 @@ class acp_styles
* @param array $style style row
* @param int $level style inheritance level
*/
protected function list_style(&$style, $level)
protected function list_style(array &$style, int $level) : void
{
// Mark row as shown
if (!empty($style['_shown']))
@ -959,35 +975,35 @@ class acp_styles
$style['_shown'] = true;
$style_cfg = $this->read_style_cfg($style['style_path']);
$style_cfg = $this->read_style_composer_file($style['style_path']);
// Generate template variables
$actions = array();
$row = array(
$actions = [];
$row = [
// Style data
'STYLE_ID' => $style['style_id'],
'STYLE_NAME' => htmlspecialchars($style['style_name'], ENT_COMPAT),
'STYLE_VERSION' => $style_cfg['style_version'] ?? '-',
'STYLE_PHPBB_VERSION' => $style_cfg['phpbb_version'],
'STYLE_VERSION' => $style_cfg['version'] ?? '-',
'STYLE_PHPBB_VERSION' => $style_cfg['extra']['phpbb-version'] ?? '',
'STYLE_PATH' => htmlspecialchars($style['style_path'], ENT_COMPAT),
'STYLE_COPYRIGHT' => strip_tags($style['style_copyright']),
'STYLE_ACTIVE' => $style['style_active'],
// Additional data
'DEFAULT' => ($style['style_id'] && $style['style_id'] == $this->default_style),
'USERS' => (isset($style['_users'])) ? $style['_users'] : '',
'USERS' => $style['_users'] ?? '',
'LEVEL' => $level,
'PADDING' => (4 + 16 * $level),
'SHOW_COPYRIGHT' => ($style['style_id']) ? false : true,
'STYLE_PATH_FULL' => htmlspecialchars($this->styles_path_absolute . '/' . $style['style_path'], ENT_COMPAT) . '/',
// Comment to show below style
'COMMENT' => (isset($style['_note'])) ? $style['_note'] : '',
'COMMENT' => $style['_note'] ?? '',
// The following variables should be used by hooks to add custom HTML code
'EXTRA' => '',
'EXTRA_OPTIONS' => ''
);
];
// Status specific data
if ($style['style_id'])
@ -995,60 +1011,52 @@ class acp_styles
// Style is installed
// Details
$actions[] = array(
$actions[] = [
'U_ACTION' => $this->u_action . '&amp;action=details&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['DETAILS']
);
'L_ACTION' => $this->language->lang('DETAILS')
];
// Activate/Deactive
// Activate/Deactivate
$action_name = ($style['style_active'] ? 'de' : '') . 'activate';
$actions[] = array(
$actions[] = [
'U_ACTION' => $this->u_action . '&amp;action=' . $action_name . '&amp;hash=' . generate_link_hash($action_name) . '&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['STYLE_' . ($style['style_active'] ? 'DE' : '') . 'ACTIVATE']
);
/* // Export
$actions[] = array(
'U_ACTION' => $this->u_action . '&amp;action=export&amp;hash=' . generate_link_hash('export') . '&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['EXPORT']
); */
'L_ACTION' => $this->language->lang('STYLE_' . ($style['style_active'] ? 'DE' : '') . 'ACTIVATE')
];
if ($style['style_name'] !== 'prosilver')
{
// Uninstall
$actions[] = array(
$actions[] = [
'U_ACTION' => $this->u_action . '&amp;action=uninstall&amp;hash=' . generate_link_hash('uninstall') . '&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['STYLE_UNINSTALL']
);
'L_ACTION' => $this->language->lang('STYLE_UNINSTALL')
];
}
// Preview
$actions[] = array(
$actions[] = [
'U_ACTION' => append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'style=' . $style['style_id']),
'L_ACTION' => $this->user->lang['PREVIEW']
);
'L_ACTION' => $this->language->lang('PREVIEW')
];
}
else
{
// Style is not installed
if (empty($style['_available']))
{
$actions[] = array(
'HTML' => $this->user->lang['CANNOT_BE_INSTALLED']
);
$actions[] = [
'HTML' => $this->language->lang('CANNOT_BE_INSTALLED')
];
}
else
{
$actions[] = array(
$actions[] = [
'U_ACTION' => $this->u_action . '&amp;action=install&amp;hash=' . generate_link_hash('install') . '&amp;dir=' . urlencode($style['style_path']),
'L_ACTION' => $this->user->lang['INSTALL_STYLE']
);
'L_ACTION' => $this->language->lang('INSTALL_STYLE')
];
}
}
// todo: add hook
// Assign template variables
$this->template->assign_block_vars('styles_list', $row);
foreach ($actions as $action)
@ -1060,18 +1068,54 @@ class acp_styles
$counter = ($style['style_id']) ? ($style['style_active'] ? 'active' : 'inactive') : (empty($style['_available']) ? 'cannotinstall' : 'caninstall');
if (!isset($this->style_counters))
{
$this->style_counters = array(
$this->style_counters = [
'total' => 0,
'active' => 0,
'inactive' => 0,
'caninstall' => 0,
'cannotinstall' => 0
);
];
}
$this->style_counters[$counter]++;
$this->style_counters['total']++;
}
/**
* List invalid style
*
* @param array $style Array with info about style to display as invalid
*/
protected function list_invalid(&$style)
{
$style['_shown'] = true;
$row = [
// Style data
'STYLE_INVALID' => true,
'STYLE_NAME' => $this->language->lang('INVALID_STYLE_MESSAGE', $style['style_path']),
];
$this->template->assign_block_vars('styles_list', $row);
$this->template->assign_block_vars('styles_list.actions', [
'HTML' => $this->language->lang('CANNOT_BE_INSTALLED')
]);
// Increase counters
if (!isset($this->style_counters))
{
$this->style_counters = [
'total' => 0,
'active' => 0,
'inactive' => 0,
'caninstall' => 0,
'cannotinstall' => 0
];
}
$this->style_counters['cannotinstall']++;
$this->style_counters['total']++;
}
/**
* Show welcome message
*
@ -1080,11 +1124,10 @@ class acp_styles
*/
protected function welcome_message($title, $description)
{
$this->template->assign_vars(array(
'L_TITLE' => $this->user->lang[$title],
'L_EXPLAIN' => (isset($this->user->lang[$description])) ? $this->user->lang[$description] : ''
)
);
$this->template->assign_vars([
'L_TITLE' => $this->language->lang($title),
'L_EXPLAIN' => $this->language->is_set($description) ? $this->language->lang($description) : ''
]);
}
/**
@ -1107,7 +1150,7 @@ class acp_styles
continue;
}
if (file_exists("{$dir}/style.cfg"))
if (file_exists("{$dir}/composer.json"))
{
$styles[] = $file;
}
@ -1135,43 +1178,45 @@ class acp_styles
}
/**
* Read style configuration file
*
* @param string $dir style directory
* @return array|bool Style data, false on error
*/
protected function read_style_cfg($dir)
* Read style composer.json file
*
* @param string $dir style directory
*
* @return array Style data
* @throws \DomainException in case of error
*/
protected function read_style_composer_file($dir)
{
// This should never happen, we give them a red warning because of its relevance.
if (!file_exists($this->styles_path . $dir . '/style.cfg'))
if (!file_exists($this->styles_path . $dir . '/composer.json'))
{
trigger_error($this->user->lang('NO_STYLE_CFG', $dir), E_USER_WARNING);
trigger_error($this->language->lang('NO_STYLE_CFG', $dir), E_USER_WARNING);
}
static $required = array('name', 'phpbb_version', 'copyright');
$json = file_get_contents($this->styles_path . $dir . '/composer.json');
$style_data = \phpbb\json\sanitizer::decode($json);
$cfg = parse_cfg_file($this->styles_path . $dir . '/style.cfg');
// Check if it is a valid file
foreach ($required as $key)
if (!is_array($style_data) || !isset($style_data['type']) || $style_data['type'] !== 'phpbb-style')
{
if (!isset($cfg[$key]))
{
return false;
}
throw new \DomainException('NO_VALID_STYLE');
}
if (!isset($style_data['extra']))
{
$style_data['extra'] = array();
}
// Check data
if (!isset($cfg['parent']) || !is_string($cfg['parent']) || $cfg['parent'] == $cfg['name'])
if (!isset($style_data['extra']['parent-style']) || !is_string($style_data['extra']['parent-style']) || $style_data['extra']['parent-style'] === $style_data['name'])
{
$cfg['parent'] = '';
$style_data['extra']['parent-style'] = '';
}
if (!isset($cfg['template_bitfield']))
if (!isset($style_data['extra']['template-bitfield']))
{
$cfg['template_bitfield'] = $this->default_bitfield();
$style_data['extra']['template-bitfield'] = $this->default_bitfield();
}
return $cfg;
return $style_data;
}
/**
@ -1271,7 +1316,7 @@ class acp_styles
if ($conflict !== false)
{
return sprintf($this->user->lang['STYLE_UNINSTALL_DEPENDENT'], $style['style_name']);
return $this->language->lang('STYLE_UNINSTALL_DEPENDENT', $style['style_name']);
}
// Change default style for users
@ -1360,7 +1405,7 @@ class acp_styles
if ($error && !count($items))
{
trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING);
trigger_error($this->language->lang('NO_MATCHING_STYLES_FOUND') . adm_back_link($this->u_action), E_USER_WARNING);
}
return $items;

View file

@ -2668,63 +2668,6 @@ function build_hidden_fields($field_ary, $specialchar = false, $stripslashes = f
return $s_hidden_fields;
}
/**
* Parse cfg file
*/
function parse_cfg_file($filename, $lines = false)
{
$parsed_items = array();
if ($lines === false)
{
$lines = file($filename);
}
foreach ($lines as $line)
{
$line = trim($line);
if (!$line || $line[0] == '#' || ($delim_pos = strpos($line, '=')) === false)
{
continue;
}
// Determine first occurrence, since in values the equal sign is allowed
$key = htmlspecialchars(strtolower(trim(substr($line, 0, $delim_pos))), ENT_COMPAT);
$value = trim(substr($line, $delim_pos + 1));
if (in_array($value, array('off', 'false', '0')))
{
$value = false;
}
else if (in_array($value, array('on', 'true', '1')))
{
$value = true;
}
else if (!trim($value))
{
$value = '';
}
else if (($value[0] == "'" && $value[strlen($value) - 1] == "'") || ($value[0] == '"' && $value[strlen($value) - 1] == '"'))
{
$value = htmlspecialchars(substr($value, 1, strlen($value)-2), ENT_COMPAT);
}
else
{
$value = htmlspecialchars($value, ENT_COMPAT);
}
$parsed_items[$key] = $value;
}
if (isset($parsed_items['parent']) && isset($parsed_items['name']) && $parsed_items['parent'] == $parsed_items['name'])
{
unset($parsed_items['parent']);
}
return $parsed_items;
}
/**
* Return a nicely formatted backtrace.
*

View file

@ -881,3 +881,65 @@ function phpbb_check_and_display_sql_report(\phpbb\request\request_interface $re
$controller_helper->display_sql_report();
}
/**
* Parse cfg file
* @param string $filename
* @param bool|array $lines
* @return array
*
* @deprecated 4.0.0-a1 (To be removed: 5.0.0)
*/
function parse_cfg_file($filename, $lines = false)
{
$parsed_items = array();
if ($lines === false)
{
$lines = file($filename);
}
foreach ($lines as $line)
{
$line = trim($line);
if (!$line || $line[0] == '#' || ($delim_pos = strpos($line, '=')) === false)
{
continue;
}
// Determine first occurrence, since in values the equal sign is allowed
$key = htmlspecialchars(strtolower(trim(substr($line, 0, $delim_pos))), ENT_COMPAT);
$value = trim(substr($line, $delim_pos + 1));
if (in_array($value, array('off', 'false', '0')))
{
$value = false;
}
else if (in_array($value, array('on', 'true', '1')))
{
$value = true;
}
else if (!trim($value))
{
$value = '';
}
else if (($value[0] == "'" && $value[strlen($value) - 1] == "'") || ($value[0] == '"' && $value[strlen($value) - 1] == '"'))
{
$value = htmlspecialchars(substr($value, 1, strlen($value)-2), ENT_COMPAT);
}
else
{
$value = htmlspecialchars($value, ENT_COMPAT);
}
$parsed_items[$key] = $value;
}
if (isset($parsed_items['parent']) && isset($parsed_items['name']) && $parsed_items['parent'] == $parsed_items['name'])
{
unset($parsed_items['parent']);
}
return $parsed_items;
}

View file

@ -60,6 +60,7 @@ $lang = array_merge($lang, array(
'LANG_ENGLISH_NAME' => 'English name',
'LANG_ISO_CODE' => 'ISO code',
'LANG_LOCAL_NAME' => 'Local name',
'LANG_VERSION' => 'Language version',
'MISSING_LANG_FILES' => 'Missing language files',
'MISSING_LANG_VARIABLES' => 'Missing language variables',

View file

@ -54,6 +54,7 @@ $lang = array_merge($lang, [
'INSTALL_STYLES' => 'Install styles',
'INSTALL_STYLES_EXPLAIN' => 'Here you can install new styles.<br>If you cannot find a specific style in list below, check to make sure style is already installed. If it is not installed, check if it was uploaded correctly.',
'INVALID_STYLE_ID' => 'Invalid style ID.',
'INVALID_STYLE_MESSAGE' => 'The directory <strong><i>%1$s</i></strong> does not contain a valid style.',
'NO_MATCHING_STYLES_FOUND' => 'No styles match your query.',
'NO_UNINSTALLED_STYLE' => 'No uninstalled styles detected.',

View file

@ -0,0 +1,27 @@
{
"name": "phpbb/phpbb-language-en",
"description": "phpBB Forum Software default language",
"type": "phpbb-language",
"version": "4.0.0-a1-dev",
"homepage": "https://www.phpbb.com",
"license": "GPL-2.0",
"authors": [
{
"name": "phpBB Limited",
"email": "operations@phpbb.com",
"homepage": "https://www.phpbb.com/go/authors"
}
],
"support": {
"issues": "https://tracker.phpbb.com",
"forum": "https://www.phpbb.com/community/",
"wiki": "https://wiki.phpbb.com",
"irc": "irc://irc.freenode.org/phpbb"
},
"extra": {
"language-iso": "en",
"english-name": "British English",
"local-name": "British English",
"phpbb-version": "4.0.0-a1-dev"
}
}

View file

@ -1,3 +0,0 @@
British English
British English
phpBB Limited

View file

@ -13,6 +13,8 @@
namespace phpbb\cache;
use phpbb\json\sanitizer as json_sanitizer;
/**
* Class for grabbing/handling cached entries
*/
@ -344,7 +346,7 @@ class service
$parsed_array = array();
}
$filename = $this->phpbb_root_path . 'styles/' . $style['style_path'] . '/style.cfg';
$filename = $this->phpbb_root_path . 'styles/' . $style['style_path'] . '/composer.json';
if (!file_exists($filename))
{
@ -354,7 +356,8 @@ class service
if (!isset($parsed_array['filetime']) || (($this->config['load_tplcompile'] && @filemtime($filename) > $parsed_array['filetime'])))
{
// Re-parse cfg file
$parsed_array = parse_cfg_file($filename);
$json = file_get_contents($filename);
$parsed_array = json_sanitizer::decode($json);
$parsed_array['filetime'] = @filemtime($filename);
$this->driver->put('_cfg_' . $style['style_path'], $parsed_array);

View file

@ -13,6 +13,8 @@
namespace phpbb\db\migration\data\v310;
use phpbb\json\sanitizer as json_sanitizer;
class style_update_p1 extends \phpbb\db\migration\migration
{
public function effectively_installed()
@ -69,13 +71,26 @@ class style_update_p1 extends \phpbb\db\migration\migration
$skip_dirs = array('.', '..', 'prosilver');
foreach ($iterator as $fileinfo)
{
if ($fileinfo->isDir() && !in_array($fileinfo->getFilename(), $skip_dirs) && file_exists($fileinfo->getPathname() . '/style.cfg'))
if ($fileinfo->isDir() && !in_array($fileinfo->getFilename(), $skip_dirs))
{
$style_cfg = parse_cfg_file($fileinfo->getPathname() . '/style.cfg');
if (isset($style_cfg['phpbb_version']) && version_compare($style_cfg['phpbb_version'], '3.1.0-dev', '>='))
if (file_exists($fileinfo->getPathname() . '/style.cfg'))
{
// 3.1 style
$available_styles[] = $fileinfo->getFilename();
$style_cfg = parse_cfg_file($fileinfo->getPathname() . '/style.cfg');
if (isset($style_cfg['phpbb_version']) && version_compare($style_cfg['phpbb_version'], '3.1.0-dev', '>='))
{
// 3.1 - 3.3 style
$available_styles[] = $fileinfo->getFilename();
}
}
else if (file_exists($fileinfo->getPathname() . '/composer.json'))
{
$json = file_get_contents($fileinfo->getPathname() . '/composer.json');
$style_data = json_sanitizer::decode($json);
if (isset($style_data['extra']['phpbb-version']) && version_compare($style_data['extra']['phpbb-version'], '4.0.0-dev', '>='))
{
// 4.x style
$available_styles[] = $fileinfo->getFilename();
}
}
}
}

View file

@ -52,8 +52,8 @@ class style_update extends \phpbb\db\migration\migration
// Try to parse config file
$cfg = parse_cfg_file($this->phpbb_root_path . 'styles/prosilver/style.cfg');
// Stop running this if prosilver cfg file can't be read
if (empty($cfg))
// Stop running this if both prosilver cfg file and composer.json file can't be read
if (empty($cfg) && !file_exists($this->phpbb_root_path . 'styles/prosilver/composer.json'))
{
throw new \RuntimeException('No styles available and could not fall back to prosilver.');
}
@ -123,7 +123,7 @@ class style_update extends \phpbb\db\migration\migration
continue;
}
if (file_exists("{$dir}/style.cfg"))
if (file_exists("{$dir}/composer.json") || file_exists("{$dir}/style.cfg"))
{
$styles[] = $file;
}

View file

@ -0,0 +1,59 @@
<?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.
*
*/
declare(strict_types=1);
namespace phpbb\json;
use phpbb\request\type_cast_helper;
/**
* JSON sanitizer class
*/
class sanitizer
{
/**
* Sanitize json data
*
* @param array $data Data to sanitize
*
* @return array Sanitized data
*/
static public function sanitize(array $data) : array
{
if (!empty($data))
{
$json_sanitizer = function (&$value)
{
$type_cast_helper = new type_cast_helper();
$type_cast_helper->set_var($value, $value, gettype($value), true);
};
array_walk_recursive($data, $json_sanitizer);
}
return $data;
}
/**
* Decode and sanitize json data
*
* @param string $json JSON data string
*
* @return array Data array
*/
static public function decode(string $json) : array
{
$data = json_decode($json, true);
return !empty($data) ? self::sanitize($data) : [];
}
}

View file

@ -13,6 +13,8 @@
namespace phpbb\language;
use DomainException;
use phpbb\json\sanitizer as json_sanitizer;
use Symfony\Component\Finder\Finder;
/**
@ -28,9 +30,9 @@ class language_file_helper
/**
* Constructor
*
* @param string $phpbb_root_path Path to phpBB's root
* @param string $phpbb_root_path Path to phpBB's root
*/
public function __construct($phpbb_root_path)
public function __construct(string $phpbb_root_path)
{
$this->phpbb_root_path = $phpbb_root_path;
}
@ -39,13 +41,16 @@ class language_file_helper
* Returns available languages
*
* @return array
*
* @throws DomainException When one of the languages in language directory
* could not be loaded or have invalid composer.json data
*/
public function get_available_languages()
public function get_available_languages() : array
{
// Find available language packages
$finder = new Finder();
$finder->files()
->name('iso.txt')
->name('composer.json')
->depth('== 1')
->followLinks()
->in($this->phpbb_root_path . 'language');
@ -53,20 +58,63 @@ class language_file_helper
$available_languages = array();
foreach ($finder as $file)
{
$path = $file->getRelativePath();
$info = explode("\n", $file->getContents());
$json = $file->getContents();
$data = json_sanitizer::decode($json);
$available_languages[] = array(
// Get the name of the directory containing iso.txt
'iso' => $path,
// Recover data from file
'name' => trim($info[0]),
'local_name' => trim($info[1]),
'author' => trim($info[2])
);
$available_languages[] = $this->get_language_data_from_json($data);
}
return $available_languages;
}
/**
* Collect some data from the composer.json file
*
* @param string $path
* @return array
*
* @throws DomainException When unable to language data from composer.json
*/
public function get_language_data_from_composer_file(string $path) : array
{
$json_data = file_get_contents($path);
return $this->get_language_data_from_json(json_sanitizer::decode($json_data));
}
/**
* Collect some data from the composer.json data
*
* @param array $data
* @return array
*
* @throws DomainException When composer.json data is invalid for language files
*/
protected function get_language_data_from_json(array $data) : array
{
if (!isset($data['extra']['language-iso']) || !isset($data['extra']['english-name']) || !isset($data['extra']['local-name']))
{
throw new DomainException('INVALID_LANGUAGE_PACK');
}
$authors = [];
if (isset($data['authors']))
{
foreach ($data['authors'] as $author)
{
if (isset($author['name']) && $author['name'] !== '')
{
$authors[] = $author['name'];
}
}
}
return [
'iso' => $data['extra']['language-iso'],
'name' => $data['extra']['english-name'],
'local_name' => $data['extra']['local-name'],
'author' => implode(', ', $authors),
'version' => $data['version'],
'phpbb_version' => $data['extra']['phpbb-version'],
];
}
}

View file

@ -14,6 +14,7 @@
namespace phpbb;
use phpbb\exception\version_check_exception;
use phpbb\json\sanitizer as json_sanitizer;
/**
* Class to handle version checking and comparison
@ -389,17 +390,8 @@ class version_helper
throw new version_check_exception($error_string);
}
$info = json_decode($info, true);
// Sanitize any data we retrieve from a server
if (!empty($info))
{
$json_sanitizer = function (&$value, $key) {
$type_cast_helper = new \phpbb\request\type_cast_helper();
$type_cast_helper->set_var($value, $value, gettype($value), true);
};
array_walk_recursive($info, $json_sanitizer);
}
$info = json_sanitizer::decode($info);
if (empty($info['stable']) && empty($info['unstable']))
{

View file

@ -0,0 +1,26 @@
{
"name": "phpbb/phpbb-style-prosilver",
"description": "phpBB Forum Software default style",
"type": "phpbb-style",
"version": "4.0.0-a1-dev",
"homepage": "https://www.phpbb.com",
"license": "GPL-2.0",
"authors": [
{
"name": "phpBB Limited",
"email": "operations@phpbb.com",
"homepage": "https://www.phpbb.com/go/authors"
}
],
"support": {
"issues": "https://tracker.phpbb.com",
"forum": "https://www.phpbb.com/community/",
"wiki": "https://wiki.phpbb.com",
"irc": "irc://irc.freenode.org/phpbb"
},
"extra": {
"display-name": "prosilver",
"phpbb-version": "4.0.0-a1-dev",
"parent-style": ""
}
}

View file

@ -1,32 +0,0 @@
#
# phpBB Style Configuration File
#
# This file is part of the phpBB Forum Software package.
#
# @copyright (c) phpBB Limited <https://www.phpbb.com>
# @license GNU General Public License, version 2 (GPL-2.0)
#
# For full copyright and license information, please see
# the docs/CREDITS.txt file.
#
# At the left is the name, please do not change this
# At the right the value is entered
#
# Values get trimmed, if you want to add a space in front or at the end of
# the value, then enclose the value with single or double quotes.
# Single and double quotes do not need to be escaped.
#
#
# General Information about this style
name = prosilver
copyright = © phpBB Limited, 2007
style_version = 4.0.0-a1-dev
phpbb_version = 4.0.0-a1-dev
# Defining a different template bitfield
# template_bitfield = //g=
# Parent style
# Set value to empty or to this style's name if this style does not have a parent style
parent = prosilver

View file

@ -0,0 +1,35 @@
<?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.
*
*/
use phpbb\json\sanitizer as json_sanitizer;
class phpbb_json_sanitizer_test extends phpbb_test_case
{
public function data_decode()
{
return [
[false, []],
['', []],
['{ "name": "phpbb/phpbb-style-prosilver"}', ['name' => 'phpbb/phpbb-style-prosilver']],
['{ "name":[[ "phpbb/phpbb-style-prosilver"}', []],
];
}
/**
* @dataProvider data_decode
*/
public function test_decode_data($input, $output)
{
$this->assertEquals($output, json_sanitizer::decode($input));
}
}