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; $action = (empty($action)) ? request_var('action', '') : $action; $form_name = 'acp_lang'; 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); 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); // 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)) { trigger_error($user->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); } $sql = 'SELECT * FROM ' . LANG_TABLE . " WHERE lang_id = $lang_id"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); $sql_ary = array( 'lang_english_name' => request_var('lang_english_name', $row['lang_english_name']), 'lang_local_name' => utf8_normalize_nfc(request_var('lang_local_name', $row['lang_local_name'], true)), 'lang_author' => utf8_normalize_nfc(request_var('lang_author', $row['lang_author'], true)), ); $db->sql_query('UPDATE ' . LANG_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE lang_id = ' . $lang_id); add_log('admin', 'LOG_LANGUAGE_PACK_UPDATED', $sql_ary['lang_english_name']); 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) { trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } $this->page_title = 'LANGUAGE_PACK_DETAILS'; $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); $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_AUTHOR' => $lang_entries['lang_author'], 'ALLOW_UPLOAD' => sizeof($methods) ) ); // If current lang is different from the default lang, then first try to grab missing/additional vars if ($lang_iso != $config['default_lang']) { $is_missing_var = false; foreach ($this->main_files as $file) { 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); } } // Now go through acp/mods directories foreach ($acp_files as $file) { 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); if (sizeof($missing_vars['acp/' . $file])) { $is_missing_var = true; } } else { $missing_files[] = $this->get_filename($lang_iso, 'acp', $file); } } 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])) { $is_missing_var = true; } } 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))) { $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)) ); } } } // 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': 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); if ($row['lang_iso'] == $config['default_lang']) { trigger_error($user->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); $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); // 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); $sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . ' WHERE lang_id = ' . $lang_id; $db->sql_query($sql); add_log('admin', 'LOG_LANGUAGE_PACK_DELETED', $row['lang_english_name']); trigger_error(sprintf($user->lang['LANGUAGE_PACK_DELETED'], $row['lang_english_name']) . adm_back_link($this->u_action)); } else { $s_hidden_fields = array( 'i' => $id, 'mode' => $mode, 'action' => $action, 'id' => $lang_id, ); confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); } break; case 'install': $lang_iso = request_var('iso', ''); $lang_iso = basename($lang_iso); if (!$lang_iso || !file_exists("{$phpbb_root_path}language/$lang_iso/iso.txt")) { trigger_error($user->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])), 'local_name'=> trim(htmlspecialchars($file[1], ENT_COMPAT, 'UTF-8')), 'author' => trim(htmlspecialchars($file[2], ENT_COMPAT, 'UTF-8')) ); unset($file); $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); if ($row) { trigger_error($user->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); } // Add language pack $sql_ary = array( 'lang_iso' => $lang_pack['iso'], 'lang_dir' => $lang_pack['iso'], 'lang_english_name' => $lang_pack['name'], 'lang_local_name' => $lang_pack['local_name'], 'lang_author' => $lang_pack['author'] ); $db->sql_query('INSERT INTO ' . LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); $lang_id = $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); // We want to notify the admin that custom profile fields need to be updated for the new language. $notify_cpf_update = false; // From the mysql documentation: // Prior to MySQL 4.0.14, the target table of the INSERT statement cannot appear in the FROM clause of the SELECT part of the query. This limitation is lifted in 4.0.14. // Due to this we stay on the safe side if we do the insertion "the manual way" $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); while ($row = $db->sql_fetchrow($result)) { $row['lang_id'] = $lang_id; $db->sql_query('INSERT INTO ' . PROFILE_LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $row)); $notify_cpf_update = true; } $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); while ($row = $db->sql_fetchrow($result)) { $row['lang_id'] = $lang_id; $db->sql_query('INSERT INTO ' . PROFILE_FIELDS_LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $row)); $notify_cpf_update = true; } $db->sql_freeresult($result); add_log('admin', 'LOG_LANGUAGE_PACK_INSTALLED', $lang_pack['name']); $message = sprintf($user->lang['LANGUAGE_PACK_INSTALLED'], $lang_pack['name']); $message .= ($notify_cpf_update) ? '

' . $user->lang['LANGUAGE_PACK_CPF_UPDATE'] : ''; 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 FROM ' . USERS_TABLE . ' GROUP BY user_lang'; $result = $db->sql_query($sql); $lang_count = array(); while ($row = $db->sql_fetchrow($result)) { $lang_count[$row['user_lang']] = $row['lang_count']; } $db->sql_freeresult($result); $sql = 'SELECT * FROM ' . LANG_TABLE . ' ORDER BY lang_english_name'; $result = $db->sql_query($sql); $installed = array(); while ($row = $db->sql_fetchrow($result)) { $installed[] = $row['lang_iso']; $tagstyle = ($row['lang_iso'] == $config['default_lang']) ? '*' : ''; $template->assign_block_vars('lang', array( 'U_DETAILS' => $this->u_action . "&action=details&id={$row['lang_id']}", 'U_DOWNLOAD' => $this->u_action . "&action=download&id={$row['lang_id']}", 'U_DELETE' => $this->u_action . "&action=delete&id={$row['lang_id']}", 'ENGLISH_NAME' => $row['lang_english_name'], 'TAG' => $tagstyle, 'LOCAL_NAME' => $row['lang_local_name'], 'ISO' => $row['lang_iso'], 'USED_BY' => (isset($lang_count[$row['lang_iso']])) ? $lang_count[$row['lang_iso']] : 0, )); } $db->sql_freeresult($result); $new_ary = $iso = array(); $dp = @opendir("{$phpbb_root_path}language"); if ($dp) { while (($file = readdir($dp)) !== false) { if ($file[0] == '.' || !is_dir($phpbb_root_path . 'language/' . $file)) { continue; } if (file_exists("{$phpbb_root_path}language/$file/iso.txt")) { if (!in_array($file, $installed)) { if ($iso = file("{$phpbb_root_path}language/$file/iso.txt")) { if (sizeof($iso) == 3) { $new_ary[$file] = array( 'iso' => $file, 'name' => trim($iso[0]), 'local_name'=> trim($iso[1]), 'author' => trim($iso[2]) ); } } } } } closedir($dp); } unset($installed); if (sizeof($new_ary)) { foreach ($new_ary as $iso => $lang_ary) { $template->assign_block_vars('notinst', array( 'ISO' => htmlspecialchars($lang_ary['iso']), 'LOCAL_NAME' => htmlspecialchars($lang_ary['local_name'], ENT_COMPAT, 'UTF-8'), 'NAME' => htmlspecialchars($lang_ary['name'], ENT_COMPAT, 'UTF-8'), 'U_INSTALL' => $this->u_action . '&action=install&iso=' . urlencode($lang_ary['iso'])) ); } } 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) { global $phpbb_root_path, $phpEx; $return_ary = array(); $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))) { return array(); } include($phpbb_root_path . $this->get_filename($dest_lang, $directory, $file, true)); $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; } }