plugins/admin/LangManager.php
author Dan Fuhry <dan@enanocms.org>
Wed, 29 Dec 2010 13:25:32 -0500
changeset 1332 12286b3ee214
parent 1227 bdac73ed481e
child 1377 fa2b0825bbc5
permissions -rw-r--r--
Added some more hooks to the page editing pipeline. It should now be possible to add controls to the page editor, send the data from them out to the server, and process them on the server side.

<?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>';
}