Namespace_Default: added a workaround for an inconsistency in SQL. Basically, if you join the same table multiple times under multiple aliases, COUNT() always uses the first instance. Was affecting the comment counter in the "discussion" button.
<?php
/*
* Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
* Copyright (C) 2006-2009 Dan Fuhry
*
* This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
*/
function page_Admin_LangManager()
{
global $db, $session, $paths, $template, $plugins; // Common objects
global $lang;
global $cache;
if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
{
$login_link = makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true);
echo '<h3>' . $lang->get('adm_err_not_auth_title') . '</h3>';
echo '<p>' . $lang->get('adm_err_not_auth_body', array( 'login_link' => $login_link )) . '</p>';
return;
}
if ( isset($_POST['action']) )
{
$action =& $_POST['action'];
// Parse parameters
if ( strpos($action, ';') )
{
// Parameter section
$parms = substr($action, strpos($action, ';') + 1);
// Action name section
$action = substr($action, 0, strpos($action, ';'));
// Match all parameters
preg_match_all('/([a-z0-9_]+)=(.+?)(;|$)/', $parms, $matches);
$parms = array();
// For each full parameter, assign $parms an associative value
foreach ( $matches[0] as $i => $_ )
{
$parm = $matches[2][$i];
// Is this parameter in the form of an integer?
// (designed to ease validation later)
if ( ctype_digit($parm) )
// Yes, run intval(), this enabling is_int()-ish checks
$parm = intval($parm);
$parms[$matches[1][$i]] = $parm;
}
}
switch ( $action )
{
case 'install_language':
if ( defined('ENANO_DEMO_MODE') )
{
echo '<div class="error-box">' . $lang->get('acplm_err_lang_install_demo') . '</div>';
break;
}
$lang_list = list_available_languages();
// Verify that we have this language's metadata
if ( isset($lang_list[@$parms['iso639']]) )
{
// From here it's all downhill :-)
$lang_code =& $parms['iso639'];
$lang_data =& $lang_list[$lang_code];
$result = install_language($lang_code, $lang_data['name_eng'], $lang_data['name']);
if ( $result )
{
// Language installed. Import the language files.
$lang_local = new Language($lang_code);
if ( file_exists(ENANO_ROOT . "/language/{$lang_data['dir']}/backup.json") )
{
$lang_local->import(ENANO_ROOT . "/language/{$lang_data['dir']}/backup.json");
}
else
{
foreach ( array('core', 'admin', 'tools', 'user') as $file )
{
$lang_local->import(ENANO_ROOT . "/language/{$lang_data['dir']}/$file.json");
}
}
unset($lang_local);
echo '<div class="info-box">' . $lang->get('acplm_msg_lang_install_success', array('lang_name' => htmlspecialchars($lang_data['name_eng']))) . '</div>';
}
}
break;
case 'modify_language':
$lang_id =& $parms['lang_id'];
if ( !is_int($lang_id) )
{
echo 'Hacking attempt';
break;
}
if ( isset($parms['finish']) && !empty($_POST['lang_name_native']) && !empty($_POST['lang_name_english']) && !defined('ENANO_DEMO_MODE') )
{
// We just did validation above, it's safe to save.
$name_native = $db->escape($_POST['lang_name_native']);
$name_english = $db->escape($_POST['lang_name_english']);
$q = $db->sql_query('UPDATE ' . table_prefix . "language SET lang_name_native = '$name_native', lang_name_default = '$name_english' WHERE lang_id = $lang_id;");
if ( !$q )
$db->_die();
echo '<div class="info-box">' . $lang->get('acplm_msg_basic_save_success') . '</div>';
}
else if ( isset($parms['finish']) && defined('ENANO_DEMO_MODE') )
{
echo '<div class="error-box">' . $lang->get('acplm_err_lang_install_demo') . '</div>';
}
// Select language data
$q = $db->sql_query('SELECT lang_name_native, lang_name_default, lang_code FROM ' . table_prefix . "language WHERE lang_id = $lang_id;");
if ( !$q )
$db->_die();
list($name_native, $name_english, $lang_code) = $db->fetchrow_num();
// Output properties table
echo '<h3>' . $lang->get('acplm_heading_modify') . '</h3>';
acp_start_form();
?>
<div class="tblholder">
<table border="0" cellspacing="1" cellpadding="4">
<tr>
<th colspan="2">
<?php
echo $lang->get('acplm_th_lang_basic');
?>
</th>
</tr>
<tr>
<td class="row2" style="width: 50%;">
<?php
echo str_replace('"', '', $lang->get('acplm_field_lang_name_native'));
?>
</td>
<td class="row1">
<input type="text" name="lang_name_native" value="<?php echo htmlspecialchars($name_native); ?>" />
</td>
</tr>
<tr>
<td class="row2">
<?php
echo $lang->get('acplm_field_lang_name_english');
?>
</td>
<td class="row1">
<input type="text" name="lang_name_english" value="<?php echo htmlspecialchars($name_english); ?>" />
</td>
</tr>
<tr>
<td class="row2">
<?php
echo $lang->get('acplm_field_lang_code') . '<br />'
. '<small>' . $lang->get('acplm_field_lang_code_hint') . '</small>';
?>
</td>
<td class="row1">
<?php
echo $lang_code;
?>
</td>
</tr>
<tr>
<th class="subhead" colspan="2">
<button name="action" value="modify_language;finish=1;lang_id=<?php echo $lang_id; ?>"><?php echo $lang->get('etc_save_changes'); ?></button>
</th>
</tr>
</table>
</div>
</form>
<?php
acp_start_form();
?>
<h3><?php echo $lang->get('acplm_heading_edit_strings_portal'); ?></h3>
<p><?php echo $lang->get('acplm_msg_edit_strings_portal_intro'); ?></p>
<p>
<?php
// Grab a Language object
if ( $lang->lang_id == $lang_id )
{
$lang_local =& $lang;
}
else
{
$lang_local = new Language($lang_id);
$lang_local->fetch();
}
$categories_loc = array();
// Using the & here ensures that a reference is created, thus avoiding wasting memory
foreach ( $lang_local->strings as $cat => &$_ )
{
unset($_);
$categories_loc[$cat] = htmlspecialchars($lang->get("meta_$cat"));
}
asort($categories_loc);
echo '<select name="cat_id">';
foreach ( $categories_loc as $cat_id => $cat_name)
{
echo "<option value=\"$cat_id\">$cat_name</option>";
}
echo '</select>';
?>
<button name="action" value="edit_strings;lang_id=<?php echo $lang_id; ?>">
<?php echo $lang->get('acplm_btn_edit_strings_portal'); ?>
</button>
</p>
<h3><?php echo $lang->get('acplm_heading_reimport_portal'); ?></h3>
<p><?php echo $lang->get('acplm_msg_reimport_portal_intro'); ?></p>
<p>
<button name="action" value="reimport;iso639=<?php echo $lang_code; ?>;lang_id=<?php echo $lang_id; ?>">
<?php echo $lang->get('acplm_btn_reimport'); ?>
</button>
</p>
</form>
<?php
echo '<h3>' . $lang->get('acplm_heading_backup') . '</h3>';
echo '<p>' . $lang->get('acplm_backup_intro') . '</p>';
echo '<form action="' . makeUrlNS('Admin', 'LangManager') . '" method="post">';
echo '<button name="action" value="backup_language;lang_id=' . $lang_id . '">' . $lang->get('acplm_btn_create_backup') . '</button>';
echo '</form>';
return true;
case 'edit_strings':
$cat_id = @$_POST['cat_id'];
if ( !preg_match('/^[a-z0-9]+$/', $cat_id) || !is_int(@$parms['lang_id']) )
break;
$lang_id =& $parms['lang_id'];
if ( isset($parms['save']) && !defined('ENANO_DEMO_MODE') )
{
// Grab a Language object
if ( $lang->lang_id == $lang_id )
{
$lang_local =& $lang;
}
else
{
$lang_local = new Language($lang_id);
}
// Main save loop
// Trying to minimize queries as much as possible here, but you know how that goes.
$count_upd = 0;
foreach ( $_POST['string'] as $string_id => $user_content )
{
$curr_content = $lang_local->get_uncensored("{$cat_id}_{$string_id}");
if ( $curr_content != $user_content )
{
$count_upd++;
$user_content = $db->escape($user_content);
$string_id = $db->escape($string_id);
$q = $db->sql_query('UPDATE ' . table_prefix . "language_strings SET string_content = '$user_content' WHERE lang_id = $lang_id AND string_category = '$cat_id' AND string_name = '$string_id';");
if ( !$q )
$db->_die();
}
}
if ( $count_upd > 0 )
{
// Update the cache
$lang_local->regen_caches();
// Update modification time
$q = $db->sql_query('UPDATE ' . table_prefix . "language SET last_changed = " . time() . " WHERE lang_id = $lang_id;");
if ( !$q )
$db->_die();
}
echo '<div class="info-box">' . $lang->get('acplm_msg_string_save_success') . '</div>';
}
else if ( isset($parms['save']) && defined('ENANO_DEMO_MODE') )
{
echo '<div class="error-box">' . $lang->get('acplm_err_lang_install_demo') . '</div>';
}
acp_start_form();
$cat_name = $lang->get("meta_$cat_id");
echo '<h3>' . $lang->get('acplm_editor_heading', array('cat_name' => $cat_name)) . '</h3>';
// Fetch all strings
// This is more efficient than iterating through $lang->strings, I think.
$q = $db->sql_query('SELECT string_id, string_name, string_content FROM ' . table_prefix . "language_strings WHERE string_category = '$cat_id' AND lang_id = $lang_id;");
if ( !$q )
$db->_die();
?>
<div class="tblholder">
<table border="0" cellspacing="1" cellpadding="4">
<tr>
<th style="width: 3%;"><?php echo $lang->get('acplm_editor_col_string_name'); ?></th>
<th><?php echo $lang->get('acplm_editor_col_string_content'); ?></th>
</tr>
<?php
while ( $row = $db->fetchrow_num() )
{
list($string_id, $string_name, $string_content) = $row;
unset($row);
echo '<tr>';
if ( strpos($string_content, "\n") )
{
$editor = '<textarea rows="' . get_line_count($string_content) . '" cols="50" style="width: 99%;" ';
$editor .= 'name="string[' . htmlspecialchars($string_name) . ']" ';
$editor .= '>' . htmlspecialchars($string_content);
$editor .= '</textarea>';
}
else
{
$editor = '<input type="text" size="50" style="width: 99%;" ';
$editor .= 'name="string[' . htmlspecialchars($string_name) . ']" ';
$editor .= 'value="' . htmlspecialchars($string_content) . '" ';
$editor .= '/>';
}
echo '<td class="row2">' . htmlspecialchars($string_name) . '</td>';
echo '<td class="row1">' . $editor . '</td>';
echo '</tr>';
echo "\n";
}
echo '<tr>
<th class="subhead" colspan="2">';
echo '<input type="hidden" name="cat_id" value="' . $cat_id . '" />';
// Button: save
echo '<button name="action" value="edit_strings;lang_id=' . $lang_id . ';save=1" style="font-weight: bold;">' . $lang->get('etc_save_changes') . '</button> ';
// Button: revert
echo '<button name="action" value="edit_strings;lang_id=' . $lang_id . '" style="font-weight: normal;">' . $lang->get('acplm_editor_btn_revert') . '</button> ';
// Button: cancel
echo '<button name="action" value="modify_language;lang_id=' . $lang_id . '" style="font-weight: normal;">' . $lang->get('acplm_editor_btn_cancel') . '</button>';
echo ' </th>
</tr>';
?>
</table>
</div>
<?php
echo '</form>';
return true;
case 'reimport':
if ( !isset($parms['iso639']) || !is_int(@$parms['lang_id']) )
break;
if ( defined('ENANO_DEMO_MODE') )
{
echo '<div class="error-box">' . $lang->get('acplm_err_lang_install_demo') . '</div>';
break;
}
$lang_code =& $parms['iso639'];
$lang_id =& $parms['lang_id'];
$lang_list = list_available_languages();
if ( !isset($lang_list[$lang_code]) )
break;
// Grab a Language object
if ( $lang->lang_id == $lang_id )
{
$lang_local =& $lang;
}
else
{
$lang_local = new Language($lang_id);
}
$lang_data =& $lang_list[$lang_code];
// This is the big re-import loop
if ( file_exists(ENANO_ROOT . "/language/{$lang_data['dir']}/backup.json") )
{
$lang_local->import(ENANO_ROOT . "/language/{$lang_data['dir']}/backup.json");
}
else
{
foreach ( array('core', 'admin', 'tools', 'user') as $file )
{
$lang_local->import(ENANO_ROOT . "/language/{$lang_data['dir']}/$file.json");
}
}
echo '<div class="info-box">' . $lang->get('acplm_msg_reimport_success') . '</div>';
break;
case 'backup_language':
if ( !is_int(@$parms['lang_id']) )
break;
$lang_id =& $parms['lang_id'];
// Grab a Language object
if ( $lang->lang_id == $lang_id )
{
$lang_local =& $lang;
}
else
{
$lang_local = new Language($lang_id);
}
$filename = 'enano_lang_' . $lang_local->lang_code . '_' . enano_date('ymd') . '.json';
// Free as much memory as possible
$db->close();
unset($GLOBALS['session'], $GLOBALS['paths'], $GLOBALS['template'], $GLOBALS['plugins']);
// HTTP headers
header('Content-type: application/json');
header('Content-disposition: attachment; filename=' . $filename);
// Export to JSON
$lang_struct = array(
'categories' => array_keys($lang_local->strings),
'strings' => $lang_local->strings
);
$lang_struct = enano_json_encode($lang_struct);
header('Content-length: ' . strlen($lang_struct));
echo $lang_struct;
exit;
case 'uninstall_language':
if ( !is_int(@$parms['lang_id']) )
break;
if ( defined('ENANO_DEMO_MODE') )
{
echo '<div class="error-box">' . $lang->get('acplm_err_lang_install_demo') . '</div>';
break;
}
$lang_id =& $parms['lang_id'];
if ( isset($parms['confirm']) )
{
$lang_default = intval(getConfig('default_language'));
if ( $lang_default == $lang_id )
{
echo '<div class="error-box">' . $lang->get('acplm_err_cant_uninstall_default') . '</div>';
break;
}
if ( $lang_id == $lang->lang_id )
{
// Unload the current language since it's about to be uninstalled
unset($lang, $GLOBALS['lang']);
$GLOBALS['lang'] = new Language($lang_default);
global $lang;
}
// We're clear
// Remove cache files
$cache_file = ENANO_ROOT . "/cache/lang_{$lang_id}.php";
if ( file_exists($cache_file) )
@unlink($cache_file);
$cache->purge("lang_{$lang_id}");
// Remove strings
$q = $db->sql_query('DELETE FROM ' . table_prefix . "language_strings WHERE lang_id = $lang_id;");
if ( !$q )
$db->_die();
// Delete the language
$q = $db->sql_query('DELETE FROM ' . table_prefix . "language WHERE lang_id = $lang_id;");
if ( !$q )
$db->_die();
echo '<div class="info-box">' . $lang->get('acplm_msg_uninstall_success') . '</div>';
break;
}
acp_start_form();
echo '<h3>' . $lang->get('acplm_uninstall_confirm_title') . '</h3>';
echo '<p>' . $lang->get('acplm_uninstall_confirm_body') . '</p>';
echo '<p><button name="action" style="font-weight: bold;" value="uninstall_language;lang_id=' . $lang_id . ';confirm=1">' . $lang->get('acplm_btn_uninstall_confirm') . '</button> ';
echo '<button name="action" value="home">' . $lang->get('acplm_btn_uninstall_cancel') . '</button></p>';
echo '</form>';
return true;
}
}
acp_start_form();
// Select current languages
$q = $db->sql_query('SELECT lang_code, lang_name_native, lang_name_default, lang_id FROM ' . table_prefix . "language ORDER BY lang_id ASC;");
if ( !$q )
$db->_die();
// Language properties/edit/delete portal table
echo '<h3>' . $lang->get('acplm_heading_editor_portal') . '</h3>';
echo '<div class="tblholder">';
echo '<table border="0" cellspacing="1" cellpadding="4">';
echo '<tr>
<th>' . $lang->get('acplm_col_lang_id') . '</th>
<th>' . $lang->get('acplm_col_lang_code') . '</th>
<th>' . $lang->get('acplm_col_lang_name') . '</th>
<th>' . $lang->get('acplm_col_lang_name_eng') . '</th>
<th></th>
</tr>';
$cls = 'row2';
$btn_edit = $lang->get('acplm_portal_btn_edit');
$btn_unin = $lang->get('acplm_portal_btn_unin');
while ( $row = $db->fetchrow($q) )
{
$cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
echo '<tr>';
$lang_code = htmlspecialchars($row['lang_code']);
$lang_name_native = htmlspecialchars($row['lang_name_native']);
$lang_name_english = htmlspecialchars($row['lang_name_default']);
echo "<td class=\"$cls\" style=\"text-align: center;\">{$row['lang_id']}</td>";
echo "<td class=\"$cls\" style=\"text-align: center;\">{$lang_code}</td>";
echo "<td class=\"$cls\" style=\"text-align: center;\">{$lang_name_native}</td>";
echo "<td class=\"$cls\" style=\"text-align: center;\">{$lang_name_english}</td>";
echo "<td class=\"$cls\" style=\"text-align: center;\"><button name=\"action\" value=\"modify_language;lang_id={$row['lang_id']}\">$btn_edit</button> <button name=\"action\" value=\"uninstall_language;lang_id={$row['lang_id']}\">$btn_unin</button></td>";
echo '</tr>';
}
echo '</table></div>';
// Reset the result pointer to zero so we can fetch that list of languages again
if ( !$db->sql_data_seek(0, $q) )
{
$db->_die('LangManager doing seek back to zero for installation blacklist');
}
// $lang_list is fetched by the posthandler sometimes
if ( !isset($lang_list) )
{
// Build a list of languages in the languages/ directory, then
// eliminate the ones that are already installed.
$lang_list = list_available_languages();
}
while ( $row = $db->fetchrow($q) )
{
$lang_code =& $row['lang_code'];
if ( isset($lang_list[$lang_code]) )
{
unset($lang_list[$lang_code]);
unset($lang_list[$lang_code]); // PHP <5.1.4 Zend bug
}
}
if ( count($lang_list) > 0 )
{
echo '<h3>' . $lang->get('acplm_heading_install') . '</h3>';
echo '<div class="tblholder">
<table border="0" cellspacing="1" cellpadding="4">
<tr>
<th>' . $lang->get('acplm_col_lang_code') . '</th>
<th>' . $lang->get('acplm_col_lang_name') . '</th>
<th>' . $lang->get('acplm_col_lang_name_eng') . '</th>
<th></th>
</tr>';
$cls = 'row2';
foreach ( $lang_list as $lang_code => $lang_data )
{
$cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
echo '<tr>';
$lang_code = htmlspecialchars($lang_code);
$lang_data['name'] = htmlspecialchars($lang_data['name']);
$lang_data['name_eng'] = htmlspecialchars($lang_data['name_eng']);
echo "<td class=\"$cls\" style=\"text-align: center;\">$lang_code</td>";
echo "<td class=\"$cls\" style=\"text-align: center;\">{$lang_data['name']}</td>";
echo "<td class=\"$cls\" style=\"text-align: center;\">{$lang_data['name_eng']}</td>";
echo "<td class=\"$cls\" style=\"text-align: center;\"><button name=\"action\" value=\"install_language;iso639=$lang_code\">" . $lang->get('acplm_btn_install_language') . "</button></td>";
echo '</tr>';
}
echo ' </tr>
</table>
</div>';
}
echo '</form>';
}