diff options
Diffstat (limited to 'phpBB/includes')
228 files changed, 19609 insertions, 41143 deletions
diff --git a/phpBB/includes/acm/acm_apc.php b/phpBB/includes/acm/acm_apc.php deleted file mode 100644 index 205353d3a5..0000000000 --- a/phpBB/includes/acm/acm_apc.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php -/** -* -* @package acm -* @version $Id$ -* @copyright (c) 2005, 2009 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -// Include the abstract base -if (!class_exists('acm_memory')) -{ - require("{$phpbb_root_path}includes/acm/acm_memory.$phpEx"); -} - -/** -* ACM for APC -* @package acm -*/ -class acm extends acm_memory -{ - var $extension = 'apc'; - - /** - * Purge cache data - * - * @return null - */ - function purge() - { - apc_clear_cache('user'); - - parent::purge(); - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - return apc_fetch($this->key_prefix . $var); - } - - /** - * Store data in the cache - * - * @access protected - * @param string $var Cache key - * @param mixed $data Data to store - * @param int $ttl Time-to-live of cached data - * @return bool True if the operation succeeded - */ - function _write($var, $data, $ttl = 2592000) - { - return apc_store($this->key_prefix . $var, $data, $ttl); - } - - /** - * Remove an item from the cache - * - * @access protected - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - function _delete($var) - { - return apc_delete($this->key_prefix . $var); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/acm/acm_eaccelerator.php b/phpBB/includes/acm/acm_eaccelerator.php deleted file mode 100644 index ecec3ac9a5..0000000000 --- a/phpBB/includes/acm/acm_eaccelerator.php +++ /dev/null @@ -1,121 +0,0 @@ -<?php -/** -* -* @package acm -* @version $Id$ -* @copyright (c) 2005, 2009 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -// Include the abstract base -if (!class_exists('acm_memory')) -{ - require("{$phpbb_root_path}includes/acm/acm_memory.$phpEx"); -} - -/** -* ACM for eAccelerator -* @package acm -* @todo Missing locks from destroy() talk with David -*/ -class acm extends acm_memory -{ - var $extension = 'eaccelerator'; - var $function = 'eaccelerator_get'; - - var $serialize_header = '#phpbb-serialized#'; - - /** - * Purge cache data - * - * @return null - */ - function purge() - { - foreach (eaccelerator_list_keys() as $var) - { - // @todo Check why the substr() - // @todo Only unset vars matching $this->key_prefix - eaccelerator_rm(substr($var['name'], 1)); - } - - parent::purge(); - } - - /** - * Perform cache garbage collection - * - * @return null - */ - function tidy() - { - eaccelerator_gc(); - - set_config('cache_last_gc', time(), true); - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - $result = eaccelerator_get($this->key_prefix . $var); - - if ($result === null) - { - return false; - } - - // Handle serialized objects - if (is_string($result) && strpos($result, $this->serialize_header . 'O:') === 0) - { - $result = unserialize(substr($result, strlen($this->serialize_header))); - } - - return $result; - } - - /** - * Store data in the cache - * - * @access protected - * @param string $var Cache key - * @param mixed $data Data to store - * @param int $ttl Time-to-live of cached data - * @return bool True if the operation succeeded - */ - function _write($var, $data, $ttl = 2592000) - { - // Serialize objects and make them easy to detect - $data = (is_object($data)) ? $this->serialize_header . serialize($data) : $data; - - return eaccelerator_put($this->key_prefix . $var, $data, $ttl); - } - - /** - * Remove an item from the cache - * - * @access protected - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - function _delete($var) - { - return eaccelerator_rm($this->key_prefix . $var); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/acm/acm_file.php b/phpBB/includes/acm/acm_file.php deleted file mode 100644 index 524a28561e..0000000000 --- a/phpBB/includes/acm/acm_file.php +++ /dev/null @@ -1,732 +0,0 @@ -<?php -/** -* -* @package acm -* @version $Id$ -* @copyright (c) 2005, 2009 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* ACM File Based Caching -* @package acm -*/ -class acm -{ - var $vars = array(); - var $var_expires = array(); - var $is_modified = false; - - var $sql_rowset = array(); - var $sql_row_pointer = array(); - var $cache_dir = ''; - - /** - * Set cache path - */ - function acm() - { - global $phpbb_root_path; - $this->cache_dir = $phpbb_root_path . 'cache/'; - } - - /** - * Load global cache - */ - function load() - { - return $this->_read('data_global'); - } - - /** - * Unload cache object - */ - function unload() - { - $this->save(); - unset($this->vars); - unset($this->var_expires); - unset($this->sql_rowset); - unset($this->sql_row_pointer); - - $this->vars = array(); - $this->var_expires = array(); - $this->sql_rowset = array(); - $this->sql_row_pointer = array(); - } - - /** - * Save modified objects - */ - function save() - { - if (!$this->is_modified) - { - return; - } - - global $phpEx; - - if (!$this->_write('data_global')) - { - if (!function_exists('phpbb_is_writable')) - { - global $phpbb_root_path; - include($phpbb_root_path . 'includes/functions.' . $phpEx); - } - - // Now, this occurred how often? ... phew, just tell the user then... - if (!phpbb_is_writable($this->cache_dir)) - { - // We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload()) - die('Fatal: ' . $this->cache_dir . ' is NOT writable.'); - exit; - } - - die('Fatal: Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx); - exit; - } - - $this->is_modified = false; - } - - /** - * Tidy cache - */ - function tidy() - { - global $phpEx; - - $dir = @opendir($this->cache_dir); - - if (!$dir) - { - return; - } - - $time = time(); - - while (($entry = readdir($dir)) !== false) - { - if (!preg_match('/^(sql_|data_(?!global))/', $entry)) - { - continue; - } - - if (!($handle = @fopen($this->cache_dir . $entry, 'rb'))) - { - continue; - } - - // Skip the PHP header - fgets($handle); - - // Skip expiration - $expires = (int) fgets($handle); - - fclose($handle); - - if ($time >= $expires) - { - $this->remove_file($this->cache_dir . $entry); - } - } - closedir($dir); - - if (file_exists($this->cache_dir . 'data_global.' . $phpEx)) - { - if (!sizeof($this->vars)) - { - $this->load(); - } - - foreach ($this->var_expires as $var_name => $expires) - { - if ($time >= $expires) - { - $this->destroy($var_name); - } - } - } - - set_config('cache_last_gc', time(), true); - } - - /** - * Get saved cache object - */ - function get($var_name) - { - if ($var_name[0] == '_') - { - global $phpEx; - - if (!$this->_exists($var_name)) - { - return false; - } - - return $this->_read('data' . $var_name); - } - else - { - return ($this->_exists($var_name)) ? $this->vars[$var_name] : false; - } - } - - /** - * Put data into cache - */ - function put($var_name, $var, $ttl = 31536000) - { - if ($var_name[0] == '_') - { - $this->_write('data' . $var_name, $var, time() + $ttl); - } - else - { - $this->vars[$var_name] = $var; - $this->var_expires[$var_name] = time() + $ttl; - $this->is_modified = true; - } - } - - /** - * Purge cache data - */ - function purge() - { - // Purge all phpbb cache files - $dir = @opendir($this->cache_dir); - - if (!$dir) - { - return; - } - - while (($entry = readdir($dir)) !== false) - { - if (strpos($entry, 'sql_') !== 0 && strpos($entry, 'data_') !== 0 && strpos($entry, 'ctpl_') !== 0 && strpos($entry, 'tpl_') !== 0) - { - continue; - } - - $this->remove_file($this->cache_dir . $entry); - } - closedir($dir); - - unset($this->vars); - unset($this->var_expires); - unset($this->sql_rowset); - unset($this->sql_row_pointer); - - $this->vars = array(); - $this->var_expires = array(); - $this->sql_rowset = array(); - $this->sql_row_pointer = array(); - - $this->is_modified = false; - } - - /** - * Destroy cache data - */ - function destroy($var_name, $table = '') - { - global $phpEx; - - if ($var_name == 'sql' && !empty($table)) - { - if (!is_array($table)) - { - $table = array($table); - } - - $dir = @opendir($this->cache_dir); - - if (!$dir) - { - return; - } - - while (($entry = readdir($dir)) !== false) - { - if (strpos($entry, 'sql_') !== 0) - { - continue; - } - - if (!($handle = @fopen($this->cache_dir . $entry, 'rb'))) - { - continue; - } - - // Skip the PHP header - fgets($handle); - - // Skip expiration - fgets($handle); - - // Grab the query, remove the LF - $query = substr(fgets($handle), 0, -1); - - fclose($handle); - - foreach ($table as $check_table) - { - // Better catch partial table names than no table names. ;) - if (strpos($query, $check_table) !== false) - { - $this->remove_file($this->cache_dir . $entry); - break; - } - } - } - closedir($dir); - - return; - } - - if (!$this->_exists($var_name)) - { - return; - } - - if ($var_name[0] == '_') - { - $this->remove_file($this->cache_dir . 'data' . $var_name . ".$phpEx", true); - } - else if (isset($this->vars[$var_name])) - { - $this->is_modified = true; - unset($this->vars[$var_name]); - unset($this->var_expires[$var_name]); - - // We save here to let the following cache hits succeed - $this->save(); - } - } - - /** - * Check if a given cache entry exist - */ - function _exists($var_name) - { - if ($var_name[0] == '_') - { - global $phpEx; - return file_exists($this->cache_dir . 'data' . $var_name . ".$phpEx"); - } - else - { - if (!sizeof($this->vars)) - { - $this->load(); - } - - if (!isset($this->var_expires[$var_name])) - { - return false; - } - - return (time() > $this->var_expires[$var_name]) ? false : isset($this->vars[$var_name]); - } - } - - /** - * Load cached sql query - */ - function sql_load($query) - { - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - - if (($rowset = $this->_read('sql_' . md5($query))) === false) - { - return false; - } - - $query_id = sizeof($this->sql_rowset); - $this->sql_rowset[$query_id] = $rowset; - $this->sql_row_pointer[$query_id] = 0; - - return $query_id; - } - - /** - * Save sql query - */ - function sql_save($query, &$query_result, $ttl) - { - global $db; - - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - - $query_id = sizeof($this->sql_rowset); - $this->sql_rowset[$query_id] = array(); - $this->sql_row_pointer[$query_id] = 0; - - while ($row = $db->sql_fetchrow($query_result)) - { - $this->sql_rowset[$query_id][] = $row; - } - $db->sql_freeresult($query_result); - - if ($this->_write('sql_' . md5($query), $this->sql_rowset[$query_id], $ttl + time(), $query)) - { - $query_result = $query_id; - } - } - - /** - * Ceck if a given sql query exist in cache - */ - function sql_exists($query_id) - { - return isset($this->sql_rowset[$query_id]); - } - - /** - * Fetch row from cache (database) - */ - function sql_fetchrow($query_id) - { - if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) - { - return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++]; - } - - return false; - } - - /** - * Fetch a field from the current row of a cached database result (database) - */ - function sql_fetchfield($query_id, $field) - { - if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) - { - return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false; - } - - return false; - } - - /** - * Seek a specific row in an a cached database result (database) - */ - function sql_rowseek($rownum, $query_id) - { - if ($rownum >= sizeof($this->sql_rowset[$query_id])) - { - return false; - } - - $this->sql_row_pointer[$query_id] = $rownum; - return true; - } - - /** - * Free memory used for a cached database result (database) - */ - function sql_freeresult($query_id) - { - if (!isset($this->sql_rowset[$query_id])) - { - return false; - } - - unset($this->sql_rowset[$query_id]); - unset($this->sql_row_pointer[$query_id]); - - return true; - } - - /** - * Read cached data from a specified file - * - * @access private - * @param string $filename Filename to write - * @return mixed False if an error was encountered, otherwise the data type of the cached data - */ - function _read($filename) - { - global $phpEx; - - $file = "{$this->cache_dir}$filename.$phpEx"; - - $type = substr($filename, 0, strpos($filename, '_')); - - if (!file_exists($file)) - { - return false; - } - - if (!($handle = @fopen($file, 'rb'))) - { - return false; - } - - // Skip the PHP header - fgets($handle); - - if ($filename == 'data_global') - { - $this->vars = $this->var_expires = array(); - - $time = time(); - - while (($expires = (int) fgets($handle)) && !feof($handle)) - { - // Number of bytes of data - $bytes = substr(fgets($handle), 0, -1); - - if (!is_numeric($bytes) || ($bytes = (int) $bytes) === 0) - { - // We cannot process the file without a valid number of bytes - // so we discard it - fclose($handle); - - $this->vars = $this->var_expires = array(); - $this->is_modified = false; - - $this->remove_file($file); - - return false; - } - - if ($time >= $expires) - { - fseek($handle, $bytes, SEEK_CUR); - - continue; - } - - $var_name = substr(fgets($handle), 0, -1); - - // Read the length of bytes that consists of data. - $data = fread($handle, $bytes - strlen($var_name)); - $data = @unserialize($data); - - // Don't use the data if it was invalid - if ($data !== false) - { - $this->vars[$var_name] = $data; - $this->var_expires[$var_name] = $expires; - } - - // Absorb the LF - fgets($handle); - } - - fclose($handle); - - $this->is_modified = false; - - return true; - } - else - { - $data = false; - $line = 0; - - while (($buffer = fgets($handle)) && !feof($handle)) - { - $buffer = substr($buffer, 0, -1); // Remove the LF - - // $buffer is only used to read integers - // if it is non numeric we have an invalid - // cache file, which we will now remove. - if (!is_numeric($buffer)) - { - break; - } - - if ($line == 0) - { - $expires = (int) $buffer; - - if (time() >= $expires) - { - break; - } - - if ($type == 'sql') - { - // Skip the query - fgets($handle); - } - } - else if ($line == 1) - { - $bytes = (int) $buffer; - - // Never should have 0 bytes - if (!$bytes) - { - break; - } - - // Grab the serialized data - $data = fread($handle, $bytes); - - // Read 1 byte, to trigger EOF - fread($handle, 1); - - if (!feof($handle)) - { - // Somebody tampered with our data - $data = false; - } - break; - } - else - { - // Something went wrong - break; - } - $line++; - } - fclose($handle); - - // unserialize if we got some data - $data = ($data !== false) ? @unserialize($data) : $data; - - if ($data === false) - { - $this->remove_file($file); - return false; - } - - return $data; - } - } - - /** - * Write cache data to a specified file - * - * 'data_global' is a special case and the generated format is different for this file: - * <code> - * <?php exit; ?> - * (expiration) - * (length of var and serialised data) - * (var) - * (serialised data) - * ... (repeat) - * </code> - * - * The other files have a similar format: - * <code> - * <?php exit; ?> - * (expiration) - * (query) [SQL files only] - * (length of serialised data) - * (serialised data) - * </code> - * - * @access private - * @param string $filename Filename to write - * @param mixed $data Data to store - * @param int $expires Timestamp when the data expires - * @param string $query Query when caching SQL queries - * @return bool True if the file was successfully created, otherwise false - */ - function _write($filename, $data = null, $expires = 0, $query = '') - { - global $phpEx; - - $file = "{$this->cache_dir}$filename.$phpEx"; - - if ($handle = @fopen($file, 'wb')) - { - @flock($handle, LOCK_EX); - - // File header - fwrite($handle, '<' . '?php exit; ?' . '>'); - - if ($filename == 'data_global') - { - // Global data is a different format - foreach ($this->vars as $var => $data) - { - if (strpos($var, "\r") !== false || strpos($var, "\n") !== false) - { - // CR/LF would cause fgets() to read the cache file incorrectly - // do not cache test entries, they probably won't be read back - // the cache keys should really be alphanumeric with a few symbols. - continue; - } - $data = serialize($data); - - // Write out the expiration time - fwrite($handle, "\n" . $this->var_expires[$var] . "\n"); - - // Length of the remaining data for this var (ignoring two LF's) - fwrite($handle, strlen($data . $var) . "\n"); - fwrite($handle, $var . "\n"); - fwrite($handle, $data); - } - } - else - { - fwrite($handle, "\n" . $expires . "\n"); - - if (strpos($filename, 'sql_') === 0) - { - fwrite($handle, $query . "\n"); - } - $data = serialize($data); - - fwrite($handle, strlen($data) . "\n"); - fwrite($handle, $data); - } - - @flock($handle, LOCK_UN); - fclose($handle); - - if (!function_exists('phpbb_chmod')) - { - global $phpbb_root_path; - include($phpbb_root_path . 'includes/functions.' . $phpEx); - } - - phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE); - - return true; - } - - return false; - } - - /** - * Removes/unlinks file - */ - function remove_file($filename, $check = false) - { - if (!function_exists('phpbb_is_writable')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/functions.' . $phpEx); - } - - if ($check && !phpbb_is_writable($this->cache_dir)) - { - // E_USER_ERROR - not using language entry - intended. - trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR); - } - - return @unlink($filename); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/acm/acm_memcache.php b/phpBB/includes/acm/acm_memcache.php deleted file mode 100644 index 70bc219952..0000000000 --- a/phpBB/includes/acm/acm_memcache.php +++ /dev/null @@ -1,138 +0,0 @@ -<?php -/** -* -* @package acm -* @version $Id$ -* @copyright (c) 2005, 2009 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -// Include the abstract base -if (!class_exists('acm_memory')) -{ - require("{$phpbb_root_path}includes/acm/acm_memory.$phpEx"); -} - -if (!defined('PHPBB_ACM_MEMCACHE_PORT')) -{ - define('PHPBB_ACM_MEMCACHE_PORT', 11211); -} - -if (!defined('PHPBB_ACM_MEMCACHE_COMPRESS')) -{ - define('PHPBB_ACM_MEMCACHE_COMPRESS', false); -} - -if (!defined('PHPBB_ACM_MEMCACHE_HOST')) -{ - define('PHPBB_ACM_MEMCACHE_HOST', 'localhost'); -} - -if (!defined('PHPBB_ACM_MEMCACHE')) -{ - //can define multiple servers with host1/port1,host2/port2 format - define('PHPBB_ACM_MEMCACHE', PHPBB_ACM_MEMCACHE_HOST . '/' . PHPBB_ACM_MEMCACHE_PORT); -} - -/** -* ACM for Memcached -* @package acm -*/ -class acm extends acm_memory -{ - var $extension = 'memcache'; - - var $memcache; - var $flags = 0; - - function acm() - { - // Call the parent constructor - parent::acm_memory(); - - $this->memcache = new Memcache; - foreach(explode(',', PHPBB_ACM_MEMCACHE) as $u) - { - $parts = explode('/', $u); - $this->memcache->addServer(trim($parts[0]), trim($parts[1])); - } - $this->flags = (PHPBB_ACM_MEMCACHE_COMPRESS) ? MEMCACHE_COMPRESSED : 0; - } - - /** - * Unload the cache resources - * - * @return null - */ - function unload() - { - parent::unload(); - - $this->memcache->close(); - } - - /** - * Purge cache data - * - * @return null - */ - function purge() - { - $this->memcache->flush(); - - parent::purge(); - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - return $this->memcache->get($this->key_prefix . $var); - } - - /** - * Store data in the cache - * - * @access protected - * @param string $var Cache key - * @param mixed $data Data to store - * @param int $ttl Time-to-live of cached data - * @return bool True if the operation succeeded - */ - function _write($var, $data, $ttl = 2592000) - { - if (!$this->memcache->replace($this->key_prefix . $var, $data, $this->flags, $ttl)) - { - return $this->memcache->set($this->key_prefix . $var, $data, $this->flags, $ttl); - } - return true; - } - - /** - * Remove an item from the cache - * - * @access protected - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - function _delete($var) - { - return $this->memcache->delete($this->key_prefix . $var); - } -} - -?> diff --git a/phpBB/includes/acm/acm_memory.php b/phpBB/includes/acm/acm_memory.php deleted file mode 100644 index 9b68585d24..0000000000 --- a/phpBB/includes/acm/acm_memory.php +++ /dev/null @@ -1,451 +0,0 @@ -<?php -/** -* -* @package acm -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* ACM Abstract Memory Class -* @package acm -*/ -class acm_memory -{ - var $key_prefix; - - var $vars = array(); - var $is_modified = false; - - var $sql_rowset = array(); - var $sql_row_pointer = array(); - var $cache_dir = ''; - - /** - * Set cache path - */ - function acm_memory() - { - global $phpbb_root_path, $dbname, $table_prefix; - - $this->cache_dir = $phpbb_root_path . 'cache/'; - $this->key_prefix = substr(md5($dbname . $table_prefix), 0, 8) . '_'; - - if (!isset($this->extension) || !extension_loaded($this->extension)) - { - global $acm_type; - - trigger_error("Could not find required extension [{$this->extension}] for the ACM module $acm_type.", E_USER_ERROR); - } - - if (isset($this->function) && !function_exists($this->function)) - { - global $acm_type; - - trigger_error("The required function [{$this->function}] is not available for the ACM module $acm_type.", E_USER_ERROR); - } - } - - /** - * Load global cache - */ - function load() - { - // grab the global cache - $this->vars = $this->_read('global'); - - if ($this->vars !== false) - { - return true; - } - - return false; - } - - /** - * Unload cache object - */ - function unload() - { - $this->save(); - unset($this->vars); - unset($this->sql_rowset); - unset($this->sql_row_pointer); - - $this->vars = array(); - $this->sql_rowset = array(); - $this->sql_row_pointer = array(); - } - - /** - * Save modified objects - */ - function save() - { - if (!$this->is_modified) - { - return; - } - - $this->_write('global', $this->vars, 2592000); - - $this->is_modified = false; - } - - /** - * Tidy cache - */ - function tidy() - { - // cache has auto GC, no need to have any code here :) - - set_config('cache_last_gc', time(), true); - } - - /** - * Get saved cache object - */ - function get($var_name) - { - if ($var_name[0] == '_') - { - if (!$this->_exists($var_name)) - { - return false; - } - - return $this->_read($var_name); - } - else - { - return ($this->_exists($var_name)) ? $this->vars[$var_name] : false; - } - } - - /** - * Put data into cache - */ - function put($var_name, $var, $ttl = 2592000) - { - if ($var_name[0] == '_') - { - $this->_write($var_name, $var, $ttl); - } - else - { - $this->vars[$var_name] = $var; - $this->is_modified = true; - } - } - - /** - * Purge cache data - */ - function purge() - { - // Purge all phpbb cache files - $dir = @opendir($this->cache_dir); - - if (!$dir) - { - return; - } - - while (($entry = readdir($dir)) !== false) - { - if (strpos($entry, 'sql_') !== 0 && strpos($entry, 'data_') !== 0 && strpos($entry, 'ctpl_') !== 0 && strpos($entry, 'tpl_') !== 0) - { - continue; - } - - $this->remove_file($this->cache_dir . $entry); - } - closedir($dir); - - unset($this->vars); - unset($this->sql_rowset); - unset($this->sql_row_pointer); - - $this->vars = array(); - $this->sql_rowset = array(); - $this->sql_row_pointer = array(); - - $this->is_modified = false; - } - - - /** - * Destroy cache data - */ - function destroy($var_name, $table = '') - { - if ($var_name == 'sql' && !empty($table)) - { - if (!is_array($table)) - { - $table = array($table); - } - - foreach ($table as $table_name) - { - // gives us the md5s that we want - $temp = $this->_read('sql_' . $table_name); - - if ($temp === false) - { - continue; - } - - // delete each query ref - foreach ($temp as $md5_id => $void) - { - $this->_delete('sql_' . $md5_id); - } - - // delete the table ref - $this->_delete('sql_' . $table_name); - } - - return; - } - - if (!$this->_exists($var_name)) - { - return; - } - - if ($var_name[0] == '_') - { - $this->_delete($var_name); - } - else if (isset($this->vars[$var_name])) - { - $this->is_modified = true; - unset($this->vars[$var_name]); - - // We save here to let the following cache hits succeed - $this->save(); - } - } - - /** - * Check if a given cache entry exist - */ - function _exists($var_name) - { - if ($var_name[0] == '_') - { - return $this->_isset($var_name); - } - else - { - if (!sizeof($this->vars)) - { - $this->load(); - } - - return isset($this->vars[$var_name]); - } - } - - /** - * Load cached sql query - */ - function sql_load($query) - { - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - $query_id = sizeof($this->sql_rowset); - - if (($result = $this->_read('sql_' . md5($query))) === false) - { - return false; - } - - $this->sql_rowset[$query_id] = $result; - $this->sql_row_pointer[$query_id] = 0; - - return $query_id; - } - - /** - * Save sql query - */ - function sql_save($query, &$query_result, $ttl) - { - global $db; - - // Remove extra spaces and tabs - $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - $hash = md5($query); - - // determine which tables this query belongs to - // Some queries use backticks, namely the get_database_size() query - // don't check for conformity, the SQL would error and not reach here. - if (!preg_match_all('/(?:FROM \\(?(`?\\w+`?(?: \\w+)?(?:, ?`?\\w+`?(?: \\w+)?)*)\\)?)|(?:JOIN (`?\\w+`?(?: \\w+)?))/', $query, $regs, PREG_SET_ORDER)) - { - // Bail out if the match fails. - return; - } - - $tables = array(); - foreach ($regs as $match) - { - if ($match[0][0] == 'F') - { - $tables = array_merge($tables, array_map('trim', explode(',', $match[1]))); - } - else - { - $tables[] = $match[2]; - } - } - - foreach ($tables as $table_name) - { - // Remove backticks - $table_name = ($table_name[0] == '`') ? substr($table_name, 1, -1) : $table_name; - - if (($pos = strpos($table_name, ' ')) !== false) - { - $table_name = substr($table_name, 0, $pos); - } - - $temp = $this->_read('sql_' . $table_name); - - if ($temp === false) - { - $temp = array(); - } - - $temp[$hash] = true; - - // This must never expire - $this->_write('sql_' . $table_name, $temp, 0); - } - - // store them in the right place - $query_id = sizeof($this->sql_rowset); - $this->sql_rowset[$query_id] = array(); - $this->sql_row_pointer[$query_id] = 0; - - while ($row = $db->sql_fetchrow($query_result)) - { - $this->sql_rowset[$query_id][] = $row; - } - $db->sql_freeresult($query_result); - - $this->_write('sql_' . $hash, $this->sql_rowset[$query_id], $ttl); - - $query_result = $query_id; - } - - /** - * Ceck if a given sql query exist in cache - */ - function sql_exists($query_id) - { - return isset($this->sql_rowset[$query_id]); - } - - /** - * Fetch row from cache (database) - */ - function sql_fetchrow($query_id) - { - if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) - { - return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++]; - } - - return false; - } - - /** - * Fetch a field from the current row of a cached database result (database) - */ - function sql_fetchfield($query_id, $field) - { - if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) - { - return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false; - } - - return false; - } - - /** - * Seek a specific row in an a cached database result (database) - */ - function sql_rowseek($rownum, $query_id) - { - if ($rownum >= sizeof($this->sql_rowset[$query_id])) - { - return false; - } - - $this->sql_row_pointer[$query_id] = $rownum; - return true; - } - - /** - * Free memory used for a cached database result (database) - */ - function sql_freeresult($query_id) - { - if (!isset($this->sql_rowset[$query_id])) - { - return false; - } - - unset($this->sql_rowset[$query_id]); - unset($this->sql_row_pointer[$query_id]); - - return true; - } - - /** - * Removes/unlinks file - */ - function remove_file($filename, $check = false) - { - if (!function_exists('phpbb_is_writable')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/functions.' . $phpEx); - } - - if ($check && !phpbb_is_writable($this->cache_dir)) - { - // E_USER_ERROR - not using language entry - intended. - trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR); - } - - return @unlink($filename); - } - - /** - * Check if a cache var exists - * - * @access protected - * @param string $var Cache key - * @return bool True if it exists, otherwise false - */ - function _isset($var) - { - // Most caches don't need to check - return true; - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/acm/acm_null.php b/phpBB/includes/acm/acm_null.php deleted file mode 100644 index fca67115a7..0000000000 --- a/phpBB/includes/acm/acm_null.php +++ /dev/null @@ -1,156 +0,0 @@ -<?php -/** -* -* @package acm -* @version $Id$ -* @copyright (c) 2005, 2009 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* ACM Null Caching -* @package acm -*/ -class acm -{ - /** - * Set cache path - */ - function acm() - { - } - - /** - * Load global cache - */ - function load() - { - return true; - } - - /** - * Unload cache object - */ - function unload() - { - } - - /** - * Save modified objects - */ - function save() - { - } - - /** - * Tidy cache - */ - function tidy() - { - // This cache always has a tidy room. - set_config('cache_last_gc', time(), true); - } - - /** - * Get saved cache object - */ - function get($var_name) - { - return false; - } - - /** - * Put data into cache - */ - function put($var_name, $var, $ttl = 0) - { - } - - /** - * Purge cache data - */ - function purge() - { - } - - /** - * Destroy cache data - */ - function destroy($var_name, $table = '') - { - } - - /** - * Check if a given cache entry exist - */ - function _exists($var_name) - { - return false; - } - - /** - * Load cached sql query - */ - function sql_load($query) - { - return false; - } - - /** - * Save sql query - */ - function sql_save($query, &$query_result, $ttl) - { - } - - /** - * Ceck if a given sql query exist in cache - */ - function sql_exists($query_id) - { - return false; - } - - /** - * Fetch row from cache (database) - */ - function sql_fetchrow($query_id) - { - return false; - } - - /** - * Fetch a field from the current row of a cached database result (database) - */ - function sql_fetchfield($query_id, $field) - { - return false; - } - - /** - * Seek a specific row in an a cached database result (database) - */ - function sql_rowseek($rownum, $query_id) - { - return false; - } - - /** - * Free memory used for a cached database result (database) - */ - function sql_freeresult($query_id) - { - return false; - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/acm/acm_redis.php b/phpBB/includes/acm/acm_redis.php deleted file mode 100644 index dc11ca7768..0000000000 --- a/phpBB/includes/acm/acm_redis.php +++ /dev/null @@ -1,145 +0,0 @@ -<?php -/** -* -* @package acm -* @copyright (c) 2011 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -// Include the abstract base -if (!class_exists('acm_memory')) -{ - require("{$phpbb_root_path}includes/acm/acm_memory.$phpEx"); -} - -if (!defined('PHPBB_ACM_REDIS_PORT')) -{ - define('PHPBB_ACM_REDIS_PORT', 6379); -} - -if (!defined('PHPBB_ACM_REDIS_HOST')) -{ - define('PHPBB_ACM_REDIS_HOST', 'localhost'); -} - -/** -* ACM for Redis -* -* Compatible with the php extension phpredis available -* at https://github.com/nicolasff/phpredis -* -* @package acm -*/ -class acm extends acm_memory -{ - var $extension = 'redis'; - - var $redis; - - function acm() - { - // Call the parent constructor - parent::acm_memory(); - - $this->redis = new Redis(); - $this->redis->connect(PHPBB_ACM_REDIS_HOST, PHPBB_ACM_REDIS_PORT); - - if (defined('PHPBB_ACM_REDIS_PASSWORD')) - { - if (!$this->redis->auth(PHPBB_ACM_REDIS_PASSWORD)) - { - global $acm_type; - - trigger_error("Incorrect password for the ACM module $acm_type.", E_USER_ERROR); - } - } - - $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); - $this->redis->setOption(Redis::OPT_PREFIX, $this->key_prefix); - - if (defined('PHPBB_ACM_REDIS_DB')) - { - if (!$this->redis->select(PHPBB_ACM_REDIS_DB)) - { - global $acm_type; - - trigger_error("Incorrect database for the ACM module $acm_type.", E_USER_ERROR); - } - } - } - - /** - * Unload the cache resources - * - * @return null - */ - function unload() - { - parent::unload(); - - $this->redis->close(); - } - - /** - * Purge cache data - * - * @return null - */ - function purge() - { - $this->redis->flushDB(); - - parent::purge(); - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - return $this->redis->get($var); - } - - /** - * Store data in the cache - * - * @access protected - * @param string $var Cache key - * @param mixed $data Data to store - * @param int $ttl Time-to-live of cached data - * @return bool True if the operation succeeded - */ - function _write($var, $data, $ttl = 2592000) - { - return $this->redis->setex($var, $ttl, $data); - } - - /** - * Remove an item from the cache - * - * @access protected - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - function _delete($var) - { - if ($this->redis->delete($var) > 0) - { - return true; - } - return false; - } -} diff --git a/phpBB/includes/acm/acm_wincache.php b/phpBB/includes/acm/acm_wincache.php deleted file mode 100644 index 7faba4f5b6..0000000000 --- a/phpBB/includes/acm/acm_wincache.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php -/** -* -* @package acm -* @copyright (c) 2010 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -// Include the abstract base -if (!class_exists('acm_memory')) -{ - require("{$phpbb_root_path}includes/acm/acm_memory.$phpEx"); -} - -/** -* ACM for WinCache -* @package acm -*/ -class acm extends acm_memory -{ - var $extension = 'wincache'; - - /** - * Purge cache data - * - * @return null - */ - function purge() - { - wincache_ucache_clear(); - - parent::purge(); - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - $success = false; - $result = wincache_ucache_get($this->key_prefix . $var, $success); - - return ($success) ? $result : false; - } - - /** - * Store data in the cache - * - * @access protected - * @param string $var Cache key - * @param mixed $data Data to store - * @param int $ttl Time-to-live of cached data - * @return bool True if the operation succeeded - */ - function _write($var, $data, $ttl = 2592000) - { - return wincache_ucache_set($this->key_prefix . $var, $data, $ttl); - } - - /** - * Remove an item from the cache - * - * @access protected - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - function _delete($var) - { - return wincache_ucache_delete($this->key_prefix . $var); - } -} diff --git a/phpBB/includes/acm/acm_xcache.php b/phpBB/includes/acm/acm_xcache.php deleted file mode 100644 index e3d83f8bfa..0000000000 --- a/phpBB/includes/acm/acm_xcache.php +++ /dev/null @@ -1,121 +0,0 @@ -<?php -/** -* -* @package acm -* @version $Id$ -* @copyright (c) 2005, 2009 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -// Include the abstract base -if (!class_exists('acm_memory')) -{ - require("{$phpbb_root_path}includes/acm/acm_memory.$phpEx"); -} - -/** -* ACM for XCache -* @package acm -* -* To use this module you need ini_get() enabled and the following INI settings configured as follows: -* - xcache.var_size > 0 -* - xcache.admin.enable_auth = off (or xcache.admin.user and xcache.admin.password set) -* -*/ -class acm extends acm_memory -{ - var $extension = 'XCache'; - - function acm() - { - parent::acm_memory(); - - if (!function_exists('ini_get') || (int) ini_get('xcache.var_size') <= 0) - { - trigger_error('Increase xcache.var_size setting above 0 or enable ini_get() to use this ACM module.', E_USER_ERROR); - } - } - - /** - * Purge cache data - * - * @return null - */ - function purge() - { - // Run before for XCache, if admin functions are disabled it will terminate execution - parent::purge(); - - // If the admin authentication is enabled but not set up, this will cause a nasty error. - // Not much we can do about it though. - $n = xcache_count(XC_TYPE_VAR); - - for ($i = 0; $i < $n; $i++) - { - xcache_clear_cache(XC_TYPE_VAR, $i); - } - } - - /** - * Fetch an item from the cache - * - * @access protected - * @param string $var Cache key - * @return mixed Cached data - */ - function _read($var) - { - $result = xcache_get($this->key_prefix . $var); - - return ($result !== null) ? $result : false; - } - - /** - * Store data in the cache - * - * @access protected - * @param string $var Cache key - * @param mixed $data Data to store - * @param int $ttl Time-to-live of cached data - * @return bool True if the operation succeeded - */ - function _write($var, $data, $ttl = 2592000) - { - return xcache_set($this->key_prefix . $var, $data, $ttl); - } - - /** - * Remove an item from the cache - * - * @access protected - * @param string $var Cache key - * @return bool True if the operation succeeded - */ - function _delete($var) - { - return xcache_unset($this->key_prefix . $var); - } - - /** - * Check if a cache var exists - * - * @access protected - * @param string $var Cache key - * @return bool True if it exists, otherwise false - */ - function _isset($var) - { - return xcache_isset($this->key_prefix . $var); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php index bffe6f7db3..67fba1094d 100644 --- a/phpBB/includes/acp/acp_attachments.php +++ b/phpBB/includes/acp/acp_attachments.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,19 +19,39 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_attachments { - var $u_action; - var $new_config; + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + /** @var \phpbb\config\config */ + protected $config; + + /** @var ContainerBuilder */ + protected $phpbb_container; + + /** @var \phpbb\template\template */ + protected $template; + + /** @var \phpbb\user */ + protected $user; + + public $id; + public $u_action; + protected $new_config; function main($id, $mode) { - global $db, $user, $auth, $template, $cache; + global $db, $user, $auth, $template, $cache, $phpbb_container; global $config, $phpbb_admin_path, $phpbb_root_path, $phpEx; + $this->id = $id; + $this->db = $db; + $this->config = $config; + $this->template = $template; + $this->user = $user; + $this->phpbb_container = $phpbb_container; + $user->add_lang(array('posting', 'viewtopic', 'acp/attachments')); $error = $notify = array(); @@ -61,6 +84,10 @@ class acp_attachments $l_title = 'ACP_ORPHAN_ATTACHMENTS'; break; + case 'manage': + $l_title = 'ACP_MANAGE_ATTACHMENTS'; + break; + default: trigger_error('NO_MODE', E_USER_ERROR); break; @@ -95,7 +122,7 @@ class acp_attachments } $db->sql_freeresult($result); - $l_legend_cat_images = $user->lang['SETTINGS_CAT_IMAGES'] . ' [' . $user->lang['ASSIGNED_GROUP'] . ': ' . ((!empty($s_assigned_groups[ATTACHMENT_CATEGORY_IMAGE])) ? implode(', ', $s_assigned_groups[ATTACHMENT_CATEGORY_IMAGE]) : $user->lang['NO_EXT_GROUP']) . ']'; + $l_legend_cat_images = $user->lang['SETTINGS_CAT_IMAGES'] . ' [' . $user->lang['ASSIGNED_GROUP'] . ': ' . ((!empty($s_assigned_groups[ATTACHMENT_CATEGORY_IMAGE])) ? implode($user->lang['COMMA_SEPARATOR'], $s_assigned_groups[ATTACHMENT_CATEGORY_IMAGE]) : $user->lang['NO_EXT_GROUP']) . ']'; $display_vars = array( 'title' => 'ACP_ATTACHMENT_SETTINGS', @@ -114,22 +141,21 @@ class acp_attachments 'attachment_quota' => array('lang' => 'ATTACH_QUOTA', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), 'max_filesize' => array('lang' => 'ATTACH_MAX_FILESIZE', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), 'max_filesize_pm' => array('lang' => 'ATTACH_MAX_PM_FILESIZE','validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => false), - 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => false), + 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false), + 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false), 'secure_downloads' => array('lang' => 'SECURE_DOWNLOADS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'secure_allow_deny' => array('lang' => 'SECURE_ALLOW_DENY', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_allow_deny', 'explain' => true), 'secure_allow_empty_referer' => array('lang' => 'SECURE_EMPTY_REFERRER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'check_attachment_content' => array('lang' => 'CHECK_CONTENT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'legend2' => $l_legend_cat_images, 'img_display_inlined' => array('lang' => 'DISPLAY_INLINED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'img_create_thumbnail' => array('lang' => 'CREATE_THUMBNAIL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), + 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int:0:999999999999999', 'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + 'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'validate' => 'int:0:999999999999999', 'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), 'img_imagick' => array('lang' => 'IMAGICK_PATH', 'validate' => 'absolute_path', 'type' => 'text:20:200', 'explain' => true, 'append' => ' <span>[ <a href="' . $this->u_action . '&action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'), - 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), ) ); @@ -745,7 +771,6 @@ class acp_attachments } $template->assign_vars(array( - 'PHPBB_ROOT_PATH' => $phpbb_root_path, 'IMG_PATH' => $img_path, 'ACTION' => $action, 'GROUP_ID' => $group_id, @@ -914,7 +939,7 @@ class acp_attachments $db->sql_query($sql); add_log('admin', 'LOG_ATTACH_ORPHAN_DEL', implode(', ', $delete_files)); - $notify[] = sprintf($user->lang['LOG_ATTACH_ORPHAN_DEL'], implode(', ', $delete_files)); + $notify[] = sprintf($user->lang['LOG_ATTACH_ORPHAN_DEL'], implode($user->lang['COMMA_SEPARATOR'], $delete_files)); } $upload_list = array(); @@ -1043,6 +1068,181 @@ class acp_attachments $db->sql_freeresult($result); break; + + case 'manage': + + if ($submit) + { + $delete_files = (isset($_POST['delete'])) ? array_keys(request_var('delete', array('' => 0))) : array(); + + if (sizeof($delete_files)) + { + // Select those attachments we want to delete... + $sql = 'SELECT real_filename + FROM ' . ATTACHMENTS_TABLE . ' + WHERE ' . $db->sql_in_set('attach_id', $delete_files) . ' + AND is_orphan = 0'; + $result = $db->sql_query($sql); + while ($row = $db->sql_fetchrow($result)) + { + $deleted_filenames[] = $row['real_filename']; + } + $db->sql_freeresult($result); + + if ($num_deleted = delete_attachments('attach', $delete_files)) + { + if (sizeof($delete_files) != $num_deleted) + { + $error[] = $user->lang['FILES_GONE']; + } + add_log('admin', 'LOG_ATTACHMENTS_DELETED', implode(', ', $deleted_filenames)); + $notify[] = sprintf($user->lang['LOG_ATTACHMENTS_DELETED'], implode($user->lang['COMMA_SEPARATOR'], $deleted_filenames)); + } + else + { + $error[] = $user->lang['NO_FILES_TO_DELETE']; + } + } + } + + if ($action == 'stats') + { + $this->handle_stats_resync(); + } + + $stats_error = $this->check_stats_accuracy(); + + if ($stats_error) + { + $error[] = $stats_error; + } + + $template->assign_vars(array( + 'S_MANAGE' => true, + )); + + $start = request_var('start', 0); + + // Sort keys + $sort_days = request_var('st', 0); + $sort_key = request_var('sk', 't'); + $sort_dir = request_var('sd', 'd'); + + // Sorting + $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); + $sort_by_text = array('f' => $user->lang['FILENAME'], 't' => $user->lang['FILEDATE'], 's' => $user->lang['FILESIZE'], 'x' => $user->lang['EXTENSION'], 'd' => $user->lang['DOWNLOADS'],'p' => $user->lang['ATTACH_POST_TYPE'], 'u' => $user->lang['AUTHOR']); + $sort_by_sql = array('f' => 'a.real_filename', 't' => 'a.filetime', 's' => 'a.filesize', 'x' => 'a.extension', 'd' => 'a.download_count', 'p' => 'a.in_message', 'u' => 'u.username'); + + $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; + gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); + + $min_filetime = ($sort_days) ? (time() - ($sort_days * 86400)) : ''; + $limit_filetime = ($min_filetime) ? " AND a.filetime >= $min_filetime " : ''; + $start = ($sort_days && isset($_POST['sort'])) ? 0 : $start; + + $attachments_per_page = (int) $config['topics_per_page']; + + $stats = $this->get_attachment_stats($limit_filetime); + $num_files = $stats['num_files']; + $total_size = $stats['upload_dir_size']; + + // Make sure $start is set to the last page if it exceeds the amount + $pagination = $phpbb_container->get('pagination'); + $start = $pagination->validate_start($start, $attachments_per_page, $num_files); + + // If the user is trying to reach the second half of the attachments list, fetch it starting from the end + $store_reverse = false; + $sql_limit = $attachments_per_page; + + if ($start > $num_files / 2) + { + $store_reverse = true; + + // Select the sort order. Add time sort anchor for non-time sorting cases + $sql_sort_anchor = ($sort_key != 't') ? ', a.filetime ' . (($sort_dir == 'd') ? 'ASC' : 'DESC') : ''; + $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'ASC' : 'DESC') . $sql_sort_anchor; + $sql_limit = $pagination->reverse_limit($start, $sql_limit, $num_files); + $sql_start = $pagination->reverse_start($start, $sql_limit, $num_files); + } + else + { + // Select the sort order. Add time sort anchor for non-time sorting cases + $sql_sort_anchor = ($sort_key != 't') ? ', a.filetime ' . (($sort_dir == 'd') ? 'DESC' : 'ASC') : ''; + $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC') . $sql_sort_anchor; + $sql_start = $start; + } + + $attachments_list = array(); + + // Just get the files + $sql = 'SELECT a.*, u.username, u.user_colour, t.topic_title + FROM ' . ATTACHMENTS_TABLE . ' a + LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = a.poster_id) + LEFT JOIN ' . TOPICS_TABLE . " t ON (a.topic_id = t.topic_id) + WHERE a.is_orphan = 0 + $limit_filetime + ORDER BY $sql_sort_order"; + $result = $db->sql_query_limit($sql, $sql_limit, $sql_start); + + $i = ($store_reverse) ? $sql_limit - 1 : 0; + + // Store increment value in a variable to save some conditional calls + $i_increment = ($store_reverse) ? -1 : 1; + while ($attachment_row = $db->sql_fetchrow($result)) + { + $attachments_list[$i] = $attachment_row; + $i = $i + $i_increment; + } + $db->sql_freeresult($result); + + $base_url = $this->u_action . "&$u_sort_param"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $num_files, $attachments_per_page, $start); + + $template->assign_vars(array( + 'TOTAL_FILES' => $num_files, + 'TOTAL_SIZE' => get_formatted_filesize($total_size), + + 'S_LIMIT_DAYS' => $s_limit_days, + 'S_SORT_KEY' => $s_sort_key, + 'S_SORT_DIR' => $s_sort_dir) + ); + + // Grab extensions + $extensions = $cache->obtain_attach_extensions(true); + + for ($i = 0, $end = sizeof($attachments_list); $i < $end; ++$i) + { + $row = $attachments_list[$i]; + + $row['extension'] = strtolower(trim((string) $row['extension'])); + $comment = ($row['attach_comment'] && !$row['in_message']) ? str_replace(array("\n", "\r"), array('<br />', "\n"), $row['attach_comment']) : ''; + $display_cat = $extensions[$row['extension']]['display_cat']; + $l_downloaded_viewed = ($display_cat == ATTACHMENT_CATEGORY_NONE) ? 'DOWNLOAD_COUNTS' : 'VIEWED_COUNTS'; + + $template->assign_block_vars('attachments', array( + 'ATTACHMENT_POSTER' => get_username_string('full', (int) $row['poster_id'], (string) $row['username'], (string) $row['user_colour'], (string) $row['username']), + 'FILESIZE' => get_formatted_filesize((int) $row['filesize']), + 'FILETIME' => $user->format_date((int) $row['filetime']), + 'REAL_FILENAME' => (!$row['in_message']) ? utf8_basename((string) $row['real_filename']) : '', + 'PHYSICAL_FILENAME' => utf8_basename((string) $row['physical_filename']), + 'EXT_GROUP_NAME' => (!empty($extensions[$row['extension']]['group_name'])) ? $user->lang['EXT_GROUP_' . $extensions[$row['extension']]['group_name']] : '', + 'COMMENT' => $comment, + 'TOPIC_TITLE' => (!$row['in_message']) ? (string) $row['topic_title'] : '', + 'ATTACH_ID' => (int) $row['attach_id'], + 'POST_ID' => (int) $row['post_msg_id'], + 'TOPIC_ID' => (int) $row['topic_id'], + 'POST_IDS' => (!empty($post_ids[$row['attach_id']])) ? (int) $post_ids[$row['attach_id']] : '', + + 'L_DOWNLOAD_COUNT' => $user->lang($l_downloaded_viewed, (int) $row['download_count']), + + 'S_IN_MESSAGE' => (bool) $row['in_message'], + + 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_id']}&p={$row['post_msg_id']}") . "#p{$row['post_msg_id']}", + 'U_FILE' => append_sid($phpbb_root_path . 'download/file.' . $phpEx, 'mode=view&id=' . $row['attach_id'])) + ); + } + + break; } if (sizeof($error)) @@ -1063,6 +1263,96 @@ class acp_attachments } /** + * Get attachment file count and size of upload directory + * + * @param $limit string Additional limit for WHERE clause to filter stats by. + * @return array Returns array with stats: num_files and upload_dir_size + */ + public function get_attachment_stats($limit = '') + { + $sql = 'SELECT COUNT(a.attach_id) AS num_files, SUM(a.filesize) AS upload_dir_size + FROM ' . ATTACHMENTS_TABLE . " a + WHERE a.is_orphan = 0 + $limit"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + return array( + 'num_files' => (int) $row['num_files'], + 'upload_dir_size' => (float) $row['upload_dir_size'], + ); + } + + /** + * Set config attachment stat values + * + * @param $stats array Array of config key => value pairs to set. + * @return null + */ + public function set_attachment_stats($stats) + { + foreach ($stats as $key => $value) + { + $this->config->set($key, $value, true); + } + } + + /** + * Check accuracy of attachment statistics. + * + * @return bool|string Returns false if stats are correct or error message + * otherwise. + */ + public function check_stats_accuracy() + { + // Get fresh stats. + $stats = $this->get_attachment_stats(); + + // Get current files stats + $num_files = (int) $this->config['num_files']; + $total_size = (float) $this->config['upload_dir_size']; + + if (($num_files != $stats['num_files']) || ($total_size != $stats['upload_dir_size'])) + { + $u_resync = $this->u_action . '&action=stats'; + + return $this->user->lang( + 'FILES_STATS_WRONG', + (int) $stats['num_files'], + get_formatted_filesize($stats['upload_dir_size']), + '<a href="' . $u_resync . '">', + '</a>' + ); + } + return false; + } + + /** + * Handle stats resync. + * + * @return null + */ + public function handle_stats_resync() + { + if (!confirm_box(true)) + { + confirm_box(false, $this->user->lang['RESYNC_FILES_STATS_CONFIRM'], build_hidden_fields(array( + 'i' => $this->id, + 'mode' => 'manage', + 'action' => 'stats', + ))); + } + else + { + $this->set_attachment_stats($this->get_attachment_stats()); + $log = $this->phpbb_container->get('log'); + $log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_RESYNC_FILES_STATS'); + } + + } + + /** * Build Select for category items */ function category_select($select_name, $group_id = false, $key = '') @@ -1235,6 +1525,7 @@ class acp_attachments function perform_site_list() { global $db, $user; + global $request; if (isset($_REQUEST['securesubmit'])) { @@ -1243,7 +1534,7 @@ class acp_attachments $ip_list = array_unique(explode("\n", $ips)); $ip_list_log = implode(', ', $ip_list); - $ip_exclude = (!empty($_POST['ipexclude'])) ? 1 : 0; + $ip_exclude = (int) $request->variable('ipexclude', false, false, \phpbb\request\request_interface::POST); $iplist = array(); $hostlist = array(); @@ -1441,7 +1732,8 @@ class acp_attachments $size_var = $filesize['si_identifier']; $value = $filesize['value']; - return '<input type="text" id="' . $key . '" size="8" maxlength="15" name="config[' . $key . ']" value="' . $value . '" /> <select name="' . $key . '">' . size_select_options($size_var) . '</select>'; + // size="8" and maxlength="15" attributes as a fallback for browsers that do not support type="number" yet. + return '<input type="number" id="' . $key . '" size="8" maxlength="15" min="0" name="config[' . $key . ']" value="' . $value . '" /> <select name="' . $key . '">' . size_select_options($size_var) . '</select>'; } /** @@ -1455,5 +1747,3 @@ class acp_attachments } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_ban.php b/phpBB/includes/acp/acp_ban.php index f8af1b86e1..b555f46a94 100644 --- a/phpBB/includes/acp/acp_ban.php +++ b/phpBB/includes/acp/acp_ban.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,23 +19,19 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_ban { var $u_action; function main($id, $mode) { - global $config, $db, $user, $auth, $template, $cache; - global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix; + global $user, $template, $request, $phpbb_dispatcher; + global $phpbb_root_path, $phpEx; include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - $bansubmit = (isset($_POST['bansubmit'])) ? true : false; - $unbansubmit = (isset($_POST['unbansubmit'])) ? true : false; - $current_time = time(); + $bansubmit = $request->is_set_post('bansubmit'); + $unbansubmit = $request->is_set_post('unbansubmit'); $user->add_lang(array('acp/ban', 'acp/users')); $this->tpl_name = 'acp_ban'; @@ -48,23 +47,79 @@ class acp_ban if ($bansubmit) { // Grab the list of entries - $ban = utf8_normalize_nfc(request_var('ban', '', true)); - $ban_len = request_var('banlength', 0); - $ban_len_other = request_var('banlengthother', ''); - $ban_exclude = request_var('banexclude', 0); - $ban_reason = utf8_normalize_nfc(request_var('banreason', '', true)); - $ban_give_reason = utf8_normalize_nfc(request_var('bangivereason', '', true)); + $ban = $request->variable('ban', '', true); + $ban_length = $request->variable('banlength', 0); + $ban_length_other = $request->variable('banlengthother', ''); + $ban_exclude = $request->variable('banexclude', 0); + $ban_reason = $request->variable('banreason', '', true); + $ban_give_reason = $request->variable('bangivereason', '', true); if ($ban) { - user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reason, $ban_give_reason); + $abort_ban = false; + /** + * Use this event to modify the ban details before the ban is performed + * + * @event core.acp_ban_before + * @var string mode One of the following: user, ip, email + * @var string ban Either string or array with usernames, ips or email addresses + * @var int ban_length Ban length in minutes + * @var string ban_length_other Ban length as a date (YYYY-MM-DD) + * @var bool ban_exclude Are we banning or excluding from another ban + * @var string ban_reason Ban reason displayed to moderators + * @var string ban_give_reason Ban reason displayed to the banned user + * @var mixed abort_ban Either false, or an error message that is displayed to the user. + * If a string is given the bans are not issued. + * @since 3.1.0-RC5 + */ + $vars = array( + 'mode', + 'ban', + 'ban_length', + 'ban_length_other', + 'ban_exclude', + 'ban_reason', + 'ban_give_reason', + 'abort_ban', + ); + extract($phpbb_dispatcher->trigger_event('core.acp_ban_before', compact($vars))); + + if ($abort_ban) + { + trigger_error($abort_ban . adm_back_link($this->u_action)); + } + user_ban($mode, $ban, $ban_length, $ban_length_other, $ban_exclude, $ban_reason, $ban_give_reason); + + /** + * Use this event to perform actions after the ban has been performed + * + * @event core.acp_ban_after + * @var string mode One of the following: user, ip, email + * @var string ban Either string or array with usernames, ips or email addresses + * @var int ban_length Ban length in minutes + * @var string ban_length_other Ban length as a date (YYYY-MM-DD) + * @var bool ban_exclude Are we banning or excluding from another ban + * @var string ban_reason Ban reason displayed to moderators + * @var string ban_give_reason Ban reason displayed to the banned user + * @since 3.1.0-RC5 + */ + $vars = array( + 'mode', + 'ban', + 'ban_length', + 'ban_length_other', + 'ban_exclude', + 'ban_reason', + 'ban_give_reason', + ); + extract($phpbb_dispatcher->trigger_event('core.acp_ban_after', compact($vars))); trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . adm_back_link($this->u_action)); } } else if ($unbansubmit) { - $ban = request_var('unban', array('')); + $ban = $request->variable('unban', array('')); if ($ban) { @@ -98,7 +153,7 @@ class acp_ban break; } - $this->display_ban_options($mode); + self::display_ban_options($mode); $template->assign_vars(array( 'L_TITLE' => $this->page_title, @@ -110,7 +165,7 @@ class acp_ban 'L_NO_BAN_CELL' => $l_no_ban_cell, 'S_USERNAME_BAN' => ($mode == 'user') ? true : false, - + 'U_ACTION' => $this->u_action, 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=acp_ban&field=ban'), )); @@ -119,7 +174,7 @@ class acp_ban /** * Display ban options */ - function display_ban_options($mode) + static public function display_ban_options($mode) { global $user, $db, $template; @@ -176,8 +231,6 @@ class acp_ban $result = $db->sql_query($sql); $banned_options = $excluded_options = array(); - $ban_length = $ban_reasons = $ban_give_reasons = array(); - while ($row = $db->sql_fetchrow($result)) { $option = '<option value="' . $row['ban_id'] . '">' . $row[$field] . '</option>'; @@ -196,60 +249,31 @@ class acp_ban if ($time_length == 0) { // Banned permanently - $ban_length[$row['ban_id']] = $user->lang['PERMANENT']; + $ban_length = $user->lang['PERMANENT']; } else if (isset($ban_end_text[$time_length])) { // Banned for a given duration - $ban_length[$row['ban_id']] = sprintf($user->lang['BANNED_UNTIL_DURATION'], $ban_end_text[$time_length], $user->format_date($row['ban_end'], false, true)); + $ban_length = $user->lang('BANNED_UNTIL_DURATION', $ban_end_text[$time_length], $user->format_date($row['ban_end'], false, true)); } else { // Banned until given date - $ban_length[$row['ban_id']] = sprintf($user->lang['BANNED_UNTIL_DATE'], $user->format_date($row['ban_end'], false, true)); + $ban_length = $user->lang('BANNED_UNTIL_DATE', $user->format_date($row['ban_end'], false, true)); } - $ban_reasons[$row['ban_id']] = $row['ban_reason']; - $ban_give_reasons[$row['ban_id']] = $row['ban_give_reason']; + $template->assign_block_vars('bans', array( + 'BAN_ID' => (int) $row['ban_id'], + 'LENGTH' => $ban_length, + 'A_LENGTH' => addslashes($ban_length), + 'REASON' => $row['ban_reason'], + 'A_REASON' => addslashes($row['ban_reason']), + 'GIVE_REASON' => $row['ban_give_reason'], + 'A_GIVE_REASON' => addslashes($row['ban_give_reason']), + )); } $db->sql_freeresult($result); - if (sizeof($ban_length)) - { - foreach ($ban_length as $ban_id => $length) - { - $template->assign_block_vars('ban_length', array( - 'BAN_ID' => (int) $ban_id, - 'LENGTH' => $length, - 'A_LENGTH' => addslashes($length), - )); - } - } - - if (sizeof($ban_reasons)) - { - foreach ($ban_reasons as $ban_id => $reason) - { - $template->assign_block_vars('ban_reason', array( - 'BAN_ID' => $ban_id, - 'REASON' => $reason, - 'A_REASON' => addslashes($reason), - )); - } - } - - if (sizeof($ban_give_reasons)) - { - foreach ($ban_give_reasons as $ban_id => $reason) - { - $template->assign_block_vars('ban_give_reason', array( - 'BAN_ID' => $ban_id, - 'REASON' => $reason, - 'A_REASON' => addslashes($reason), - )); - } - } - $options = ''; if ($excluded_options) { @@ -272,5 +296,3 @@ class acp_ban )); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_bbcodes.php b/phpBB/includes/acp/acp_bbcodes.php index 31166a56dc..e245eea069 100644 --- a/phpBB/includes/acp/acp_bbcodes.php +++ b/phpBB/includes/acp/acp_bbcodes.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,16 +19,13 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_bbcodes { var $u_action; function main($id, $mode) { - global $db, $user, $auth, $template, $cache; + global $db, $user, $auth, $template, $cache, $request, $phpbb_dispatcher; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; $user->add_lang('acp/posting'); @@ -97,7 +97,7 @@ class acp_bbcodes case 'edit': case 'add': - $template->assign_vars(array( + $tpl_ary = array( 'S_EDIT_BBCODE' => true, 'U_BACK' => $this->u_action, 'U_ACTION' => $this->u_action . '&action=' . (($action == 'add') ? 'create' : 'modify') . (($bbcode_id) ? "&bbcode=$bbcode_id" : ''), @@ -106,14 +106,32 @@ class acp_bbcodes 'BBCODE_MATCH' => $bbcode_match, 'BBCODE_TPL' => $bbcode_tpl, 'BBCODE_HELPLINE' => $bbcode_helpline, - 'DISPLAY_ON_POSTING' => $display_on_posting) + 'DISPLAY_ON_POSTING' => $display_on_posting, ); - foreach ($user->lang['tokens'] as $token => $token_explain) + $bbcode_tokens = array('TEXT', 'SIMPLETEXT', 'INTTEXT', 'IDENTIFIER', 'NUMBER', 'EMAIL', 'URL', 'LOCAL_URL', 'RELATIVE_URL', 'COLOR'); + + /** + * Modify custom bbcode template data before we display the add/edit form + * + * @event core.acp_bbcodes_edit_add + * @var string action Type of the action: add|edit + * @var array tpl_ary Array with custom bbcode add/edit data + * @var int bbcode_id When editing: the bbcode id, + * when creating: 0 + * @var array bbcode_tokens Array of bbcode tokens + * @since 3.1.0-a3 + */ + $vars = array('action', 'tpl_ary', 'bbcode_id', 'bbcode_tokens'); + extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_edit_add', compact($vars))); + + $template->assign_vars($tpl_ary); + + foreach ($bbcode_tokens as $token) { $template->assign_block_vars('token', array( 'TOKEN' => '{' . $token . '}', - 'EXPLAIN' => ($token === 'LOCAL_URL') ? sprintf($token_explain, generate_board_url() . '/') : $token_explain, + 'EXPLAIN' => ($token === 'LOCAL_URL') ? $user->lang(array('tokens', $token), generate_board_url() . '/') : $user->lang(array('tokens', $token)), )); } @@ -124,6 +142,36 @@ class acp_bbcodes case 'modify': case 'create': + $sql_ary = $hidden_fields = array(); + + /** + * Modify custom bbcode data before the modify/create action + * + * @event core.acp_bbcodes_modify_create + * @var string action Type of the action: modify|create + * @var array sql_ary Array with new bbcode data + * @var int bbcode_id When editing: the bbcode id, + * when creating: 0 + * @var bool display_on_posting Display bbcode on posting form + * @var string bbcode_match The bbcode usage string to match + * @var string bbcode_tpl The bbcode HTML replacement string + * @var string bbcode_helpline The bbcode help line string + * @var array hidden_fields Array of hidden fields for use when + * submitting form when $warn_text is true + * @since 3.1.0-a3 + */ + $vars = array( + 'action', + 'sql_ary', + 'bbcode_id', + 'display_on_posting', + 'bbcode_match', + 'bbcode_tpl', + 'bbcode_helpline', + 'hidden_fields', + ); + extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_modify_create', compact($vars))); + $warn_text = preg_match('%<[^>]*\{text[\d]*\}[^>]*>%i', $bbcode_tpl); if (!$warn_text || confirm_box(true)) { @@ -172,13 +220,12 @@ class acp_bbcodes trigger_error($user->lang['BBCODE_TAG_DEF_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); } - if (strlen($bbcode_helpline) > 255) { trigger_error($user->lang['BBCODE_HELPLINE_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); } - $sql_ary = array( + $sql_ary = array_merge($sql_ary, array( 'bbcode_tag' => $data['bbcode_tag'], 'bbcode_match' => $bbcode_match, 'bbcode_tpl' => $bbcode_tpl, @@ -188,7 +235,7 @@ class acp_bbcodes 'first_pass_replace' => $data['first_pass_replace'], 'second_pass_match' => $data['second_pass_match'], 'second_pass_replace' => $data['second_pass_replace'] - ); + )); if ($action == 'create') { @@ -244,14 +291,14 @@ class acp_bbcodes } else { - confirm_box(false, $user->lang['BBCODE_DANGER'], build_hidden_fields(array( + confirm_box(false, $user->lang['BBCODE_DANGER'], build_hidden_fields(array_merge($hidden_fields, array( 'action' => $action, 'bbcode' => $bbcode_id, 'bbcode_match' => $bbcode_match, 'bbcode_tpl' => htmlspecialchars($bbcode_tpl), 'bbcode_helpline' => $bbcode_helpline, 'display_on_posting' => $display_on_posting, - )) + ))) , 'confirm_bbcode.html'); } @@ -273,6 +320,18 @@ class acp_bbcodes $db->sql_query('DELETE FROM ' . BBCODES_TABLE . " WHERE bbcode_id = $bbcode_id"); $cache->destroy('sql', BBCODES_TABLE); add_log('admin', 'LOG_BBCODE_DELETE', $row['bbcode_tag']); + + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $user->lang['BBCODE_DELETED'], + 'REFRESH_DATA' => array( + 'time' => 3 + ) + )); + } } else { @@ -288,22 +347,57 @@ class acp_bbcodes break; } - $template->assign_vars(array( - 'U_ACTION' => $this->u_action . '&action=add') + $u_action = $this->u_action; + + $template_data = array( + 'U_ACTION' => $this->u_action . '&action=add', ); - $sql = 'SELECT * - FROM ' . BBCODES_TABLE . ' - ORDER BY bbcode_tag'; - $result = $db->sql_query($sql); + $sql_ary = array( + 'SELECT' => 'b.*', + 'FROM' => array(BBCODES_TABLE => 'b'), + 'ORDER_BY' => 'b.bbcode_tag', + ); + + /** + * Modify custom bbcode template data before we display the form + * + * @event core.acp_bbcodes_display_form + * @var string action Type of the action: modify|create + * @var string sql_ary The SQL array to get custom bbcode data + * @var array template_data Array with form template data + * @var string u_action The u_action link + * @since 3.1.0-a3 + */ + $vars = array('action', 'sql_ary', 'template_data', 'u_action'); + extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_display_form', compact($vars))); + + $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); + + $template->assign_vars($template_data); while ($row = $db->sql_fetchrow($result)) { - $template->assign_block_vars('bbcodes', array( + $bbcodes_array = array( 'BBCODE_TAG' => $row['bbcode_tag'], - 'U_EDIT' => $this->u_action . '&action=edit&bbcode=' . $row['bbcode_id'], - 'U_DELETE' => $this->u_action . '&action=delete&bbcode=' . $row['bbcode_id']) + 'U_EDIT' => $u_action . '&action=edit&bbcode=' . $row['bbcode_id'], + 'U_DELETE' => $u_action . '&action=delete&bbcode=' . $row['bbcode_id'], ); + + /** + * Modify display of custom bbcodes in the form + * + * @event core.acp_bbcodes_display_bbcodes + * @var array row Array with current bbcode data + * @var array bbcodes_array Array of bbcodes template data + * @var string u_action The u_action link + * @since 3.1.0-a3 + */ + $vars = array('bbcodes_array', 'row', 'u_action'); + extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_display_bbcodes', compact($vars))); + + $template->assign_block_vars('bbcodes', $bbcodes_array); + } $db->sql_freeresult($result); } @@ -315,18 +409,11 @@ class acp_bbcodes { $bbcode_match = trim($bbcode_match); $bbcode_tpl = trim($bbcode_tpl); - $utf8 = strpos($bbcode_match, 'INTTEXT') !== false; - // make sure we have utf8 support - $utf8_pcre_properties = false; - if (version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) - { - // While this is the proper range of PHP versions, PHP may not be linked with the bundled PCRE lib and instead with an older version - if (@preg_match('/\p{L}/u', 'a') !== false) - { - $utf8_pcre_properties = true; - } - } + // Allow unicode characters for URL|LOCAL_URL|RELATIVE_URL|INTTEXT tokens + $utf8 = preg_match('/(URL|LOCAL_URL|RELATIVE_URL|INTTEXT)/', $bbcode_match); + + $utf8_pcre_properties = phpbb_pcre_utf8_support(); $fp_match = preg_quote($bbcode_match, '!'); $fp_replace = preg_replace('#^\[(.*?)\]#', '[$1:$uid]', $bbcode_match); @@ -480,5 +567,3 @@ class acp_bbcodes ); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 526d8e05da..63e2647f02 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -1,11 +1,17 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. +* +*/ + +/** * @todo add cron intervals to server settings? (database_gc, queue_interval, session_gc, search_gc, cache_gc, warnings_gc) */ @@ -17,9 +23,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_board { var $u_action; @@ -29,7 +32,7 @@ class acp_board { global $db, $user, $auth, $template; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; - global $cache; + global $cache, $phpbb_container, $phpbb_dispatcher; $user->add_lang('acp/board'); @@ -54,19 +57,24 @@ class acp_board 'legend1' => 'ACP_BOARD_SETTINGS', 'sitename' => array('lang' => 'SITE_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false), 'site_desc' => array('lang' => 'SITE_DESC', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false), + 'site_home_url' => array('lang' => 'SITE_HOME_URL', 'validate' => 'string', 'type' => 'url:40:255', 'explain' => true), + 'site_home_text' => array('lang' => 'SITE_HOME_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true), + 'board_index_text' => array('lang' => 'BOARD_INDEX_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true), 'board_disable' => array('lang' => 'DISABLE_BOARD', 'validate' => 'bool', 'type' => 'custom', 'method' => 'board_disable', 'explain' => true), 'board_disable_msg' => false, 'default_lang' => array('lang' => 'DEFAULT_LANGUAGE', 'validate' => 'lang', 'type' => 'select', 'function' => 'language_select', 'params' => array('{CONFIG_VALUE}'), 'explain' => false), 'default_dateformat' => array('lang' => 'DEFAULT_DATE_FORMAT', 'validate' => 'string', 'type' => 'custom', 'method' => 'dateformat_select', 'explain' => true), - 'board_timezone' => array('lang' => 'SYSTEM_TIMEZONE', 'validate' => 'string', 'type' => 'select', 'function' => 'tz_select', 'params' => array('{CONFIG_VALUE}', 1), 'explain' => true), - 'board_dst' => array('lang' => 'SYSTEM_DST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'default_style' => array('lang' => 'DEFAULT_STYLE', 'validate' => 'int', 'type' => 'select', 'function' => 'style_select', 'params' => array('{CONFIG_VALUE}', false), 'explain' => false), + 'board_timezone' => array('lang' => 'SYSTEM_TIMEZONE', 'validate' => 'timezone', 'type' => 'custom', 'method' => 'timezone_select', 'explain' => true), + + 'legend2' => 'BOARD_STYLE', + 'default_style' => array('lang' => 'DEFAULT_STYLE', 'validate' => 'int', 'type' => 'select', 'function' => 'style_select', 'params' => array('{CONFIG_VALUE}', false), 'explain' => true), + 'guest_style' => array('lang' => 'GUEST_STYLE', 'validate' => 'int', 'type' => 'select', 'function' => 'style_select', 'params' => array($this->guest_style_get(), false), 'explain' => true), 'override_user_style' => array('lang' => 'OVERRIDE_STYLE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'legend2' => 'WARNINGS', - 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int', 'type' => 'text:3:4', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), + 'legend3' => 'WARNINGS', + 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - 'legend3' => 'ACP_SUBMIT_CHANGES', + 'legend4' => 'ACP_SUBMIT_CHANGES', ) ); break; @@ -89,6 +97,7 @@ class acp_board 'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_birthdays' => array('lang' => 'ALLOW_BIRTHDAYS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'display_last_subject' => array('lang' => 'DISPLAY_LAST_SUBJECT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_quick_reply' => array('lang' => 'ALLOW_QUICK_REPLY', 'validate' => 'bool', 'type' => 'custom', 'method' => 'quick_reply', 'explain' => true), 'legend2' => 'ACP_LOAD_SETTINGS', @@ -96,6 +105,7 @@ class acp_board 'load_moderators' => array('lang' => 'YES_MODERATORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_jumpbox' => array('lang' => 'YES_JUMPBOX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'load_cpf_pm' => array('lang' => 'LOAD_CPF_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), @@ -105,28 +115,43 @@ class acp_board break; case 'avatar': + $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); + $avatar_drivers = $phpbb_avatar_manager->get_all_drivers(); + + $avatar_vars = array(); + foreach ($avatar_drivers as $current_driver) + { + $driver = $phpbb_avatar_manager->get_driver($current_driver, false); + + /* + * First grab the settings for enabling/disabling the avatar + * driver and afterwards grab additional settings the driver + * might have. + */ + $avatar_vars += $phpbb_avatar_manager->get_avatar_settings($driver); + $avatar_vars += $driver->prepare_form_acp($user); + } + $display_vars = array( 'title' => 'ACP_AVATAR_SETTINGS', 'vars' => array( 'legend1' => 'ACP_AVATAR_SETTINGS', - 'avatar_min_width' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'avatar_min_height' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'avatar_max_width' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), - 'avatar_max_height' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), + 'avatar_min_width' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), + 'avatar_min_height' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), + 'avatar_max_width' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), + 'avatar_max_height' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false), 'allow_avatar' => array('lang' => 'ALLOW_AVATARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_avatar_local' => array('lang' => 'ALLOW_LOCAL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_avatar_remote' => array('lang' => 'ALLOW_REMOTE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_avatar_upload' => array('lang' => 'ALLOW_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'text:4:10', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), - 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), - 'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true) + 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), ) ); + + if (!empty($avatar_vars)) + { + $display_vars['vars'] += $avatar_vars; + } break; case 'message': @@ -136,11 +161,11 @@ class acp_board 'vars' => array( 'legend1' => 'GENERAL_SETTINGS', 'allow_privmsg' => array('lang' => 'BOARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true), - 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true), + 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), 'full_folder_action' => array('lang' => 'FULL_FOLDER_ACTION', 'validate' => 'int', 'type' => 'select', 'method' => 'full_folder_select', 'explain' => true), - 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'pm_max_recipients' => array('lang' => 'PM_MAX_RECIPIENTS', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true), + 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), + 'pm_max_recipients' => array('lang' => 'PM_MAX_RECIPIENTS', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), 'legend2' => 'GENERAL_OPTIONS', 'allow_mass_pm' => array('lang' => 'ALLOW_MASS_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), @@ -177,24 +202,24 @@ class acp_board 'legend2' => 'POSTING', 'bump_type' => false, - 'edit_time' => array('lang' => 'EDIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'delete_time' => array('lang' => 'DELETE_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), + 'edit_time' => array('lang' => 'EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), + 'delete_time' => array('lang' => 'DELETE_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), 'display_last_edited' => array('lang' => 'DISPLAY_LAST_EDITED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'validate' => 'int:0', 'type' => 'text:3:10', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), + 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'validate' => 'int:0:9999999999', 'type' => 'number:0:9999999999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), 'bump_interval' => array('lang' => 'BUMP_INTERVAL', 'validate' => 'int:0', 'type' => 'custom', 'method' => 'bump_interval', 'explain' => true), - 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'validate' => 'int:1', 'type' => 'text:3:4', 'explain' => false), - 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'validate' => 'int:1', 'type' => 'text:3:4', 'explain' => false), - 'smilies_per_page' => array('lang' => 'SMILIES_PER_PAGE', 'validate' => 'int:1', 'type' => 'text:3:4', 'explain' => false), - 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'validate' => 'int:0', 'type' => 'text:3:4', 'explain' => true), - 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'validate' => 'int:2:127', 'type' => 'text:4:4', 'explain' => false), - 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:6', 'explain' => true), - 'min_post_chars' => array('lang' => 'MIN_CHAR_LIMIT', 'validate' => 'int:1', 'type' => 'text:4:6', 'explain' => true), - 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true), - 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true), - 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' %'), - 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true), - 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false), + 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false), + 'smilies_per_page' => array('lang' => 'SMILIES_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false), + 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'validate' => 'int:2:127', 'type' => 'number:2:127', 'explain' => false), + 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'validate' => 'int:0:999999', 'type' => 'number:0:999999', 'explain' => true), + 'min_post_chars' => array('lang' => 'MIN_CHAR_LIMIT', 'validate' => 'int:1:999999', 'type' => 'number:1:999999', 'explain' => true), + 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'), + 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), 'legend3' => 'ACP_SUBMIT_CHANGES', ) @@ -214,12 +239,12 @@ class acp_board 'allow_sig_links' => array('lang' => 'ALLOW_SIG_LINKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend2' => 'GENERAL_SETTINGS', - 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true), - 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true), - 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' %'), - 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true), - 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), - 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'), + 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), 'legend3' => 'ACP_SUBMIT_CHANGES', ) @@ -235,20 +260,20 @@ class acp_board 'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,), 'require_activation' => array('lang' => 'ACC_ACTIVATION', 'validate' => 'int', 'type' => 'select', 'method' => 'select_acc_activation', 'explain' => true), - 'new_member_post_limit' => array('lang' => 'NEW_MEMBER_POST_LIMIT', 'validate' => 'int:0:255', 'type' => 'text:4:4', 'explain' => true, 'append' => ' ' . $user->lang['POSTS']), + 'new_member_post_limit' => array('lang' => 'NEW_MEMBER_POST_LIMIT', 'validate' => 'int:0:255', 'type' => 'number:0:255', 'explain' => true, 'append' => ' ' . $user->lang['POSTS']), 'new_member_group_default'=> array('lang' => 'NEW_MEMBER_GROUP_DEFAULT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'min_name_chars' => array('lang' => 'USERNAME_LENGTH', 'validate' => 'int:1', 'type' => 'custom:5:180', 'method' => 'username_length', 'explain' => true), 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), 'allow_name_chars' => array('lang' => 'USERNAME_CHARS', 'validate' => 'string', 'type' => 'select', 'method' => 'select_username_chars', 'explain' => true), 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), - 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), + 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), 'legend2' => 'GENERAL_OPTIONS', 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'allow_emailreuse' => array('lang' => 'ALLOW_EMAIL_REUSE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'enable_confirm' => array('lang' => 'VISUAL_CONFIRM_REG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true), - 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true), + 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true), + 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), 'legend3' => 'COPPA', 'coppa_enable' => array('lang' => 'ENABLE_COPPA', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), @@ -270,13 +295,13 @@ class acp_board 'feed_http_auth' => array('lang' => 'ACP_FEED_HTTP_AUTH', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), 'legend2' => 'ACP_FEED_POST_BASED', - 'feed_limit_post' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => true), + 'feed_limit_post' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true), 'feed_overall' => array('lang' => 'ACP_FEED_OVERALL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'feed_forum' => array('lang' => 'ACP_FEED_FORUM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'feed_topic' => array('lang' => 'ACP_FEED_TOPIC', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'legend3' => 'ACP_FEED_TOPIC_BASED', - 'feed_limit_topic' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => true), + 'feed_limit_topic' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true), 'feed_topics_new' => array('lang' => 'ACP_FEED_TOPICS_NEW', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'feed_topics_active' => array('lang' => 'ACP_FEED_TOPICS_ACTIVE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'feed_news_id' => array('lang' => 'ACP_FEED_NEWS', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_news_forums', 'explain' => true), @@ -296,7 +321,7 @@ class acp_board 'cookie_domain' => array('lang' => 'COOKIE_DOMAIN', 'validate' => 'string', 'type' => 'text::255', 'explain' => false), 'cookie_name' => array('lang' => 'COOKIE_NAME', 'validate' => 'string', 'type' => 'text::16', 'explain' => false), 'cookie_path' => array('lang' => 'COOKIE_PATH', 'validate' => 'string', 'type' => 'text::255', 'explain' => false), - 'cookie_secure' => array('lang' => 'COOKIE_SECURE', 'validate' => 'bool', 'type' => 'radio:disabled_enabled', 'explain' => true) + 'cookie_secure' => array('lang' => 'COOKIE_SECURE', 'validate' => 'bool', 'type' => 'radio:disabled_enabled', 'explain' => true), ) ); break; @@ -306,12 +331,14 @@ class acp_board 'title' => 'ACP_LOAD_SETTINGS', 'vars' => array( 'legend1' => 'GENERAL_SETTINGS', - 'limit_load' => array('lang' => 'LIMIT_LOAD', 'validate' => 'string', 'type' => 'text:4:4', 'explain' => true), - 'session_length' => array('lang' => 'SESSION_LENGTH', 'validate' => 'int:60', 'type' => 'text:5:10', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), - 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true), - 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int:0', 'type' => 'text:4:3', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), + 'limit_load' => array('lang' => 'LIMIT_LOAD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'session_length' => array('lang' => 'SESSION_LENGTH', 'validate' => 'int:60:9999999999', 'type' => 'number:60:9999999999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), + 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true), + 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), + 'read_notification_expire_days' => array('lang' => 'READ_NOTIFICATION_EXPIRE_DAYS', 'validate' => 'int:0', 'type' => 'number:0', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), 'legend2' => 'GENERAL_OPTIONS', + 'load_notifications' => array('lang' => 'LOAD_NOTIFICATIONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'load_db_track' => array('lang' => 'YES_POST_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'load_db_lastread' => array('lang' => 'YES_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'load_anon_lastread' => array('lang' => 'YES_ANON_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), @@ -323,10 +350,13 @@ class acp_board 'load_moderators' => array('lang' => 'YES_MODERATORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_jumpbox' => array('lang' => 'YES_JUMPBOX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_user_activity' => array('lang' => 'LOAD_USER_ACTIVITY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'load_tplcompile' => array('lang' => 'RECOMPILE_STYLES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'load_tplcompile' => array('lang' => 'RECOMPILE_STYLES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_cdn' => array('lang' => 'ALLOW_CDN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_live_searches' => array('lang' => 'ALLOW_LIVE_SEARCHES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend3' => 'CUSTOM_PROFILE_FIELDS', 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'load_cpf_pm' => array('lang' => 'LOAD_CPF_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), @@ -340,7 +370,7 @@ class acp_board 'title' => 'ACP_AUTH_SETTINGS', 'vars' => array( 'legend1' => 'ACP_AUTH_SETTINGS', - 'auth_method' => array('lang' => 'AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'select_auth_method', 'explain' => false) + 'auth_method' => array('lang' => 'AUTH_METHOD', 'validate' => 'string', 'type' => 'select:1:toggable', 'method' => 'select_auth_method', 'explain' => false), ) ); break; @@ -351,8 +381,10 @@ class acp_board 'vars' => array( 'legend1' => 'ACP_SERVER_SETTINGS', 'gzip_compress' => array('lang' => 'ENABLE_GZIP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'use_system_cron' => array('lang' => 'USE_SYSTEM_CRON', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend2' => 'PATH_SETTINGS', + 'enable_mod_rewrite' => array('lang' => 'MOD_REWRITE_ENABLE', 'validate' => 'bool', 'type' => 'custom', 'method' => 'enable_mod_rewrite', 'explain' => true), 'smilies_path' => array('lang' => 'SMILIES_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), 'icons_path' => array('lang' => 'ICONS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), 'upload_icons_path' => array('lang' => 'UPLOAD_ICONS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), @@ -362,7 +394,7 @@ class acp_board 'force_server_vars' => array('lang' => 'FORCE_SERVER_VARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'server_protocol' => array('lang' => 'SERVER_PROTOCOL', 'validate' => 'string', 'type' => 'text:10:10', 'explain' => true), 'server_name' => array('lang' => 'SERVER_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true), - 'server_port' => array('lang' => 'SERVER_PORT', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true), + 'server_port' => array('lang' => 'SERVER_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), 'script_path' => array('lang' => 'SCRIPT_PATH', 'validate' => 'script_path', 'type' => 'text::255', 'explain' => true), 'legend4' => 'ACP_SUBMIT_CHANGES', @@ -376,23 +408,24 @@ class acp_board 'vars' => array( 'legend1' => 'ACP_SECURITY_SETTINGS', 'allow_autologin' => array('lang' => 'ALLOW_AUTOLOGIN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), + 'allow_password_reset' => array('lang' => 'ALLOW_PASSWORD_RESET', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), 'ip_check' => array('lang' => 'IP_VALID', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_ip_check', 'explain' => true), 'browser_check' => array('lang' => 'BROWSER_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'forwarded_for_check' => array('lang' => 'FORWARDED_FOR_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'referer_validation' => array('lang' => 'REFERER_VALID', 'validate' => 'int:0:3','type' => 'custom', 'method' => 'select_ref_check', 'explain' => true), + 'referer_validation' => array('lang' => 'REFERRER_VALID', 'validate' => 'int:0:3','type' => 'custom', 'method' => 'select_ref_check', 'explain' => true), 'check_dnsbl' => array('lang' => 'CHECK_DNSBL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'email_check_mx' => array('lang' => 'EMAIL_CHECK_MX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,), 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), - 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), - 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true), - 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true), - 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), + 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), + 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true), + 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true), + 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), 'ip_login_limit_use_forwarded' => array('lang' => 'IP_LOGIN_LIMIT_USE_FORWARDED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), + 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1:99999', 'type' => 'number:-1:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), 'form_token_sid_guests' => array('lang' => 'FORM_SID_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), ) @@ -407,16 +440,17 @@ class acp_board 'email_enable' => array('lang' => 'ENABLE_EMAIL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), 'board_email_form' => array('lang' => 'BOARD_EMAIL_FORM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), 'email_function_name' => array('lang' => 'EMAIL_FUNCTION_NAME', 'validate' => 'string', 'type' => 'text:20:50', 'explain' => true), - 'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true), - 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'email', 'type' => 'text:25:100', 'explain' => true), - 'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'email', 'type' => 'text:25:100', 'explain' => true), + 'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int:0', 'type' => 'number:0:99999', 'explain' => true), + 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'email', 'type' => 'email:25:100', 'explain' => true), + 'board_contact_name' => array('lang' => 'CONTACT_EMAIL_NAME', 'validate' => 'string', 'type' => 'text:25:50', 'explain' => true), + 'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'email', 'type' => 'email:25:100', 'explain' => true), 'board_email_sig' => array('lang' => 'EMAIL_SIG', 'validate' => 'string', 'type' => 'textarea:5:30', 'explain' => true), 'board_hide_emails' => array('lang' => 'BOARD_HIDE_EMAILS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend2' => 'SMTP_SETTINGS', 'smtp_delivery' => array('lang' => 'USE_SMTP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'smtp_host' => array('lang' => 'SMTP_SERVER', 'validate' => 'string', 'type' => 'text:25:50', 'explain' => false), - 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0', 'type' => 'text:4:5', 'explain' => true), + 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true), 'smtp_auth_method' => array('lang' => 'SMTP_AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true), 'smtp_username' => array('lang' => 'SMTP_USERNAME', 'validate' => 'string', 'type' => 'text:25:255', 'explain' => true), 'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true), @@ -431,6 +465,18 @@ class acp_board break; } + /** + * Event to add and/or modify acp_board configurations + * + * @event core.acp_board_config_edit_add + * @var array display_vars Array of config values to display and process + * @var string mode Mode of the config page we are displaying + * @var boolean submit Do we display the form or process the submission + * @since 3.1.0-a4 + */ + $vars = array('display_vars', 'mode', 'submit'); + extract($phpbb_dispatcher->trigger_event('core.acp_board_config_edit_add', compact($vars))); + if (isset($display_vars['lang'])) { $user->add_lang($display_vars['lang']); @@ -440,7 +486,7 @@ class acp_board $cfg_array = (isset($_REQUEST['config'])) ? utf8_normalize_nfc(request_var('config', array('' => ''), true)) : $this->new_config; $error = array(); - // We validate the complete config if whished + // We validate the complete config if wished validate_config_vars($display_vars['vars'], $cfg_array, $error); if ($submit && !check_form_key($form_key)) @@ -466,6 +512,14 @@ class acp_board continue; } + if ($config_name == 'guest_style') + { + if (isset($cfg_array[$config_name])) { + $this->guest_style_set($cfg_array[$config_name]); + } + continue; + } + $this->new_config[$config_name] = $config_value = $cfg_array[$config_name]; if ($config_name == 'email_function_name') @@ -499,84 +553,54 @@ class acp_board if ($mode == 'auth') { // Retrieve a list of auth plugins and check their config values - $auth_plugins = array(); - - $dp = @opendir($phpbb_root_path . 'includes/auth'); + $auth_providers = $phpbb_container->get('auth.provider_collection'); - if ($dp) + $updated_auth_settings = false; + $old_auth_config = array(); + foreach ($auth_providers as $provider) { - while (($file = readdir($dp)) !== false) + if ($fields = $provider->acp()) { - if (preg_match('#^auth_(.*?)\.' . $phpEx . '$#', $file)) + // Check if we need to create config fields for this plugin and save config when submit was pressed + foreach ($fields as $field) { - $auth_plugins[] = basename(preg_replace('#^auth_(.*?)\.' . $phpEx . '$#', '\1', $file)); - } - } - closedir($dp); + if (!isset($config[$field])) + { + set_config($field, ''); + } - sort($auth_plugins); - } + if (!isset($cfg_array[$field]) || strpos($field, 'legend') !== false) + { + continue; + } - $updated_auth_settings = false; - $old_auth_config = array(); - foreach ($auth_plugins as $method) - { - if ($method && file_exists($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx)) - { - include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); + $old_auth_config[$field] = $this->new_config[$field]; + $config_value = $cfg_array[$field]; + $this->new_config[$field] = $config_value; - $method = 'acp_' . $method; - if (function_exists($method)) - { - if ($fields = $method($this->new_config)) + if ($submit) { - // Check if we need to create config fields for this plugin and save config when submit was pressed - foreach ($fields['config'] as $field) - { - if (!isset($config[$field])) - { - set_config($field, ''); - } - - if (!isset($cfg_array[$field]) || strpos($field, 'legend') !== false) - { - continue; - } - - $old_auth_config[$field] = $this->new_config[$field]; - $config_value = $cfg_array[$field]; - $this->new_config[$field] = $config_value; - - if ($submit) - { - $updated_auth_settings = true; - set_config($field, $config_value); - } - } + $updated_auth_settings = true; + set_config($field, $config_value); } - unset($fields); } } + unset($fields); } if ($submit && (($cfg_array['auth_method'] != $this->new_config['auth_method']) || $updated_auth_settings)) { $method = basename($cfg_array['auth_method']); - if ($method && in_array($method, $auth_plugins)) + if (array_key_exists('auth.provider.' . $method, $auth_providers)) { - include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); - - $method = 'init_' . $method; - if (function_exists($method)) + $provider = $auth_providers['auth.provider.' . $method]; + if ($error = $provider->init()) { - if ($error = $method()) + foreach ($old_auth_config as $config_name => $config_value) { - foreach ($old_auth_config as $config_name => $config_value) - { - set_config($config_name, $config_value); - } - trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING); + set_config($config_name, $config_value); } + trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING); } set_config('auth_method', basename($cfg_array['auth_method'])); } @@ -591,7 +615,15 @@ class acp_board { add_log('admin', 'LOG_CONFIG_' . strtoupper($mode)); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + $message = $user->lang('CONFIG_UPDATED'); + $message_type = E_USER_NOTICE; + if (!$config['email_enable'] && in_array($mode, array('email', 'registration')) && + in_array($config['require_activation'], array(USER_ACTIVATION_SELF, USER_ACTIVATION_ADMIN))) + { + $message .= '<br /><br />' . $user->lang('ACC_ACTIVATION_WARNING'); + $message_type = E_USER_WARNING; + } + trigger_error($message . adm_back_link($this->u_action), $message_type); } $this->tpl_name = 'acp_board'; @@ -660,23 +692,22 @@ class acp_board { $template->assign_var('S_AUTH', true); - foreach ($auth_plugins as $method) + foreach ($auth_providers as $provider) { - if ($method && file_exists($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx)) + $auth_tpl = $provider->get_acp_template($this->new_config); + if ($auth_tpl) { - $method = 'acp_' . $method; - if (function_exists($method)) + if (array_key_exists('BLOCK_VAR_NAME', $auth_tpl)) { - $fields = $method($this->new_config); - - if ($fields['tpl']) + foreach ($auth_tpl['BLOCK_VARS'] as $block_vars) { - $template->assign_block_vars('auth_tpl', array( - 'TPL' => $fields['tpl']) - ); + $template->assign_block_vars($auth_tpl['BLOCK_VAR_NAME'], $block_vars); } - unset($fields); } + $template->assign_vars($auth_tpl['TEMPLATE_VARS']); + $template->assign_block_vars('auth_tpl', array( + 'TEMPLATE_FILE' => $auth_tpl['TEMPLATE_FILE'], + )); } } } @@ -687,25 +718,19 @@ class acp_board */ function select_auth_method($selected_method, $key = '') { - global $phpbb_root_path, $phpEx; + global $phpbb_root_path, $phpEx, $phpbb_container; $auth_plugins = array(); + $auth_providers = $phpbb_container->get('auth.provider_collection'); - $dp = @opendir($phpbb_root_path . 'includes/auth'); - - if (!$dp) + foreach ($auth_providers as $key => $value) { - return ''; - } - - while (($file = readdir($dp)) !== false) - { - if (preg_match('#^auth_(.*?)\.' . $phpEx . '$#', $file)) + if (!($value instanceof \phpbb\auth\provider\provider_interface)) { - $auth_plugins[] = preg_replace('#^auth_(.*?)\.' . $phpEx . '$#', '\1', $file); + continue; } + $auth_plugins[] = str_replace('auth.provider.', '', $key); } - closedir($dp); sort($auth_plugins); @@ -713,7 +738,7 @@ class acp_board foreach ($auth_plugins as $method) { $selected = ($selected_method == $method) ? ' selected="selected"' : ''; - $auth_select .= '<option value="' . $method . '"' . $selected . '>' . ucfirst($method) . '</option>'; + $auth_select .= "<option value=\"$method\"$selected data-toggle-setting=\"#auth_{$method}_settings\">" . ucfirst($method) . '</option>'; } return $auth_select; @@ -775,20 +800,19 @@ class acp_board global $user, $config; $act_ary = array( - 'ACC_DISABLE' => USER_ACTIVATION_DISABLE, - 'ACC_NONE' => USER_ACTIVATION_NONE, + 'ACC_DISABLE' => array(true, USER_ACTIVATION_DISABLE), + 'ACC_NONE' => array(true, USER_ACTIVATION_NONE), + 'ACC_USER' => array($config['email_enable'], USER_ACTIVATION_SELF), + 'ACC_ADMIN' => array($config['email_enable'], USER_ACTIVATION_ADMIN), ); - if ($config['email_enable']) - { - $act_ary['ACC_USER'] = USER_ACTIVATION_SELF; - $act_ary['ACC_ADMIN'] = USER_ACTIVATION_ADMIN; - } - $act_options = ''; - foreach ($act_ary as $key => $value) + $act_options = ''; + foreach ($act_ary as $key => $data) { + list($available, $value) = $data; $selected = ($selected_value == $value) ? ' selected="selected"' : ''; - $act_options .= '<option value="' . $value . '"' . $selected . '>' . $user->lang[$key] . '</option>'; + $class = (!$available) ? ' class="disabled-option"' : ''; + $act_options .= '<option value="' . $value . '"' . $selected . $class . '>' . $user->lang($key) . '</option>'; } return $act_options; @@ -801,7 +825,7 @@ class acp_board { global $user; - return '<input id="' . $key . '" type="text" size="3" maxlength="3" name="config[min_name_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . ' <input type="text" size="3" maxlength="3" name="config[max_name_chars]" value="' . $this->new_config['max_name_chars'] . '" /> ' . $user->lang['MAX_CHARS']; + return '<input id="' . $key . '" type="number" size="3" maxlength="3" min="1" max="999" name="config[min_name_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . ' <input type="number" size="3" maxlength="3" min="8" max="180" name="config[max_name_chars]" value="' . $this->new_config['max_name_chars'] . '" /> ' . $user->lang['MAX_CHARS']; } /** @@ -829,7 +853,7 @@ class acp_board { global $user; - return '<input id="' . $key . '" type="text" size="3" maxlength="3" name="config[min_pass_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . ' <input type="text" size="3" maxlength="3" name="config[max_pass_chars]" value="' . $this->new_config['max_pass_chars'] . '" /> ' . $user->lang['MAX_CHARS']; + return '<input id="' . $key . '" type="number" size="3" maxlength="3" min="1" max="999" name="config[min_pass_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . ' <input type="number" size="3" maxlength="3" min="8" max="255" name="config[max_pass_chars]" value="' . $this->new_config['max_pass_chars'] . '" /> ' . $user->lang['MAX_CHARS']; } /** @@ -893,6 +917,50 @@ class acp_board '<br /><br /><input class="button2" type="submit" id="' . $key . '_enable" name="' . $key . '_enable" value="' . $user->lang['ALLOW_QUICK_REPLY_BUTTON'] . '" />'; } + /** + * Select guest timezone + */ + function timezone_select($value, $key) + { + global $template, $user; + + $timezone_select = phpbb_timezone_select($template, $user, $value, true); + + return '<select name="config[' . $key . ']" id="' . $key . '">' . $timezone_select . '</select>'; + } + + /** + * Get guest style + */ + public function guest_style_get() + { + global $db; + + $sql = 'SELECT user_style + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . ANONYMOUS; + $result = $db->sql_query($sql); + + $style = (int) $db->sql_fetchfield('user_style'); + $db->sql_freeresult($result); + + return $style; + } + + /** + * Set guest style + * + * @param int $style_id The style ID + */ + public function guest_style_set($style_id) + { + global $db; + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_style = ' . (int) $style_id . ' + WHERE user_id = ' . ANONYMOUS; + $db->sql_query($sql); + } /** * Select default dateformat @@ -903,10 +971,14 @@ class acp_board // Let the format_date function operate with the acp values $old_tz = $user->timezone; - $old_dst = $user->dst; - - $user->timezone = $config['board_timezone'] * 3600; - $user->dst = $config['board_dst'] * 3600; + try + { + $user->timezone = new DateTimeZone($config['board_timezone']); + } + catch (\Exception $e) + { + // If the board timezone is invalid, we just use the users timezone. + } $dateformat_options = ''; @@ -926,7 +998,6 @@ class acp_board // Reset users date options $user->timezone = $old_tz; - $user->dst = $old_dst; return "<select name=\"dateoptions\" id=\"dateoptions\" onchange=\"if (this.value == 'custom') { document.getElementById('" . addslashes($key) . "').value = '" . addslashes($value) . "'; } else { document.getElementById('" . addslashes($key) . "').value = this.value; }\">$dateformat_options</select> <input type=\"text\" name=\"config[$key]\" id=\"$key\" value=\"$value\" maxlength=\"30\" />"; @@ -1000,6 +1071,51 @@ class acp_board $cache->destroy('sql', FORUMS_TABLE); } -} + /** + * Option to enable/disable removal of 'app.php' from URLs + * + * Note that if mod_rewrite is on, URLs without app.php will still work, + * but any paths generated by the controller helper url() method will not + * contain app.php. + * + * @param int $value The current config value + * @param string $key The config key + * @return string The HTML for the form field + */ + function enable_mod_rewrite($value, $key) + { + global $user, $config; -?>
\ No newline at end of file + // Determine whether mod_rewrite is enabled on the server + // NOTE: This only works on Apache servers on which PHP is NOT + // installed as CGI. In that case, there is no way for PHP to + // determine whether or not the Apache module is enabled. + // + // To be clear on the value of $mod_rewite: + // null = Cannot determine whether or not the server has mod_rewrite + // enabled + // false = Can determine that the server does NOT have mod_rewrite + // enabled + // true = Can determine that the server DOES have mod_rewrite_enabled + $mod_rewrite = null; + if (function_exists('apache_get_modules')) + { + $mod_rewrite = (bool) in_array('mod_rewrite', apache_get_modules()); + } + + // If $message is false, mod_rewrite is enabled. + // Otherwise, it is not and we need to: + // 1) disable the form field + // 2) make sure the config value is set to 0 + // 3) append the message to the return + $value = ($mod_rewrite === false) ? 0 : $value; + $message = $mod_rewrite === null ? 'MOD_REWRITE_INFORMATION_UNAVAILABLE' : ($mod_rewrite === false ? 'MOD_REWRITE_DISABLED' : false); + + // Let's do some friendly HTML injection if we want to disable the + // form field because h_radio() has no pretty way of doing so + $field_name = 'config[enable_mod_rewrite]' . ($message === 'MOD_REWRITE_DISABLED' ? '" disabled="disabled' : ''); + + return h_radio($field_name, array(1 => 'YES', 0 => 'NO'), $value) . + ($message !== false ? '<br /><span>' . $user->lang($message) . '</span>' : ''); + } +} diff --git a/phpBB/includes/acp/acp_bots.php b/phpBB/includes/acp/acp_bots.php index d08cabb062..1ea320e674 100644 --- a/phpBB/includes/acp/acp_bots.php +++ b/phpBB/includes/acp/acp_bots.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,16 +19,13 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_bots { var $u_action; function main($id, $mode) { - global $config, $db, $user, $auth, $template, $cache; + global $config, $db, $user, $auth, $template, $cache, $request; global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix; $action = request_var('action', ''); @@ -158,7 +158,7 @@ class acp_bots { $error[] = $user->lang['ERR_BOT_NO_MATCHES']; } - + if ($bot_row['bot_ip'] && !preg_match('#^[\d\.,:]+$#', $bot_row['bot_ip'])) { if (!$ip_list = gethostbynamel($bot_row['bot_ip'])) @@ -177,7 +177,7 @@ class acp_bots { $error[] = $user->lang['ERR_BOT_AGENT_MATCHES_UA']; } - + $bot_name = false; if ($bot_id) { @@ -202,7 +202,7 @@ class acp_bots { $error[] = $user->lang['BOT_NAME_TAKEN']; } - + if (!sizeof($error)) { // New bot? Create a new user and group entry @@ -220,7 +220,6 @@ class acp_bots { trigger_error($user->lang['NO_BOT_GROUP'] . adm_back_link($this->u_action . "&id=$bot_id&action=$action"), E_USER_WARNING); } - $user_id = user_add(array( 'user_type' => (int) USER_IGNORE, @@ -234,7 +233,7 @@ class acp_bots 'user_style' => (int) $bot_row['bot_style'], 'user_allow_massemail' => 0, )); - + $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $db->sql_build_array('INSERT', array( 'user_id' => (int) $user_id, 'bot_name' => (string) $bot_row['bot_name'], @@ -243,7 +242,7 @@ class acp_bots 'bot_ip' => (string) $bot_row['bot_ip']) ); $db->sql_query($sql); - + $log = 'ADDED'; } else if ($bot_id) @@ -290,12 +289,12 @@ class acp_bots $log = 'UPDATED'; } - + $cache->destroy('_bots'); - + add_log('admin', 'LOG_BOT_' . $log, $bot_row['bot_name']); trigger_error($user->lang['BOT_' . $log] . adm_back_link($this->u_action)); - + } } else if ($bot_id) @@ -336,11 +335,11 @@ class acp_bots 'U_ACTION' => $this->u_action . "&id=$bot_id&action=$action", 'U_BACK' => $this->u_action, 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '', - + 'BOT_NAME' => $bot_row['bot_name'], 'BOT_IP' => $bot_row['bot_ip'], 'BOT_AGENT' => $bot_row['bot_agent'], - + 'S_EDIT_BOT' => true, 'S_ACTIVE_OPTIONS' => $s_active_options, 'S_STYLE_OPTIONS' => $style_select, @@ -354,6 +353,14 @@ class acp_bots break; } + if ($request->is_ajax() && ($action == 'activate' || $action == 'deactivate')) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'text' => $user->lang['BOT_' . (($action == 'activate') ? 'DE' : '') . 'ACTIVATE'], + )); + } + $s_options = ''; $_options = array('activate' => 'BOT_ACTIVATE', 'deactivate' => 'BOT_DEACTIVATE', 'delete' => 'DELETE'); foreach ($_options as $value => $lang) @@ -390,7 +397,7 @@ class acp_bots } $db->sql_freeresult($result); } - + /** * Validate bot name against username table */ @@ -410,9 +417,7 @@ class acp_bots $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - + return ($row) ? false : true; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_captcha.php b/phpBB/includes/acp/acp_captcha.php index bfec7c27d8..fa8d8fb6a9 100644 --- a/phpBB/includes/acp/acp_captcha.php +++ b/phpBB/includes/acp/acp_captcha.php @@ -1,10 +1,14 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. +* */ /** @@ -15,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_captcha { var $u_action; @@ -25,18 +26,17 @@ class acp_captcha function main($id, $mode) { global $db, $user, $auth, $template; - global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_container; $user->add_lang('acp/board'); - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - $captchas = phpbb_captcha_factory::get_captcha_types(); + $factory = $phpbb_container->get('captcha.factory'); + $captchas = $factory->get_captcha_types(); $selected = request_var('select_captcha', $config['captcha_plugin']); $selected = (isset($captchas['available'][$selected]) || isset($captchas['unavailable'][$selected])) ? $selected : $config['captcha_plugin']; $configure = request_var('configure', false); - // Oh, they are just here for the view if (isset($_GET['captcha_demo'])) { @@ -46,7 +46,7 @@ class acp_captcha // Delegate if ($configure) { - $config_captcha =& phpbb_captcha_factory::get_instance($selected); + $config_captcha = $factory->get_instance($selected); $config_captcha->acp_page($id, $this); } else @@ -78,11 +78,11 @@ class acp_captcha // sanity check if (isset($captchas['available'][$selected])) { - $old_captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $old_captcha = $factory->get_instance($config['captcha_plugin']); $old_captcha->uninstall(); set_config('captcha_plugin', $selected); - $new_captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $new_captcha = $factory->get_instance($config['captcha_plugin']); $new_captcha->install(); add_log('admin', 'LOG_CONFIG_VISUAL'); @@ -104,16 +104,16 @@ class acp_captcha foreach ($captchas['available'] as $value => $title) { $current = ($selected !== false && $value == $selected) ? ' selected="selected"' : ''; - $captcha_select .= '<option value="' . $value . '"' . $current . '>' . $user->lang[$title] . '</option>'; + $captcha_select .= '<option value="' . $value . '"' . $current . '>' . $user->lang($title) . '</option>'; } foreach ($captchas['unavailable'] as $value => $title) { $current = ($selected !== false && $value == $selected) ? ' selected="selected"' : ''; - $captcha_select .= '<option value="' . $value . '"' . $current . ' class="disabled-option">' . $user->lang[$title] . '</option>'; + $captcha_select .= '<option value="' . $value . '"' . $current . ' class="disabled-option">' . $user->lang($title) . '</option>'; } - $demo_captcha =& phpbb_captcha_factory::get_instance($selected); + $demo_captcha = $factory->get_instance($selected); foreach ($config_vars as $config_var => $options) { @@ -136,9 +136,9 @@ class acp_captcha */ function deliver_demo($selected) { - global $db, $user, $config; + global $db, $user, $config, $phpbb_container; - $captcha =& phpbb_captcha_factory::get_instance($selected); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($selected); $captcha->init(CONFIRM_REG); $captcha->execute_demo(); @@ -146,5 +146,3 @@ class acp_captcha exit_handler(); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_contact.php b/phpBB/includes/acp/acp_contact.php new file mode 100644 index 0000000000..4e46df21e0 --- /dev/null +++ b/phpBB/includes/acp/acp_contact.php @@ -0,0 +1,134 @@ +<?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. +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* @package acp +*/ +class acp_contact +{ + public $u_action; + + public function main($id, $mode) + { + global $user, $request, $template; + global $config, $phpbb_root_path, $phpEx, $phpbb_container; + + $user->add_lang(array('acp/board', 'posting')); + + $this->tpl_name = 'acp_contact'; + $this->page_title = 'ACP_CONTACT_SETTINGS'; + $form_name = 'acp_contact'; + add_form_key($form_name); + $error = ''; + + if (!function_exists('display_custom_bbcodes')) + { + include($phpbb_root_path . 'includes/functions_display.' . $phpEx); + } + if (!class_exists('parse_message')) + { + include($phpbb_root_path . 'includes/message_parser.' . $phpEx); + } + + $config_text = $phpbb_container->get('config_text'); + + $contact_admin_data = $config_text->get_array(array( + 'contact_admin_info', + 'contact_admin_info_uid', + 'contact_admin_info_bitfield', + 'contact_admin_info_flags', + )); + + $contact_admin_info = $contact_admin_data['contact_admin_info']; + $contact_admin_info_uid = $contact_admin_data['contact_admin_info_uid']; + $contact_admin_info_bitfield= $contact_admin_data['contact_admin_info_bitfield']; + $contact_admin_info_flags = $contact_admin_data['contact_admin_info_flags']; + + if ($request->is_set_post('submit') || $request->is_set_post('preview')) + { + if (!check_form_key($form_name)) + { + $error = $user->lang('FORM_INVALID'); + } + + $contact_admin_info = $request->variable('contact_admin_info', '', true); + + generate_text_for_storage( + $contact_admin_info, + $contact_admin_info_uid, + $contact_admin_info_bitfield, + $contact_admin_info_flags, + !$request->variable('disable_bbcode', false), + !$request->variable('disable_magic_url', false), + !$request->variable('disable_smilies', false) + ); + + if (empty($error) && $request->is_set_post('submit')) + { + $config->set('contact_admin_form_enable', $request->variable('contact_admin_form_enable', false)); + + $config_text->set_array(array( + 'contact_admin_info' => $contact_admin_info, + 'contact_admin_info_uid' => $contact_admin_info_uid, + 'contact_admin_info_bitfield' => $contact_admin_info_bitfield, + 'contact_admin_info_flags' => $contact_admin_info_flags, + )); + + trigger_error($user->lang['CONTACT_US_INFO_UPDATED'] . adm_back_link($this->u_action)); + } + } + + $contact_admin_info_preview = ''; + if ($request->is_set_post('preview')) + { + $contact_admin_info_preview = generate_text_for_display($contact_admin_info, $contact_admin_info_uid, $contact_admin_info_bitfield, $contact_admin_info_flags); + } + + $contact_admin_edit = generate_text_for_edit($contact_admin_info, $contact_admin_info_uid, $contact_admin_info_flags); + + $template->assign_vars(array( + 'ERRORS' => $error, + 'CONTACT_ENABLED' => $config['contact_admin_form_enable'], + + 'CONTACT_US_INFO' => $contact_admin_edit['text'], + 'CONTACT_US_INFO_PREVIEW' => $contact_admin_info_preview, + + 'S_BBCODE_DISABLE_CHECKED' => !$contact_admin_edit['allow_bbcode'], + 'S_SMILIES_DISABLE_CHECKED' => !$contact_admin_edit['allow_smilies'], + 'S_MAGIC_URL_DISABLE_CHECKED' => !$contact_admin_edit['allow_urls'], + + 'BBCODE_STATUS' => $user->lang('BBCODE_IS_ON', '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>'), + 'SMILIES_STATUS' => $user->lang['SMILIES_ARE_ON'], + 'IMG_STATUS' => $user->lang['IMAGES_ARE_ON'], + 'FLASH_STATUS' => $user->lang['FLASH_IS_ON'], + 'URL_STATUS' => $user->lang['URL_IS_ON'], + + 'S_BBCODE_ALLOWED' => true, + 'S_SMILIES_ALLOWED' => true, + 'S_BBCODE_IMG' => true, + 'S_BBCODE_FLASH' => true, + 'S_LINKS_ALLOWED' => true, + )); + + // Assigning custom bbcodes + display_custom_bbcodes(); + } +} diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index 758cd10434..0c52f82459 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_database { var $db_tools; @@ -29,11 +29,7 @@ class acp_database global $cache, $db, $user, $auth, $template, $table_prefix; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; - if (!class_exists('phpbb_db_tools')) - { - require($phpbb_root_path . 'includes/db/db_tools.' . $phpEx); - } - $this->db_tools = new phpbb_db_tools($db); + $this->db_tools = new \phpbb\db\tools($db); $user->add_lang('acp/database'); @@ -94,34 +90,34 @@ class acp_database $time = time(); $filename = 'backup_' . $time . '_' . unique_id(); - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'mysqli': case 'mysql4': case 'mysql': - $extractor = new mysql_extractor($download, $store, $format, $filename, $time); + $extractor = new mysql_extractor($format, $filename, $time, $download, $store); break; case 'sqlite': - $extractor = new sqlite_extractor($download, $store, $format, $filename, $time); + $extractor = new sqlite_extractor($format, $filename, $time, $download, $store); + break; + + case 'sqlite3': + $extractor = new sqlite3_extractor($format, $filename, $time, $download, $store); break; case 'postgres': - $extractor = new postgres_extractor($download, $store, $format, $filename, $time); + $extractor = new postgres_extractor($format, $filename, $time, $download, $store); break; case 'oracle': - $extractor = new oracle_extractor($download, $store, $format, $filename, $time); + $extractor = new oracle_extractor($format, $filename, $time, $download, $store); break; case 'mssql': case 'mssql_odbc': case 'mssqlnative': - $extractor = new mssql_extractor($download, $store, $format, $filename, $time); - break; - - case 'firebird': - $extractor = new firebird_extractor($download, $store, $format, $filename, $time); + $extractor = new mssql_extractor($format, $filename, $time, $download, $store); break; } @@ -137,10 +133,10 @@ class acp_database else { // We might wanna empty out all that junk :D - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'sqlite': - case 'firebird': + case 'sqlite3': $extractor->flush('DELETE FROM ' . $table_name . ";\n"); break; @@ -273,7 +269,7 @@ class acp_database break; } - header('Pragma: no-cache'); + header('Cache-Control: private, no-cache'); header("Content-Type: $mimetype; name=\"$name\""); header("Content-disposition: attachment; filename=$name"); @@ -324,32 +320,19 @@ class acp_database break; } - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'mysql': case 'mysql4': case 'mysqli': case 'sqlite': + case 'sqlite3': while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false) { $db->sql_query($sql); } break; - case 'firebird': - $delim = ";\n"; - while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false) - { - $query = trim($sql); - if (substr($query, 0, 8) === 'SET TERM') - { - $delim = $query[9] . "\n"; - continue; - } - $db->sql_query($query); - } - break; - case 'postgres': $delim = ";\n"; while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false) @@ -382,10 +365,10 @@ class acp_database { trigger_error($user->lang['RESTORE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING); } - pg_put_line($db->db_connect_id, $sub . "\n"); + pg_put_line($db->get_db_connect_id(), $sub . "\n"); } - pg_put_line($db->db_connect_id, "\\.\n"); - pg_end_copy($db->db_connect_id); + pg_put_line($db->get_db_connect_id(), "\\.\n"); + pg_end_copy($db->get_db_connect_id()); } } break; @@ -478,9 +461,6 @@ class acp_database } } -/** -* @package acp -*/ class base_extractor { var $fh; @@ -493,8 +473,10 @@ class base_extractor var $format; var $run_comp = false; - function base_extractor($download = false, $store = false, $format, $filename, $time) + function base_extractor($format, $filename, $time, $download = false, $store = false) { + global $request; + $this->download = $download; $this->store = $store; $this->time = $time; @@ -528,7 +510,7 @@ class base_extractor if ($download == true) { $name = $filename . $ext; - header('Pragma: no-cache'); + header('Cache-Control: private, no-cache'); header("Content-Type: $mimetype; name=\"$name\""); header("Content-disposition: attachment; filename=$name"); @@ -539,7 +521,7 @@ class base_extractor break; case 'gzip': - if ((isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) && strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'msie') === false) + if (strpos($request->header('Accept-Encoding'), 'gzip') !== false && strpos(strtolower($request->header('User-Agent')), 'msie') === false) { ob_start('ob_gzhandler'); } @@ -622,9 +604,6 @@ class base_extractor } } -/** -* @package acp -*/ class mysql_extractor extends base_extractor { function write_start($table_prefix) @@ -644,7 +623,7 @@ class mysql_extractor extends base_extractor if ($new_extract === null) { - if ($db->sql_layer === 'mysqli' || version_compare($db->sql_server_info(true), '3.23.20', '>=')) + if ($db->get_sql_layer() === 'mysqli' || version_compare($db->sql_server_info(true), '3.23.20', '>=')) { $new_extract = true; } @@ -667,7 +646,7 @@ class mysql_extractor extends base_extractor function write_data($table_name) { global $db; - if ($db->sql_layer === 'mysqli') + if ($db->get_sql_layer() === 'mysqli') { $this->write_data_mysqli($table_name); } @@ -682,7 +661,7 @@ class mysql_extractor extends base_extractor global $db; $sql = "SELECT * FROM $table_name"; - $result = mysqli_query($db->db_connect_id, $sql, MYSQLI_USE_RESULT); + $result = mysqli_query($db->get_db_connect_id(), $sql, MYSQLI_USE_RESULT); if ($result != false) { $fields_cnt = mysqli_num_fields($result); @@ -761,7 +740,7 @@ class mysql_extractor extends base_extractor global $db; $sql = "SELECT * FROM $table_name"; - $result = mysql_unbuffered_query($sql, $db->db_connect_id); + $result = mysql_unbuffered_query($sql, $db->get_db_connect_id()); if ($result != false) { @@ -948,9 +927,6 @@ class mysql_extractor extends base_extractor } } -/** -* @package acp -*/ class sqlite_extractor extends base_extractor { function write_start($prefix) @@ -1016,50 +992,118 @@ class sqlite_extractor extends base_extractor function write_data($table_name) { global $db; - static $proper; - if (is_null($proper)) - { - $proper = version_compare(PHP_VERSION, '5.1.3', '>='); - } + $col_types = sqlite_fetch_column_types($db->get_db_connect_id(), $table_name); - if ($proper) + $sql = "SELECT * + FROM $table_name"; + $result = sqlite_unbuffered_query($db->get_db_connect_id(), $sql); + $rows = sqlite_fetch_all($result, SQLITE_ASSOC); + $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES ('; + foreach ($rows as $row) { - $col_types = sqlite_fetch_column_types($db->db_connect_id, $table_name); + foreach ($row as $column_name => $column_data) + { + if (is_null($column_data)) + { + $row[$column_name] = 'NULL'; + } + else if ($column_data == '') + { + $row[$column_name] = "''"; + } + else if (strpos($col_types[$column_name], 'text') !== false || strpos($col_types[$column_name], 'char') !== false || strpos($col_types[$column_name], 'blob') !== false) + { + $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data)); + } + } + $this->flush($sql_insert . implode(', ', $row) . ");\n"); } - else - { - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '" . $table_name . "'"; - $table_data = sqlite_single_query($db->db_connect_id, $sql); - $table_data = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', '', $table_data); - $table_data = trim($table_data); + } + + function write_end() + { + $this->flush("COMMIT;\n"); + parent::write_end(); + } +} - preg_match('#\((.*)\)#s', $table_data, $matches); +class sqlite3_extractor extends base_extractor +{ + function write_start($prefix) + { + $sql_data = "--\n"; + $sql_data .= "-- phpBB Backup Script\n"; + $sql_data .= "-- Dump of tables for $prefix\n"; + $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; + $sql_data .= "--\n"; + $sql_data .= "BEGIN TRANSACTION;\n"; + $this->flush($sql_data); + } - $table_cols = explode(',', trim($matches[1])); - foreach ($table_cols as $declaration) + function write_table($table_name) + { + global $db; + $sql_data = '-- Table: ' . $table_name . "\n"; + $sql_data .= "DROP TABLE $table_name;\n"; + + $sql = "SELECT sql + FROM sqlite_master + WHERE type = 'table' + AND name = '" . $db->sql_escape($table_name) . "' + ORDER BY name ASC;"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + // Create Table + $sql_data .= $row['sql'] . ";\n"; + + $result = $db->sql_query("PRAGMA index_list('" . $db->sql_escape($table_name) . "');"); + + while ($row = $db->sql_fetchrow($result)) + { + if (strpos($row['name'], 'autoindex') !== false) { - $entities = preg_split('#\s+#', trim($declaration)); - $column_name = preg_replace('/"?([^"]+)"?/', '\1', $entities[0]); + continue; + } - // Hit a primary key, those are not what we need :D - if (empty($entities[1]) || (strtolower($entities[0]) === 'primary' && strtolower($entities[1]) === 'key')) - { - continue; - } - $col_types[$column_name] = $entities[1]; + $result2 = $db->sql_query("PRAGMA index_info('" . $db->sql_escape($row['name']) . "');"); + + $fields = array(); + while ($row2 = $db->sql_fetchrow($result2)) + { + $fields[] = $row2['name']; } + $db->sql_freeresult($result2); + + $sql_data .= 'CREATE ' . ($row['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $row['name'] . ' ON ' . $table_name . ' (' . implode(', ', $fields) . ");\n"; + } + $db->sql_freeresult($result); + + $this->flush($sql_data . "\n"); + } + + function write_data($table_name) + { + global $db; + + $result = $db->sql_query("PRAGMA table_info('" . $db->sql_escape($table_name) . "');"); + + $col_types = array(); + while ($row = $db->sql_fetchrow($result)) + { + $col_types[$row['name']] = $row['type']; } + $db->sql_freeresult($result); + + $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES ('; $sql = "SELECT * FROM $table_name"; - $result = sqlite_unbuffered_query($db->db_connect_id, $sql); - $rows = sqlite_fetch_all($result, SQLITE_ASSOC); - $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES ('; - foreach ($rows as $row) + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) { foreach ($row as $column_name => $column_data) { @@ -1067,11 +1111,11 @@ class sqlite_extractor extends base_extractor { $row[$column_name] = 'NULL'; } - else if ($column_data == '') + else if ($column_data === '') { $row[$column_name] = "''"; } - else if (strpos($col_types[$column_name], 'text') !== false || strpos($col_types[$column_name], 'char') !== false || strpos($col_types[$column_name], 'blob') !== false) + else if (stripos($col_types[$column_name], 'text') !== false || stripos($col_types[$column_name], 'char') !== false || stripos($col_types[$column_name], 'blob') !== false) { $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data)); } @@ -1087,9 +1131,6 @@ class sqlite_extractor extends base_extractor } } -/** -* @package acp -*/ class postgres_extractor extends base_extractor { function write_start($prefix) @@ -1218,7 +1259,6 @@ class postgres_extractor extends base_extractor } $db->sql_freeresult($result); - // Get the listing of primary keys. $sql_pri_keys = "SELECT ic.relname as index_name, bc.relname as tab_name, ta.attname as column_name, i.indisunique as unique_key, i.indisprimary as primary_key FROM pg_class bc, pg_class ic, pg_index i, pg_attribute ta, pg_attribute ia @@ -1318,7 +1358,6 @@ class postgres_extractor extends base_extractor $ary_type[] = pg_field_type($result, $i); $ary_name[] = pg_field_name($result, $i); - $sql = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault FROM pg_attrdef d, pg_class c WHERE (c.relname = '{$table_name}') @@ -1381,9 +1420,6 @@ class postgres_extractor extends base_extractor } } -/** -* @package acp -*/ class mssql_extractor extends base_extractor { function write_end() @@ -1517,11 +1553,11 @@ class mssql_extractor extends base_extractor { global $db; - if ($db->sql_layer === 'mssql') + if ($db->get_sql_layer() === 'mssql') { $this->write_data_mssql($table_name); } - else if($db->sql_layer === 'mssqlnative') + else if($db->get_sql_layer() === 'mssqlnative') { $this->write_data_mssqlnative($table_name); } @@ -1624,7 +1660,7 @@ class mssql_extractor extends base_extractor } $this->flush($sql_data); } - + function write_data_mssqlnative($table_name) { global $db; @@ -1645,16 +1681,17 @@ class mssql_extractor extends base_extractor return; } - $sql = "SELECT * FROM $table_name"; - $result_fields = $db->sql_query_limit($sql, 1); + $sql = "SELECT COLUMN_NAME, DATA_TYPE + FROM INFORMATION_SCHEMA.COLUMNS + WHERE INFORMATION_SCHEMA.COLUMNS.TABLE_NAME = '" . $db->sql_escape($table_name) . "'"; + $result_fields = $db->sql_query($sql); - $row = new result_mssqlnative($result_fields); - $i_num_fields = $row->num_fields(); - - for ($i = 0; $i < $i_num_fields; $i++) + $i_num_fields = 0; + while ($row = $db->sql_fetchrow($result_fields)) { - $ary_type[$i] = $row->field_type($i); - $ary_name[$i] = $row->field_name($i); + $ary_type[$i_num_fields] = $row['DATA_TYPE']; + $ary_name[$i_num_fields] = $row['COLUMN_NAME']; + $i_num_fields++; } $db->sql_freeresult($result_fields); @@ -1663,7 +1700,7 @@ class mssql_extractor extends base_extractor WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1"; $result2 = $db->sql_query($sql); $row2 = $db->sql_fetchrow($result2); - + if (!empty($row2['has_identity'])) { $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n"; @@ -1727,8 +1764,8 @@ class mssql_extractor extends base_extractor $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n"; } $this->flush($sql_data); - } - + } + function write_data_odbc($table_name) { global $db; @@ -1827,9 +1864,6 @@ class mssql_extractor extends base_extractor } -/** -* @package acp -*/ class oracle_extractor extends base_extractor { function write_table($table_name) @@ -2057,238 +2091,6 @@ class oracle_extractor extends base_extractor } } -/** -* @package acp -*/ -class firebird_extractor extends base_extractor -{ - function write_start($prefix) - { - $sql_data = "--\n"; - $sql_data .= "-- phpBB Backup Script\n"; - $sql_data .= "-- Dump of tables for $prefix\n"; - $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n"; - $sql_data .= "--\n"; - $this->flush($sql_data); - } - - function write_data($table_name) - { - global $db; - $ary_type = $ary_name = array(); - - // Grab all of the data from current table. - $sql = "SELECT * - FROM $table_name"; - $result = $db->sql_query($sql); - - $i_num_fields = ibase_num_fields($result); - - for ($i = 0; $i < $i_num_fields; $i++) - { - $info = ibase_field_info($result, $i); - $ary_type[$i] = $info['type']; - $ary_name[$i] = $info['name']; - } - - while ($row = $db->sql_fetchrow($result)) - { - $schema_vals = $schema_fields = array(); - - // Build the SQL statement to recreate the data. - for ($i = 0; $i < $i_num_fields; $i++) - { - $str_val = $row[strtolower($ary_name[$i])]; - - if (preg_match('#char|text|bool|varbinary|blob#i', $ary_type[$i])) - { - $str_quote = ''; - $str_empty = "''"; - $str_val = sanitize_data_generic(str_replace("'", "''", $str_val)); - } - else if (preg_match('#date|timestamp#i', $ary_type[$i])) - { - if (empty($str_val)) - { - $str_quote = ''; - } - else - { - $str_quote = "'"; - } - } - else - { - $str_quote = ''; - $str_empty = 'NULL'; - } - - if (empty($str_val) && $str_val !== '0') - { - $str_val = $str_empty; - } - - $schema_vals[$i] = $str_quote . $str_val . $str_quote; - $schema_fields[$i] = '"' . $ary_name[$i] . '"'; - } - - // Take the ordered fields and their associated data and build it - // into a valid sql statement to recreate that field in the data. - $sql_data = "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\n"; - - $this->flush($sql_data); - } - $db->sql_freeresult($result); - } - - function write_table($table_name) - { - global $db; - - $sql_data = '-- Table: ' . $table_name . "\n"; - $sql_data .= "DROP TABLE $table_name;\n"; - - $data_types = array(7 => 'SMALLINT', 8 => 'INTEGER', 10 => 'FLOAT', 12 => 'DATE', 13 => 'TIME', 14 => 'CHARACTER', 27 => 'DOUBLE PRECISION', 35 => 'TIMESTAMP', 37 => 'VARCHAR', 40 => 'CSTRING', 261 => 'BLOB', 701 => 'DECIMAL', 702 => 'NUMERIC'); - - $sql_data .= "\nCREATE TABLE $table_name (\n"; - - $sql = 'SELECT DISTINCT R.RDB$FIELD_NAME as FNAME, R.RDB$NULL_FLAG as NFLAG, R.RDB$DEFAULT_SOURCE as DSOURCE, F.RDB$FIELD_TYPE as FTYPE, F.RDB$FIELD_SUB_TYPE as STYPE, F.RDB$FIELD_LENGTH as FLEN - FROM RDB$RELATION_FIELDS R - JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME - LEFT JOIN RDB$FIELD_DIMENSIONS D ON R.RDB$FIELD_SOURCE = D.RDB$FIELD_NAME - WHERE F.RDB$SYSTEM_FLAG = 0 - AND R.RDB$RELATION_NAME = \''. $table_name . '\' - ORDER BY R.RDB$FIELD_POSITION'; - $result = $db->sql_query($sql); - - $rows = array(); - while ($row = $db->sql_fetchrow($result)) - { - $line = "\t" . '"' . $row['fname'] . '" ' . $data_types[$row['ftype']]; - - if ($row['ftype'] == 261 && $row['stype'] == 1) - { - $line .= ' SUB_TYPE TEXT'; - } - - if ($row['ftype'] == 37 || $row['ftype'] == 14) - { - $line .= ' (' . $row['flen'] . ')'; - } - - if (!empty($row['dsource'])) - { - $line .= ' ' . $row['dsource']; - } - - if (!empty($row['nflag'])) - { - $line .= ' NOT NULL'; - } - $rows[] = $line; - } - $db->sql_freeresult($result); - - $sql_data .= implode(",\n", $rows); - $sql_data .= "\n);\n"; - $keys = array(); - - $sql = 'SELECT I.RDB$FIELD_NAME as NAME - FROM RDB$RELATION_CONSTRAINTS RC, RDB$INDEX_SEGMENTS I, RDB$INDICES IDX - WHERE (I.RDB$INDEX_NAME = RC.RDB$INDEX_NAME) - AND (IDX.RDB$INDEX_NAME = RC.RDB$INDEX_NAME) - AND (RC.RDB$RELATION_NAME = \''. $table_name . '\') - ORDER BY I.RDB$FIELD_POSITION'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $keys[] = $row['name']; - } - - if (sizeof($keys)) - { - $sql_data .= "\nALTER TABLE $table_name ADD PRIMARY KEY (" . implode(', ', $keys) . ');'; - } - - $db->sql_freeresult($result); - - $sql = 'SELECT I.RDB$INDEX_NAME as INAME, I.RDB$UNIQUE_FLAG as UFLAG, S.RDB$FIELD_NAME as FNAME - FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS S ON S.RDB$INDEX_NAME=I.RDB$INDEX_NAME - WHERE (I.RDB$SYSTEM_FLAG IS NULL OR I.RDB$SYSTEM_FLAG=0) - AND I.RDB$FOREIGN_KEY IS NULL - AND I.RDB$RELATION_NAME = \''. $table_name . '\' - AND I.RDB$INDEX_NAME NOT STARTING WITH \'RDB$\' - ORDER BY S.RDB$FIELD_POSITION'; - $result = $db->sql_query($sql); - - $index = array(); - while ($row = $db->sql_fetchrow($result)) - { - $index[$row['iname']]['unique'] = !empty($row['uflag']); - $index[$row['iname']]['values'][] = $row['fname']; - } - - foreach ($index as $index_name => $data) - { - $sql_data .= "\nCREATE "; - if ($data['unique']) - { - $sql_data .= 'UNIQUE '; - } - $sql_data .= "INDEX $index_name ON $table_name(" . implode(', ', $data['values']) . ");"; - } - $sql_data .= "\n"; - - $db->sql_freeresult($result); - - $sql = 'SELECT D1.RDB$DEPENDENT_NAME as DNAME, D1.RDB$FIELD_NAME as FNAME, D1.RDB$DEPENDENT_TYPE, R1.RDB$RELATION_NAME - FROM RDB$DEPENDENCIES D1 - LEFT JOIN RDB$RELATIONS R1 ON ((D1.RDB$DEPENDENT_NAME = R1.RDB$RELATION_NAME) AND (NOT (R1.RDB$VIEW_BLR IS NULL))) - WHERE (D1.RDB$DEPENDED_ON_TYPE = 0) - AND (D1.RDB$DEPENDENT_TYPE <> 3) - AND (D1.RDB$DEPENDED_ON_NAME = \'' . $table_name . '\') - UNION SELECT DISTINCT F2.RDB$RELATION_NAME, D2.RDB$FIELD_NAME, D2.RDB$DEPENDENT_TYPE, R2.RDB$RELATION_NAME FROM RDB$DEPENDENCIES D2, RDB$RELATION_FIELDS F2 - LEFT JOIN RDB$RELATIONS R2 ON ((F2.RDB$RELATION_NAME = R2.RDB$RELATION_NAME) AND (NOT (R2.RDB$VIEW_BLR IS NULL))) - WHERE (D2.RDB$DEPENDENT_TYPE = 3) - AND (D2.RDB$DEPENDENT_NAME = F2.RDB$FIELD_SOURCE) - AND (D2.RDB$DEPENDED_ON_NAME = \'' . $table_name . '\') - ORDER BY 1, 2'; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $sql = 'SELECT T1.RDB$DEPENDED_ON_NAME as GEN, T1.RDB$FIELD_NAME, T1.RDB$DEPENDED_ON_TYPE - FROM RDB$DEPENDENCIES T1 - WHERE (T1.RDB$DEPENDENT_NAME = \'' . $row['dname'] . '\') - AND (T1.RDB$DEPENDENT_TYPE = 2 AND T1.RDB$DEPENDED_ON_TYPE = 14) - UNION ALL SELECT DISTINCT D.RDB$DEPENDED_ON_NAME, D.RDB$FIELD_NAME, D.RDB$DEPENDED_ON_TYPE - FROM RDB$DEPENDENCIES D, RDB$RELATION_FIELDS F - WHERE (D.RDB$DEPENDENT_TYPE = 3) - AND (D.RDB$DEPENDENT_NAME = F.RDB$FIELD_SOURCE) - AND (F.RDB$RELATION_NAME = \'' . $row['dname'] . '\') - ORDER BY 1,2'; - $result2 = $db->sql_query($sql); - $row2 = $db->sql_fetchrow($result2); - $db->sql_freeresult($result2); - $gen_name = $row2['gen']; - - $sql_data .= "\nDROP GENERATOR " . $gen_name . ";"; - $sql_data .= "\nSET TERM ^ ;"; - $sql_data .= "\nCREATE GENERATOR " . $gen_name . "^"; - $sql_data .= "\nSET GENERATOR " . $gen_name . " TO 0^\n"; - $sql_data .= "\nCREATE TRIGGER {$row['dname']} FOR $table_name"; - $sql_data .= "\nBEFORE INSERT\nAS\nBEGIN"; - $sql_data .= "\n NEW.{$row['fname']} = GEN_ID(" . $gen_name . ", 1);"; - $sql_data .= "\nEND^\n"; - $sql_data .= "\nSET TERM ; ^\n"; - } - - $this->flush($sql_data); - - $db->sql_freeresult($result); - } -} - // get how much space we allow for a chunk of data, very similar to phpMyAdmin's way of doing things ;-) (hey, we only do this for MySQL anyway :P) function get_usable_memory() { @@ -2464,5 +2266,3 @@ function fgetd_seekless(&$fp, $delim, $read, $seek, $eof, $buffer = 8192) return false; } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_disallow.php b/phpBB/includes/acp/acp_disallow.php index e2176b7bcd..4c8f3cc65b 100644 --- a/phpBB/includes/acp/acp_disallow.php +++ b/phpBB/includes/acp/acp_disallow.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_disallow { var $u_action; @@ -116,5 +116,3 @@ class acp_disallow ); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_email.php b/phpBB/includes/acp/acp_email.php index df0d44c0c5..fda9d50779 100644 --- a/phpBB/includes/acp/acp_email.php +++ b/phpBB/includes/acp/acp_email.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_email { var $u_action; @@ -26,7 +26,7 @@ class acp_email function main($id, $mode) { global $config, $db, $user, $auth, $template, $cache; - global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix; + global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $phpbb_dispatcher; $user->add_lang('acp/email'); $this->tpl_name = 'acp_email'; @@ -40,6 +40,7 @@ class acp_email $error = array(); $usernames = request_var('usernames', '', true); + $usernames = (!empty($usernames)) ? explode("\n", $usernames) : array(); $group_id = request_var('g', 0); $subject = utf8_normalize_nfc(request_var('subject', '', true)); $message = utf8_normalize_nfc(request_var('message', '', true)); @@ -69,14 +70,18 @@ class acp_email if (!sizeof($error)) { - if ($usernames) + if (!empty($usernames)) { // If giving usernames the admin is able to email inactive users too... - $sql = 'SELECT username, user_email, user_jabber, user_notify_type, user_lang - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('username_clean', array_map('utf8_clean_string', explode("\n", $usernames))) . ' - AND user_allow_massemail = 1 - ORDER BY user_lang, user_notify_type'; // , SUBSTRING(user_email FROM INSTR(user_email, '@')) + $sql_ary = array( + 'SELECT' => 'username, user_email, user_jabber, user_notify_type, user_lang', + 'FROM' => array( + USERS_TABLE => '', + ), + 'WHERE' => $db->sql_in_set('username_clean', array_map('utf8_clean_string', $usernames)) . ' + AND user_allow_massemail = 1', + 'ORDER_BY' => 'user_lang, user_notify_type', + ); } else { @@ -123,8 +128,18 @@ class acp_email ), ); } - $sql = $db->sql_build_query('SELECT', $sql_ary); } + /** + * Modify sql query to change the list of users the email is sent to + * + * @event core.acp_email_modify_sql + * @var array sql_ary Array which is used to build the sql query + * @since 3.1.2-RC1 + */ + $vars = array('sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.acp_email_modify_sql', compact($vars))); + + $sql = $db->sql_build_query('SELECT', $sql_ary); $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); @@ -180,6 +195,39 @@ class acp_email $errored = false; + $email_template = 'admin_send_email'; + $template_data = array( + 'CONTACT_EMAIL' => phpbb_get_board_contact($config, $phpEx), + 'MESSAGE' => htmlspecialchars_decode($message), + ); + $generate_log_entry = true; + + /** + * Modify email template data before the emails are sent + * + * @event core.acp_email_send_before + * @var string email_template The template to be used for sending the email + * @var string subject The subject of the email + * @var array template_data Array with template data assigned to email template + * @var bool generate_log_entry If false, no log entry will be created + * @var array usernames Usernames which will be displayed in log entry, if it will be created + * @var int group_id The group this email will be sent to + * @var bool use_queue If true, email queue will be used for sending + * @var int priority Priority of sent emails + * @since 3.1.3-RC1 + */ + $vars = array( + 'email_template', + 'subject', + 'template_data', + 'generate_log_entry', + 'usernames', + 'group_id', + 'use_queue', + 'priority', + ); + extract($phpbb_dispatcher->trigger_event('core.acp_email_send_before', compact($vars))); + for ($i = 0, $size = sizeof($email_list); $i < $size; $i++) { $used_lang = $email_list[$i][0]['lang']; @@ -193,17 +241,14 @@ class acp_email $messenger->im($email_row['jabber'], $email_row['name']); } - $messenger->template('admin_send_email', $used_lang); + $messenger->template($email_template, $used_lang); $messenger->anti_abuse_headers($config, $user); $messenger->subject(htmlspecialchars_decode($subject)); $messenger->set_mail_priority($priority); - $messenger->assign_vars(array( - 'CONTACT_EMAIL' => $config['board_contact'], - 'MESSAGE' => htmlspecialchars_decode($message)) - ); + $messenger->assign_vars($template_data); if (!($messenger->send($used_method))) { @@ -214,24 +259,26 @@ class acp_email $messenger->save_queue(); - if ($usernames) - { - $usernames = explode("\n", $usernames); - add_log('admin', 'LOG_MASS_EMAIL', implode(', ', utf8_normalize_nfc($usernames))); - } - else + if ($generate_log_entry) { - if ($group_id) + if (!empty($usernames)) { - $group_name = get_group_name($group_id); + add_log('admin', 'LOG_MASS_EMAIL', implode(', ', utf8_normalize_nfc($usernames))); } else { - // Not great but the logging routine doesn't cope well with localising on the fly - $group_name = $user->lang['ALL_USERS']; - } + if ($group_id) + { + $group_name = get_group_name($group_id); + } + else + { + // Not great but the logging routine doesn't cope well with localising on the fly + $group_name = $user->lang['ALL_USERS']; + } - add_log('admin', 'LOG_MASS_EMAIL', $group_name); + add_log('admin', 'LOG_MASS_EMAIL', $group_name); + } } if (!$errored) @@ -267,19 +314,31 @@ class acp_email $s_priority_options .= '<option value="' . MAIL_NORMAL_PRIORITY . '" selected="selected">' . $user->lang['MAIL_NORMAL_PRIORITY'] . '</option>'; $s_priority_options .= '<option value="' . MAIL_HIGH_PRIORITY . '">' . $user->lang['MAIL_HIGH_PRIORITY'] . '</option>'; - $template->assign_vars(array( + $template_data = array( 'S_WARNING' => (sizeof($error)) ? true : false, 'WARNING_MSG' => (sizeof($error)) ? implode('<br />', $error) : '', 'U_ACTION' => $this->u_action, 'S_GROUP_OPTIONS' => $select_list, - 'USERNAMES' => $usernames, + 'USERNAMES' => implode("\n", $usernames), 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=acp_email&field=usernames'), 'SUBJECT' => $subject, 'MESSAGE' => $message, - 'S_PRIORITY_OPTIONS' => $s_priority_options) + 'S_PRIORITY_OPTIONS' => $s_priority_options, ); + /** + * Modify custom email template data before we display the form + * + * @event core.acp_email_display + * @var array template_data Array with template data assigned to email template + * @var array exclude Array with groups which are excluded from group selection + * @var array usernames Usernames which will be displayed in form + * + * @since 3.1.4-RC1 + */ + $vars = array('template_data', 'exclude', 'usernames'); + extract($phpbb_dispatcher->trigger_event('core.acp_email_display', compact($vars))); + + $template->assign_vars($template_data); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php new file mode 100644 index 0000000000..0c9bc0deab --- /dev/null +++ b/phpBB/includes/acp/acp_extensions.php @@ -0,0 +1,550 @@ +<?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. +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +class acp_extensions +{ + var $u_action; + + private $db; + private $config; + private $template; + private $user; + private $cache; + private $log; + private $request; + + function main() + { + // Start the page + global $config, $user, $template, $request, $phpbb_extension_manager, $db, $phpbb_root_path, $phpEx, $phpbb_log, $cache; + + $this->db = $db; + $this->config = $config; + $this->template = $template; + $this->user = $user; + $this->cache = $cache; + $this->request = $request; + $this->log = $phpbb_log; + + $user->add_lang(array('install', 'acp/extensions', 'migrator')); + + $this->page_title = 'ACP_EXTENSIONS'; + + $action = $request->variable('action', 'list'); + $ext_name = $request->variable('ext_name', ''); + + // What is a safe limit of execution time? Half the max execution time should be safe. + $safe_time_limit = (ini_get('max_execution_time') / 2); + $start_time = time(); + + // Cancel action + if ($request->is_set_post('cancel')) + { + $action = 'list'; + $ext_name = ''; + } + + if (in_array($action, array('enable', 'disable', 'delete_data')) && !check_link_hash($request->variable('hash', ''), $action . '.' . $ext_name)) + { + trigger_error('FORM_INVALID', E_USER_WARNING); + } + + // If they've specified an extension, let's load the metadata manager and validate it. + if ($ext_name) + { + $md_manager = new \phpbb\extension\metadata_manager($ext_name, $config, $phpbb_extension_manager, $template, $user, $phpbb_root_path); + + try + { + $md_manager->get_metadata('all'); + } + catch(\phpbb\extension\exception $e) + { + trigger_error($e, E_USER_WARNING); + } + } + + // What are we doing? + switch ($action) + { + case 'set_config_version_check_force_unstable': + $force_unstable = $this->request->variable('force_unstable', false); + + if ($force_unstable) + { + $s_hidden_fields = build_hidden_fields(array( + 'force_unstable' => $force_unstable, + )); + + confirm_box(false, $user->lang('EXTENSION_FORCE_UNSTABLE_CONFIRM'), $s_hidden_fields); + } + else + { + $config->set('extension_force_unstable', false); + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + } + break; + + case 'list': + default: + if (confirm_box(true)) + { + $config->set('extension_force_unstable', true); + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + } + + $this->list_enabled_exts($phpbb_extension_manager); + $this->list_disabled_exts($phpbb_extension_manager); + $this->list_available_exts($phpbb_extension_manager); + + $this->template->assign_vars(array( + 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=list&versioncheck_force=1', + 'FORCE_UNSTABLE' => $config['extension_force_unstable'], + 'U_ACTION' => $this->u_action, + )); + + add_form_key('version_check_settings'); + + $this->tpl_name = 'acp_ext_list'; + break; + + case 'enable_pre': + if (!$md_manager->validate_dir()) + { + trigger_error($user->lang['EXTENSION_DIR_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + if (!$md_manager->validate_enable()) + { + trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + $extension = $phpbb_extension_manager->get_extension($ext_name); + if (!$extension->is_enableable()) + { + trigger_error($user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + if ($phpbb_extension_manager->is_enabled($ext_name)) + { + redirect($this->u_action); + } + + $this->tpl_name = 'acp_ext_enable'; + + $template->assign_vars(array( + 'PRE' => true, + 'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_ENABLE_CONFIRM', $md_manager->get_metadata('display-name')), + 'U_ENABLE' => $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name), + )); + break; + + case 'enable': + if (!$md_manager->validate_dir()) + { + trigger_error($user->lang['EXTENSION_DIR_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + if (!$md_manager->validate_enable()) + { + trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + $extension = $phpbb_extension_manager->get_extension($ext_name); + if (!$extension->is_enableable()) + { + trigger_error($user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + try + { + while ($phpbb_extension_manager->enable_step($ext_name)) + { + // Are we approaching the time limit? If so we want to pause the update and continue after refreshing + if ((time() - $start_time) >= $safe_time_limit) + { + $template->assign_var('S_NEXT_STEP', true); + + meta_refresh(0, $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name)); + } + } + $this->log->add('admin', $user->data['user_id'], $user->ip, 'LOG_EXT_ENABLE', time(), array($ext_name)); + } + catch (\phpbb\db\migration\exception $e) + { + $template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($user)); + } + + $this->tpl_name = 'acp_ext_enable'; + + $template->assign_vars(array( + 'U_RETURN' => $this->u_action . '&action=list', + )); + break; + + case 'disable_pre': + if (!$phpbb_extension_manager->is_enabled($ext_name)) + { + redirect($this->u_action); + } + + $this->tpl_name = 'acp_ext_disable'; + + $template->assign_vars(array( + 'PRE' => true, + 'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DISABLE_CONFIRM', $md_manager->get_metadata('display-name')), + 'U_DISABLE' => $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name), + )); + break; + + case 'disable': + if (!$phpbb_extension_manager->is_enabled($ext_name)) + { + redirect($this->u_action); + } + + while ($phpbb_extension_manager->disable_step($ext_name)) + { + // Are we approaching the time limit? If so we want to pause the update and continue after refreshing + if ((time() - $start_time) >= $safe_time_limit) + { + $template->assign_var('S_NEXT_STEP', true); + + meta_refresh(0, $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name)); + } + } + $this->log->add('admin', $user->data['user_id'], $user->ip, 'LOG_EXT_DISABLE', time(), array($ext_name)); + + $this->tpl_name = 'acp_ext_disable'; + + $template->assign_vars(array( + 'U_RETURN' => $this->u_action . '&action=list', + )); + break; + + case 'delete_data_pre': + if ($phpbb_extension_manager->is_enabled($ext_name)) + { + redirect($this->u_action); + } + $this->tpl_name = 'acp_ext_delete_data'; + + $template->assign_vars(array( + 'PRE' => true, + 'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DELETE_DATA_CONFIRM', $md_manager->get_metadata('display-name')), + 'U_PURGE' => $this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name), + )); + break; + + case 'delete_data': + if ($phpbb_extension_manager->is_enabled($ext_name)) + { + redirect($this->u_action); + } + + try + { + while ($phpbb_extension_manager->purge_step($ext_name)) + { + // Are we approaching the time limit? If so we want to pause the update and continue after refreshing + if ((time() - $start_time) >= $safe_time_limit) + { + $template->assign_var('S_NEXT_STEP', true); + + meta_refresh(0, $this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name)); + } + } + $this->log->add('admin', $user->data['user_id'], $user->ip, 'LOG_EXT_PURGE', time(), array($ext_name)); + } + catch (\phpbb\db\migration\exception $e) + { + $template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($user)); + } + + $this->tpl_name = 'acp_ext_delete_data'; + + $template->assign_vars(array( + 'U_RETURN' => $this->u_action . '&action=list', + )); + break; + + case 'details': + // Output it to the template + $md_manager->output_template_data(); + + try + { + $updates_available = $this->version_check($md_manager, $request->variable('versioncheck_force', false)); + + $template->assign_vars(array( + 'S_UP_TO_DATE' => empty($updates_available), + 'S_VERSIONCHECK' => true, + 'UP_TO_DATE_MSG' => $this->user->lang(empty($updates_available) ? 'UP_TO_DATE' : 'NOT_UP_TO_DATE', $md_manager->get_metadata('display-name')), + )); + + foreach ($updates_available as $branch => $version_data) + { + $template->assign_block_vars('updates_available', $version_data); + } + } + catch (\RuntimeException $e) + { + $template->assign_vars(array( + 'S_VERSIONCHECK_STATUS' => $e->getCode(), + 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== $user->lang('VERSIONCHECK_FAIL')) ? $e->getMessage() : '', + )); + } + + $template->assign_vars(array( + 'U_BACK' => $this->u_action . '&action=list', + 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')), + )); + + $this->tpl_name = 'acp_ext_details'; + break; + } + } + + /** + * Lists all the enabled extensions and dumps to the template + * + * @param $phpbb_extension_manager An instance of the extension manager + * @return null + */ + public function list_enabled_exts(\phpbb\extension\manager $phpbb_extension_manager) + { + $enabled_extension_meta_data = array(); + + foreach ($phpbb_extension_manager->all_enabled() as $name => $location) + { + $md_manager = $phpbb_extension_manager->create_extension_metadata_manager($name, $this->template); + + try + { + $meta = $md_manager->get_metadata('all'); + $enabled_extension_meta_data[$name] = array( + 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), + 'META_VERSION' => $meta['version'], + ); + + $force_update = $this->request->variable('versioncheck_force', false); + $updates = $this->version_check($md_manager, $force_update, !$force_update); + + $enabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates); + $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true; + $enabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')); + } + catch(\phpbb\extension\exception $e) + { + $this->template->assign_block_vars('disabled', array( + 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $e), + 'S_VERSIONCHECK' => false, + )); + } + catch (\RuntimeException $e) + { + $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; + } + } + + uasort($enabled_extension_meta_data, array($this, 'sort_extension_meta_data_table')); + + foreach ($enabled_extension_meta_data as $name => $block_vars) + { + $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); + + $this->template->assign_block_vars('enabled', $block_vars); + + $this->output_actions('enabled', array( + 'DISABLE' => $this->u_action . '&action=disable_pre&ext_name=' . urlencode($name), + )); + } + } + + /** + * Lists all the disabled extensions and dumps to the template + * + * @param $phpbb_extension_manager An instance of the extension manager + * @return null + */ + public function list_disabled_exts(\phpbb\extension\manager $phpbb_extension_manager) + { + $disabled_extension_meta_data = array(); + + foreach ($phpbb_extension_manager->all_disabled() as $name => $location) + { + $md_manager = $phpbb_extension_manager->create_extension_metadata_manager($name, $this->template); + + try + { + $meta = $md_manager->get_metadata('all'); + $disabled_extension_meta_data[$name] = array( + 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), + 'META_VERSION' => $meta['version'], + ); + + $force_update = $this->request->variable('versioncheck_force', false); + $updates = $this->version_check($md_manager, $force_update, !$force_update); + + $disabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates); + $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true; + $disabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')); + } + catch(\phpbb\extension\exception $e) + { + $this->template->assign_block_vars('disabled', array( + 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $e), + 'S_VERSIONCHECK' => false, + )); + } + catch (\RuntimeException $e) + { + $disabeld_extension_meta_data[$name]['S_VERSIONCHECK'] = false; + } + } + + uasort($disabled_extension_meta_data, array($this, 'sort_extension_meta_data_table')); + + foreach ($disabled_extension_meta_data as $name => $block_vars) + { + $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); + + $this->template->assign_block_vars('disabled', $block_vars); + + $this->output_actions('disabled', array( + 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), + 'DELETE_DATA' => $this->u_action . '&action=delete_data_pre&ext_name=' . urlencode($name), + )); + } + } + + /** + * Lists all the available extensions and dumps to the template + * + * @param $phpbb_extension_manager An instance of the extension manager + * @return null + */ + public function list_available_exts(\phpbb\extension\manager $phpbb_extension_manager) + { + $uninstalled = array_diff_key($phpbb_extension_manager->all_available(), $phpbb_extension_manager->all_configured()); + + $available_extension_meta_data = array(); + + foreach ($uninstalled as $name => $location) + { + $md_manager = $phpbb_extension_manager->create_extension_metadata_manager($name, $this->template); + + try + { + $meta = $md_manager->get_metadata('all'); + $available_extension_meta_data[$name] = array( + 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), + 'META_VERSION' => $meta['version'], + ); + + $force_update = $this->request->variable('versioncheck_force', false); + $updates = $this->version_check($md_manager, $force_update, !$force_update); + + $available_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates); + $available_extension_meta_data[$name]['S_VERSIONCHECK'] = true; + $available_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')); + } + catch(\phpbb\extension\exception $e) + { + $this->template->assign_block_vars('disabled', array( + 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $e), + 'S_VERSIONCHECK' => false, + )); + } + catch (\RuntimeException $e) + { + $available_extension_meta_data[$name]['S_VERSIONCHECK'] = false; + } + } + + uasort($available_extension_meta_data, array($this, 'sort_extension_meta_data_table')); + + foreach ($available_extension_meta_data as $name => $block_vars) + { + $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); + + $this->template->assign_block_vars('disabled', $block_vars); + + $this->output_actions('disabled', array( + 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), + )); + } + } + + /** + * Output actions to a block + * + * @param string $block + * @param array $actions + */ + private function output_actions($block, $actions) + { + foreach ($actions as $lang => $url) + { + $this->template->assign_block_vars($block . '.actions', array( + 'L_ACTION' => $this->user->lang('EXTENSION_' . $lang), + 'L_ACTION_EXPLAIN' => (isset($this->user->lang['EXTENSION_' . $lang . '_EXPLAIN'])) ? $this->user->lang('EXTENSION_' . $lang . '_EXPLAIN') : '', + 'U_ACTION' => $url, + )); + } + } + + /** + * Check the version and return the available updates. + * + * @param \phpbb\extension\metadata_manager $md_manager The metadata manager for the version to check. + * @param bool $force_update Ignores cached data. Defaults to false. + * @param bool $force_cache Force the use of the cache. Override $force_update. + * @return string + * @throws RuntimeException + */ + protected function version_check(\phpbb\extension\metadata_manager $md_manager, $force_update = false, $force_cache = false) + { + $meta = $md_manager->get_metadata('all'); + + if (!isset($meta['extra']['version-check'])) + { + throw new \RuntimeException($this->user->lang('NO_VERSIONCHECK'), 1); + } + + $version_check = $meta['extra']['version-check']; + + $version_helper = new \phpbb\version_helper($this->cache, $this->config, new \phpbb\file_downloader(), $this->user); + $version_helper->set_current_version($meta['version']); + $version_helper->set_file_location($version_check['host'], $version_check['directory'], $version_check['filename']); + $version_helper->force_stability($this->config['extension_force_unstable'] ? 'unstable' : null); + + return $updates = $version_helper->get_suggested_updates($force_update, $force_cache); + } + + /** + * Sort helper for the table containing the metadata about the extensions. + */ + protected function sort_extension_meta_data_table($val1, $val2) + { + return strnatcasecmp($val1['META_DISPLAY_NAME'], $val2['META_DISPLAY_NAME']); + } +} diff --git a/phpBB/includes/acp/acp_forums.php b/phpBB/includes/acp/acp_forums.php index dc2e6b75fb..adf5de44f5 100644 --- a/phpBB/includes/acp/acp_forums.php +++ b/phpBB/includes/acp/acp_forums.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_forums { var $u_action; @@ -26,7 +26,7 @@ class acp_forums function main($id, $mode) { - global $db, $user, $auth, $template, $cache; + global $db, $user, $auth, $template, $cache, $request, $phpbb_dispatcher; global $config, $phpbb_admin_path, $phpbb_root_path, $phpEx; $user->add_lang('acp/forums'); @@ -139,17 +139,31 @@ class acp_forums 'enable_prune' => request_var('enable_prune', false), 'enable_post_review' => request_var('enable_post_review', true), 'enable_quick_reply' => request_var('enable_quick_reply', false), + 'enable_shadow_prune' => request_var('enable_shadow_prune', false), 'prune_days' => request_var('prune_days', 7), 'prune_viewed' => request_var('prune_viewed', 7), 'prune_freq' => request_var('prune_freq', 1), 'prune_old_polls' => request_var('prune_old_polls', false), 'prune_announce' => request_var('prune_announce', false), 'prune_sticky' => request_var('prune_sticky', false), + 'prune_shadow_days' => request_var('prune_shadow_days', 7), + 'prune_shadow_freq' => request_var('prune_shadow_freq', 1), 'forum_password' => request_var('forum_password', '', true), 'forum_password_confirm'=> request_var('forum_password_confirm', '', true), 'forum_password_unset' => request_var('forum_password_unset', false), ); + /** + * Request forum data and operate on it (parse texts, etc.) + * + * @event core.acp_manage_forums_request_data + * @var string action Type of the action: add|edit + * @var array forum_data Array with new forum data + * @since 3.1.0-a1 + */ + $vars = array('action', 'forum_data'); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_request_data', compact($vars))); + // On add, add empty forum_options... else do not consider it (not updating it) if ($action == 'add') { @@ -195,7 +209,7 @@ class acp_forums ($action != 'edit' || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')))) { copy_forum_permissions($forum_perm_from, $forum_data['forum_id'], ($action == 'edit') ? true : false); - cache_moderators(); + phpbb_cache_moderators($db, $cache, $auth); $copied_permissions = true; } /* Commented out because of questionable UI workflow - re-visit for 3.0.7 @@ -256,6 +270,12 @@ class acp_forums $cache->destroy('sql', FORUMS_TABLE); } + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array('success' => ($move_forum_name !== false))); + } + break; case 'sync': @@ -266,7 +286,7 @@ class acp_forums @set_time_limit(0); - $sql = 'SELECT forum_name, forum_topics_real + $sql = 'SELECT forum_name, (forum_topics_approved + forum_topics_unapproved + forum_topics_softdeleted) AS total_topics FROM ' . FORUMS_TABLE . " WHERE forum_id = $forum_id"; $result = $db->sql_query($sql); @@ -278,7 +298,7 @@ class acp_forums trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } - if ($row['forum_topics_real']) + if ($row['total_topics']) { $sql = 'SELECT MIN(topic_id) as min_topic_id, MAX(topic_id) as max_topic_id FROM ' . TOPICS_TABLE . ' @@ -297,7 +317,6 @@ class acp_forums $end = $start + $batch_size; // Sync all topics in batch mode... - sync('topic_approved', 'range', 'topic_id BETWEEN ' . $start . ' AND ' . $end, true, false); sync('topic', 'range', 'topic_id BETWEEN ' . $start . ' AND ' . $end, true, true); if ($end < $row2['max_topic_id']) @@ -313,15 +332,15 @@ class acp_forums $start += $batch_size; - $url = $this->u_action . "&parent_id={$this->parent_id}&f=$forum_id&action=sync&start=$start&topics_done=$topics_done&total={$row['forum_topics_real']}"; + $url = $this->u_action . "&parent_id={$this->parent_id}&f=$forum_id&action=sync&start=$start&topics_done=$topics_done&total={$row['total_topics']}"; meta_refresh(0, $url); $template->assign_vars(array( - 'U_PROGRESS_BAR' => $this->u_action . "&action=progress_bar&start=$topics_done&total={$row['forum_topics_real']}", - 'UA_PROGRESS_BAR' => addslashes($this->u_action . "&action=progress_bar&start=$topics_done&total={$row['forum_topics_real']}"), + 'U_PROGRESS_BAR' => $this->u_action . "&action=progress_bar&start=$topics_done&total={$row['total_topics']}", + 'UA_PROGRESS_BAR' => addslashes($this->u_action . "&action=progress_bar&start=$topics_done&total={$row['total_topics']}"), 'S_CONTINUE_SYNC' => true, - 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $topics_done, $row['forum_topics_real'])) + 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $topics_done, $row['total_topics'])) ); return; @@ -335,7 +354,7 @@ class acp_forums 'U_PROGRESS_BAR' => $this->u_action . '&action=progress_bar', 'UA_PROGRESS_BAR' => addslashes($this->u_action . '&action=progress_bar'), 'S_CONTINUE_SYNC' => true, - 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], 0, $row['forum_topics_real'])) + 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], 0, $row['total_topics'])) ); return; @@ -380,6 +399,9 @@ class acp_forums $forum_data['forum_flags'] += (request_var('enable_quick_reply', false)) ? FORUM_FLAG_QUICK_REPLY : 0; } + // Initialise $row, so we always have it in the event + $row = array(); + // Show form to create/modify a forum if ($action == 'edit') { @@ -439,6 +461,9 @@ class acp_forums 'prune_days' => 7, 'prune_viewed' => 7, 'prune_freq' => 1, + 'enable_shadow_prune' => false, + 'prune_shadow_days' => 7, + 'prune_shadow_freq' => 1, 'forum_flags' => FORUM_FLAG_POST_REVIEW + FORUM_FLAG_ACTIVE_TOPICS, 'forum_options' => 0, 'forum_password' => '', @@ -447,6 +472,24 @@ class acp_forums } } + /** + * Initialise data before we display the add/edit form + * + * @event core.acp_manage_forums_initialise_data + * @var string action Type of the action: add|edit + * @var bool update Do we display the form only + * or did the user press submit + * @var int forum_id When editing: the forum id, + * when creating: the parent forum id + * @var array row Array with current forum data + * empty when creating new forum + * @var array forum_data Array with new forum data + * @var string parents_list List of parent options + * @since 3.1.0-a1 + */ + $vars = array('action', 'update', 'forum_id', 'row', 'forum_data', 'parents_list'); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_initialise_data', compact($vars))); + $forum_rules_data = array( 'text' => $forum_data['forum_rules'], 'allow_bbcode' => true, @@ -576,7 +619,7 @@ class acp_forums $errors[] = $user->lang['FORUM_PASSWORD_OLD']; } - $template->assign_vars(array( + $template_data = array( 'S_EDIT_FORUM' => true, 'S_ERROR' => (sizeof($errors)) ? true : false, 'S_PARENT_ID' => $this->parent_id, @@ -600,6 +643,8 @@ class acp_forums 'PRUNE_FREQ' => $forum_data['prune_freq'], 'PRUNE_DAYS' => $forum_data['prune_days'], 'PRUNE_VIEWED' => $forum_data['prune_viewed'], + 'PRUNE_SHADOW_FREQ' => $forum_data['prune_shadow_freq'], + 'PRUNE_SHADOW_DAYS' => $forum_data['prune_shadow_days'], 'TOPICS_PER_PAGE' => $forum_data['forum_topics_per_page'], 'FORUM_RULES_LINK' => $forum_data['forum_rules_link'], 'FORUM_RULES' => $forum_data['forum_rules'], @@ -632,6 +677,7 @@ class acp_forums 'S_DISPLAY_SUBFORUM_LIST' => ($forum_data['display_subforum_list']) ? true : false, 'S_DISPLAY_ON_INDEX' => ($forum_data['display_on_index']) ? true : false, 'S_PRUNE_ENABLE' => ($forum_data['enable_prune']) ? true : false, + 'S_PRUNE_SHADOW_ENABLE' => ($forum_data['enable_shadow_prune']) ? true : false, 'S_FORUM_LINK_TRACK' => ($forum_data['forum_flags'] & FORUM_FLAG_LINK_TRACK) ? true : false, 'S_PRUNE_OLD_POLLS' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_POLL) ? true : false, 'S_PRUNE_ANNOUNCE' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_ANNOUNCE) ? true : false, @@ -641,7 +687,40 @@ class acp_forums 'S_ENABLE_POST_REVIEW' => ($forum_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) ? true : false, 'S_ENABLE_QUICK_REPLY' => ($forum_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) ? true : false, 'S_CAN_COPY_PERMISSIONS' => ($action != 'edit' || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth'))) ? true : false, - )); + ); + + /** + * Modify forum template data before we display the form + * + * @event core.acp_manage_forums_display_form + * @var string action Type of the action: add|edit + * @var bool update Do we display the form only + * or did the user press submit + * @var int forum_id When editing: the forum id, + * when creating: the parent forum id + * @var array row Array with current forum data + * empty when creating new forum + * @var array forum_data Array with new forum data + * @var string parents_list List of parent options + * @var array errors Array of errors, if you add errors + * ensure to update the template variables + * S_ERROR and ERROR_MSG to display it + * @var array template_data Array with new forum data + * @since 3.1.0-a1 + */ + $vars = array( + 'action', + 'update', + 'forum_id', + 'row', + 'forum_data', + 'parents_list', + 'errors', + 'template_data', + ); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_display_form', compact($vars))); + + $template->assign_vars($template_data); return; @@ -706,7 +785,7 @@ class acp_forums if (!empty($forum_perm_from) && $forum_perm_from != $forum_id) { copy_forum_permissions($forum_perm_from, $forum_id, true); - cache_moderators(); + phpbb_cache_moderators($db, $cache, $auth); $auth->acl_clear_prefetch(); $cache->destroy('sql', FORUMS_TABLE); @@ -795,8 +874,8 @@ class acp_forums 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', 'FORUM_NAME' => $row['forum_name'], 'FORUM_DESCRIPTION' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), - 'FORUM_TOPICS' => $row['forum_topics'], - 'FORUM_POSTS' => $row['forum_posts'], + 'FORUM_TOPICS' => $row['forum_topics_approved'], + 'FORUM_POSTS' => $row['forum_posts_approved'], 'S_FORUM_LINK' => ($forum_type == FORUM_LINK) ? true : false, 'S_FORUM_POST' => ($forum_type == FORUM_POST) ? true : false, @@ -866,10 +945,22 @@ class acp_forums */ function update_forum_data(&$forum_data) { - global $db, $user, $cache, $phpbb_root_path; + global $db, $user, $cache, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher; $errors = array(); + /** + * Validate the forum data before we create/update the forum + * + * @event core.acp_manage_forums_validate_data + * @var array forum_data Array with new forum data + * @var array errors Array of errors, should be strings and not + * language key. + * @since 3.1.0-a1 + */ + $vars = array('forum_data', 'errors'); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_validate_data', compact($vars))); + if ($forum_data['forum_name'] == '') { $errors[] = $user->lang['FORUM_NAME_EMPTY']; @@ -958,11 +1049,29 @@ class acp_forums } else { - $forum_data_sql['forum_password'] = phpbb_hash($forum_data_sql['forum_password']); + // Instantiate passwords manager + $passwords_manager = $phpbb_container->get('passwords.manager'); + + $forum_data_sql['forum_password'] = $passwords_manager->hash($forum_data_sql['forum_password']); } unset($forum_data_sql['forum_password_unset']); - if (!isset($forum_data_sql['forum_id'])) + /** + * Remove invalid values from forum_data_sql that should not be updated + * + * @event core.acp_manage_forums_update_data_before + * @var array forum_data Array with forum data + * @var array forum_data_sql Array with data we are going to update + * If forum_data_sql[forum_id] is set, we update + * that forum, otherwise a new one is created. + * @since 3.1.0-a1 + */ + $vars = array('forum_data', 'forum_data_sql'); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_update_data_before', compact($vars))); + + $is_new_forum = !isset($forum_data_sql['forum_id']); + + if ($is_new_forum) { // no forum_id means we're creating a new forum unset($forum_data_sql['type_action']); @@ -1055,7 +1164,8 @@ class acp_forums return array($user->lang['NO_FORUM_ACTION']); } - $forum_data_sql['forum_posts'] = $forum_data_sql['forum_topics'] = $forum_data_sql['forum_topics_real'] = $forum_data_sql['forum_last_post_id'] = $forum_data_sql['forum_last_poster_id'] = $forum_data_sql['forum_last_post_time'] = 0; + $forum_data_sql['forum_posts_approved'] = $forum_data_sql['forum_posts_unapproved'] = $forum_data_sql['forum_posts_softdeleted'] = $forum_data_sql['forum_topics_approved'] = $forum_data_sql['forum_topics_unapproved'] = $forum_data_sql['forum_topics_softdeleted'] = 0; + $forum_data_sql['forum_last_post_id'] = $forum_data_sql['forum_last_poster_id'] = $forum_data_sql['forum_last_post_time'] = 0; $forum_data_sql['forum_last_poster_name'] = $forum_data_sql['forum_last_poster_colour'] = ''; } else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_LINK) @@ -1175,9 +1285,12 @@ class acp_forums else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_POST) { // Changing a category to a forum? Reset the data (you can't post directly in a cat, you must use a forum) - $forum_data_sql['forum_posts'] = 0; - $forum_data_sql['forum_topics'] = 0; - $forum_data_sql['forum_topics_real'] = 0; + $forum_data_sql['forum_posts_approved'] = 0; + $forum_data_sql['forum_posts_unapproved'] = 0; + $forum_data_sql['forum_posts_softdeleted'] = 0; + $forum_data_sql['forum_topics_approved'] = 0; + $forum_data_sql['forum_topics_unapproved'] = 0; + $forum_data_sql['forum_topics_softdeleted'] = 0; $forum_data_sql['forum_last_post_id'] = 0; $forum_data_sql['forum_last_post_subject'] = ''; $forum_data_sql['forum_last_post_time'] = 0; @@ -1233,6 +1346,22 @@ class acp_forums add_log('admin', 'LOG_FORUM_EDIT', $forum_data['forum_name']); } + /** + * Event after a forum was updated or created + * + * @event core.acp_manage_forums_update_data_after + * @var array forum_data Array with forum data + * @var array forum_data_sql Array with data we updated + * @var bool is_new_forum Did we create a forum or update one + * If you want to overwrite this value, + * ensure to set forum_data_sql[forum_id] + * @var array errors Array of errors, should be strings and not + * language key. + * @since 3.1.0-a1 + */ + $vars = array('forum_data', 'forum_data_sql', 'is_new_forum', 'errors'); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_update_data_after', compact($vars))); + return $errors; } @@ -1241,7 +1370,7 @@ class acp_forums */ function move_forum($from_id, $to_id) { - global $db, $user; + global $db, $user, $phpbb_dispatcher; $to_data = $moved_ids = $errors = array(); @@ -1253,10 +1382,30 @@ class acp_forums if ($to_data['forum_type'] == FORUM_LINK) { $errors[] = $user->lang['PARENT_IS_LINK_FORUM']; - return $errors; } } + /** + * Event when we move all children of one forum to another + * + * This event may be triggered, when a forum is deleted + * + * @event core.acp_manage_forums_move_children + * @var int from_id If of the current parent forum + * @var int to_id If of the new parent forum + * @var array errors Array of errors, should be strings and not + * language key. + * @since 3.1.0-a1 + */ + $vars = array('from_id', 'to_id', 'errors'); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_children', compact($vars))); + + // Return if there were errors + if (!empty($errors)) + { + return $errors; + } + $moved_forums = get_forum_branch($from_id, 'children', 'descending'); $from_data = $moved_forums[0]; $diff = sizeof($moved_forums) * 2; @@ -1336,7 +1485,30 @@ class acp_forums */ function move_forum_content($from_id, $to_id, $sync = true) { - global $db; + global $db, $phpbb_dispatcher; + + $errors = array(); + + /** + * Event when we move content from one forum to another + * + * @event core.acp_manage_forums_move_content + * @var int from_id If of the current parent forum + * @var int to_id If of the new parent forum + * @var bool sync Shall we sync the "to"-forum's data + * @var array errors Array of errors, should be strings and not + * language key. If this array is not empty, + * The content will not be moved. + * @since 3.1.0-a1 + */ + $vars = array('from_id', 'to_id', 'sync', 'errors'); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_content', compact($vars))); + + // Return if there were errors + if (!empty($errors)) + { + return $errors; + } $table_ary = array(LOG_TABLE, POSTS_TABLE, TOPICS_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE); @@ -1645,7 +1817,7 @@ class acp_forums FROM ' . POSTS_TABLE . ' WHERE forum_id = ' . $forum_id . ' AND post_postcount = 1 - AND post_approved = 1'; + AND post_visibility = ' . ITEM_APPROVED; $result = $db->sql_query($sql); $post_counts = array(); @@ -1655,7 +1827,7 @@ class acp_forums } $db->sql_freeresult($result); - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'mysql4': case 'mysqli': @@ -1783,7 +1955,7 @@ class acp_forums // Make sure the overall post/topic count is correct... $sql = 'SELECT COUNT(post_id) AS stat FROM ' . POSTS_TABLE . ' - WHERE post_approved = 1'; + WHERE post_visibility = ' . ITEM_APPROVED; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -1792,7 +1964,7 @@ class acp_forums $sql = 'SELECT COUNT(topic_id) AS stat FROM ' . TOPICS_TABLE . ' - WHERE topic_approved = 1'; + WHERE topic_visibility = ' . ITEM_APPROVED; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -1945,5 +2117,3 @@ class acp_forums } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php index c9d476b8ae..edfada1bf1 100644 --- a/phpBB/includes/acp/acp_groups.php +++ b/phpBB/includes/acp/acp_groups.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_groups { var $u_action; @@ -27,6 +27,7 @@ class acp_groups { global $config, $db, $user, $auth, $template, $cache; global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads; + global $request, $phpbb_container, $phpbb_dispatcher; $user->add_lang('acp/groups'); $this->tpl_name = 'acp_groups'; @@ -35,6 +36,12 @@ class acp_groups $form_key = 'acp_groups'; add_form_key($form_key); + if ($mode == 'position') + { + $this->manage_position(); + return; + } + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); // Check and set some common vars @@ -47,17 +54,17 @@ class acp_groups $start = request_var('start', 0); $update = (isset($_POST['update'])) ? true : false; - // Clear some vars - $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false; $group_row = array(); // Grab basic data for group, if group_id is set and exists if ($group_id) { - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . " - WHERE group_id = $group_id"; + $sql = 'SELECT g.*, t.teampage_position AS group_teampage + FROM ' . GROUPS_TABLE . ' g + LEFT JOIN ' . TEAMPAGE_TABLE . ' t + ON (t.group_id = g.group_id) + WHERE g.group_id = ' . $group_id; $result = $db->sql_query($sql); $group_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -133,7 +140,7 @@ class acp_groups if (confirm_box(true)) { $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name']; - group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row); + group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row); trigger_error($user->lang['GROUP_DEFS_UPDATED'] . adm_back_link($this->u_action . '&action=list&g=' . $group_id)); } else @@ -305,8 +312,46 @@ class acp_groups $error = array(); $user->add_lang('ucp'); - $avatar_select = basename(request_var('avatar_select', '')); - $category = basename(request_var('category', '')); + // Setup avatar data for later + $avatars_enabled = false; + $avatar_drivers = null; + $avatar_data = null; + $avatar_error = array(); + + if ($config['allow_avatar']) + { + $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); + $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers(); + + // This is normalised data, without the group_ prefix + $avatar_data = \phpbb\avatar\manager::clean_row($group_row, 'group'); + if (!isset($avatar_data['id'])) + { + $avatar_data['id'] = 'g' . $group_id; + } + } + + if ($request->is_set_post('avatar_delete')) + { + if (confirm_box(true)) + { + $avatar_data['id'] = substr($avatar_data['id'], 1); + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, GROUPS_TABLE, 'group_'); + + $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; + trigger_error($user->lang[$message] . adm_back_link($this->u_action)); + } + else + { + confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( + 'avatar_delete' => true, + 'i' => $id, + 'mode' => $mode, + 'g' => $group_id, + 'action' => $action)) + ); + } + } // Did we submit? if ($update) @@ -324,17 +369,12 @@ class acp_groups $allow_desc_urls = request_var('desc_parse_urls', false); $allow_desc_smilies = request_var('desc_parse_smilies', false); - $data['uploadurl'] = request_var('uploadurl', ''); - $data['remotelink'] = request_var('remotelink', ''); - $data['width'] = request_var('width', ''); - $data['height'] = request_var('height', ''); - $delete = request_var('delete', ''); - $submit_ary = array( 'colour' => request_var('group_colour', ''), 'rank' => request_var('group_rank', 0), 'receive_pm' => isset($_REQUEST['group_receive_pm']) ? 1 : 0, 'legend' => isset($_REQUEST['group_legend']) ? 1 : 0, + 'teampage' => isset($_REQUEST['group_teampage']) ? 1 : 0, 'message_limit' => request_var('group_message_limit', 0), 'max_recipients' => request_var('group_max_recipients', 0), 'founder_manage' => 0, @@ -346,81 +386,39 @@ class acp_groups $submit_ary['founder_manage'] = isset($_REQUEST['group_founder_manage']) ? 1 : 0; } - if (!empty($_FILES['uploadfile']['tmp_name']) || $data['uploadurl'] || $data['remotelink']) + if ($config['allow_avatar']) { - // Avatar stuff - $var_ary = array( - 'uploadurl' => array('string', true, 5, 255), - 'remotelink' => array('string', true, 5, 255), - 'width' => array('string', true, 1, 3), - 'height' => array('string', true, 1, 3), - ); - - if (!($error = validate_data($data, $var_ary))) - { - $data['user_id'] = "g$group_id"; + // Handle avatar + $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', '')); - if ((!empty($_FILES['uploadfile']['tmp_name']) || $data['uploadurl']) && $can_upload) - { - list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_upload($data, $error); - } - else if ($data['remotelink']) - { - list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_remote($data, $error); - } - } - } - else if ($avatar_select && $config['allow_avatar_local']) - { - // check avatar gallery - if (is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category)) + if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) { - $submit_ary['avatar_type'] = AVATAR_GALLERY; + $driver = $phpbb_avatar_manager->get_driver($driver_name); + $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error); - list($submit_ary['avatar_width'], $submit_ary['avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $avatar_select); - $submit_ary['avatar'] = $category . '/' . $avatar_select; - } - } - else if ($delete) - { - $submit_ary['avatar'] = ''; - $submit_ary['avatar_type'] = $submit_ary['avatar_width'] = $submit_ary['avatar_height'] = 0; - } - else if ($data['width'] && $data['height']) - { - // Only update the dimensions? - if ($config['avatar_max_width'] || $config['avatar_max_height']) - { - if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height']) + if ($result && empty($avatar_error)) { - $error[] = sprintf($user->lang['AVATAR_WRONG_SIZE'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], $data['width'], $data['height']); + $result['avatar_type'] = $driver_name; + $submit_ary = array_merge($submit_ary, $result); } } - - if (!sizeof($error)) + else { - if ($config['avatar_min_width'] || $config['avatar_min_height']) + $driver = $phpbb_avatar_manager->get_driver($avatar_data['avatar_type']); + if ($driver) { - if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height']) - { - $error[] = sprintf($user->lang['AVATAR_WRONG_SIZE'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], $data['width'], $data['height']); - } + $driver->delete($avatar_data); } - } - if (!sizeof($error)) - { - $submit_ary['avatar_width'] = $data['width']; - $submit_ary['avatar_height'] = $data['height']; + // Removing the avatar + $submit_ary['avatar_type'] = ''; + $submit_ary['avatar'] = ''; + $submit_ary['avatar_width'] = 0; + $submit_ary['avatar_height'] = 0; } - } - if ((isset($submit_ary['avatar']) && $submit_ary['avatar'] && (!isset($group_row['group_avatar']))) || $delete) - { - if (isset($group_row['group_avatar']) && $group_row['group_avatar']) - { - avatar_delete('group', $group_row, true); - } + // Merge any avatar errors into the primary error array + $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error)); } /* @@ -434,6 +432,42 @@ class acp_groups 'colour' => array('hex_colour', true), ); + /** + * Request group data and operate on it + * + * @event core.acp_manage_group_request_data + * @var string action Type of the action: add|edit + * @var int group_id The group id + * @var array group_row Array with new group data + * @var array error Array of errors, if you add errors + * ensure to update the template variables + * S_ERROR and ERROR_MSG to display it + * @var string group_name The group name + * @var string group_desc The group description + * @var int group_type The group type + * @var bool allow_desc_bbcode Allow bbcode in group description: true|false + * @var bool allow_desc_urls Allow urls in group description: true|false + * @var bool allow_desc_smilies Allow smiles in group description: true|false + * @var array submit_ary Array with new group data + * @var array validation_checks Array with validation data + * @since 3.1.0-b5 + */ + $vars = array( + 'action', + 'group_id', + 'group_row', + 'error', + 'group_name', + 'group_desc', + 'group_type', + 'allow_desc_bbcode', + 'allow_desc_urls', + 'allow_desc_smilies', + 'submit_ary', + 'validation_checks', + ); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_group_request_data', compact($vars))); + if ($validation_error = validate_data($submit_ary, $validation_checks)) { // Replace "error" string with its real, localised form @@ -445,26 +479,66 @@ class acp_groups // Only set the rank, colour, etc. if it's changed or if we're adding a new // group. This prevents existing group members being updated if no changes // were made. + // However there are some attributes that need to be set everytime, + // otherwise the group gets removed from the feature. + $set_attributes = array('legend', 'teampage'); $group_attributes = array(); $test_variables = array( 'rank' => 'int', 'colour' => 'string', 'avatar' => 'string', - 'avatar_type' => 'int', + 'avatar_type' => 'string', 'avatar_width' => 'int', 'avatar_height' => 'int', 'receive_pm' => 'int', 'legend' => 'int', + 'teampage' => 'int', 'message_limit' => 'int', 'max_recipients'=> 'int', 'founder_manage'=> 'int', 'skip_auth' => 'int', ); + /** + * Initialise data before we display the add/edit form + * + * @event core.acp_manage_group_initialise_data + * @var string action Type of the action: add|edit + * @var int group_id The group id + * @var array group_row Array with new group data + * @var array error Array of errors, if you add errors + * ensure to update the template variables + * S_ERROR and ERROR_MSG to display it + * @var string group_name The group name + * @var string group_desc The group description + * @var int group_type The group type + * @var bool allow_desc_bbcode Allow bbcode in group description: true|false + * @var bool allow_desc_urls Allow urls in group description: true|false + * @var bool allow_desc_smilies Allow smiles in group description: true|false + * @var array submit_ary Array with new group data + * @var array test_variables Array with variables for test + * @since 3.1.0-b5 + */ + $vars = array( + 'action', + 'group_id', + 'group_row', + 'error', + 'group_name', + 'group_desc', + 'group_type', + 'allow_desc_bbcode', + 'allow_desc_urls', + 'allow_desc_smilies', + 'submit_ary', + 'test_variables', + ); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_group_initialise_data', compact($vars))); + foreach ($test_variables as $test => $type) { - if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test])) + if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test] || isset($group_attributes['group_avatar']) && strpos($test, 'avatar') === 0 || in_array($test, $set_attributes))) { settype($submit_ary[$test], $type); $group_attributes['group_' . $test] = $group_row['group_' . $test] = $submit_ary[$test]; @@ -521,7 +595,7 @@ class acp_groups } } - $cache->destroy('sql', GROUPS_TABLE); + $cache->destroy('sql', array(GROUPS_TABLE, TEAMPAGE_TABLE)); $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; trigger_error($user->lang[$message] . adm_back_link($this->u_action)); @@ -581,13 +655,44 @@ class acp_groups $type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : ''; $type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : ''; - $avatar_img = (!empty($group_row['group_avatar'])) ? get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR') : '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />'; + // Load up stuff for avatars + if ($config['allow_avatar']) + { + $avatars_enabled = false; + $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type'])); + + foreach ($avatar_drivers as $current_driver) + { + $driver = $phpbb_avatar_manager->get_driver($current_driver); - $display_gallery = (isset($_POST['display_gallery'])) ? true : false; + $avatars_enabled = true; + $config_name = $phpbb_avatar_manager->get_driver_config_name($driver); + $template->set_filenames(array( + 'avatar' => "acp_avatar_options_{$config_name}.html", + )); - if ($config['allow_avatar_local'] && $display_gallery) + if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error)) + { + $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); + $driver_upper = strtoupper($driver_name); + $template->assign_block_vars('avatar_drivers', array( + 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), + 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), + + 'DRIVER' => $driver_name, + 'SELECTED' => $current_driver == $selected_driver, + 'OUTPUT' => $template->assign_display('avatar'), + )); + } + } + } + + $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true); + + if (isset($phpbb_avatar_manager) && !$update) { - avatar_gallery($category, $avatar_select, 4); + // Merge any avatar errors into the primary error array + $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error)); } $back_link = request_var('back_link', ''); @@ -608,12 +713,10 @@ class acp_groups 'S_ADD_GROUP' => ($action == 'add') ? true : false, 'S_GROUP_PERM' => ($action == 'add' && $auth->acl_get('a_authgroups') && $auth->acl_gets('a_aauth', 'a_fauth', 'a_mauth', 'a_uauth')) ? true : false, 'S_INCLUDE_SWATCH' => true, - 'S_CAN_UPLOAD' => $can_upload, 'S_ERROR' => (sizeof($error)) ? true : false, 'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false, - 'S_DISPLAY_GALLERY' => ($config['allow_avatar_local'] && !$display_gallery) ? true : false, - 'S_IN_GALLERY' => ($config['allow_avatar_local'] && $display_gallery) ? true : false, 'S_USER_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false, + 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled), 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '', 'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name, @@ -622,6 +725,7 @@ class acp_groups 'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '', 'GROUP_FOUNDER_MANAGE' => (isset($group_row['group_founder_manage']) && $group_row['group_founder_manage']) ? ' checked="checked"' : '', 'GROUP_LEGEND' => (isset($group_row['group_legend']) && $group_row['group_legend']) ? ' checked="checked"' : '', + 'GROUP_TEAMPAGE' => (isset($group_row['group_teampage']) && $group_row['group_teampage']) ? ' checked="checked"' : '', 'GROUP_MESSAGE_LIMIT' => (isset($group_row['group_message_limit'])) ? $group_row['group_message_limit'] : 0, 'GROUP_MAX_RECIPIENTS' => (isset($group_row['group_max_recipients'])) ? $group_row['group_max_recipients'] : 0, 'GROUP_COLOUR' => (isset($group_row['group_colour'])) ? $group_row['group_colour'] : '', @@ -633,8 +737,7 @@ class acp_groups 'S_RANK_OPTIONS' => $rank_options, 'S_GROUP_OPTIONS' => group_select_options(false, false, (($user->data['user_type'] == USER_FOUNDER) ? false : 0)), - 'AVATAR' => $avatar_img, - 'AVATAR_IMAGE' => $avatar_img, + 'AVATAR' => empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar, 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'], 'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '', 'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '', @@ -651,11 +754,43 @@ class acp_groups 'GROUP_HIDDEN' => $type_hidden, 'U_BACK' => $u_back, - 'U_SWATCH' => append_sid("{$phpbb_admin_path}swatch.$phpEx", 'form=settings&name=group_colour'), 'U_ACTION' => "{$this->u_action}&action=$action&g=$group_id", - 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], round($config['avatar_filesize'] / 1024)), + 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(), )); + /** + * Modify group template data before we display the form + * + * @event core.acp_manage_group_display_form + * @var string action Type of the action: add|edit + * @var bool update Do we display the form only + * or did the user press submit + * @var int group_id The group id + * @var array group_row Array with new group data + * @var string group_name The group name + * @var int group_type The group type + * @var array group_desc_data The group description data + * @var string group_rank The group rank + * @var string rank_options The rank options + * @var array error Array of errors, if you add errors + * ensure to update the template variables + * S_ERROR and ERROR_MSG to display it + * @since 3.1.0-b5 + */ + $vars = array( + 'action', + 'update', + 'group_id', + 'group_row', + 'group_desc_data', + 'group_name', + 'group_type', + 'group_rank', + 'rank_options', + 'error', + ); + extract($phpbb_dispatcher->trigger_event('core.acp_manage_group_display_form', compact($vars))); + return; break; @@ -667,6 +802,7 @@ class acp_groups } $this->page_title = 'GROUP_MEMBERS'; + $pagination = $phpbb_container->get('pagination'); // Grab the leaders - always, on every page... $sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_regdate, u.user_colour, u.user_posts, u.group_id, ug.group_leader, ug.user_pending @@ -709,13 +845,14 @@ class acp_groups $s_action_options .= '<option value="' . $option . '">' . $user->lang['GROUP_' . $lang] . '</option>'; } + $base_url = $this->u_action . "&action=$action&g=$group_id"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_members, $config['topics_per_page'], $start); + $template->assign_vars(array( 'S_LIST' => true, 'S_GROUP_SPECIAL' => ($group_row['group_type'] == GROUP_SPECIAL) ? true : false, 'S_ACTION_OPTIONS' => $s_action_options, - 'S_ON_PAGE' => on_page($total_members, $config['topics_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&action=$action&g=$group_id", $total_members, $config['topics_per_page'], $start, true), 'GROUP_NAME' => ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'], 'U_ACTION' => $this->u_action . "&g=$group_id", @@ -831,6 +968,222 @@ class acp_groups } } } -} -?> + public function manage_position() + { + global $config, $db, $template, $user, $request, $phpbb_container; + + $this->tpl_name = 'acp_groups_position'; + $this->page_title = 'ACP_GROUPS_POSITION'; + + $field = $request->variable('field', ''); + $action = $request->variable('action', ''); + $group_id = $request->variable('g', 0); + $teampage_id = $request->variable('t', 0); + $category_id = $request->variable('c', 0); + + if ($field && !in_array($field, array('legend', 'teampage'))) + { + // Invalid mode + trigger_error($user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING); + } + else if ($field && in_array($field, array('legend', 'teampage'))) + { + + $group_position = $phpbb_container->get('groupposition.' . $field); + } + + if ($field == 'teampage') + { + try + { + switch ($action) + { + case 'add': + $group_position->add_group_teampage($group_id, $category_id); + break; + + case 'add_category': + $group_position->add_category_teampage($request->variable('category_name', '', true)); + break; + + case 'delete': + $group_position->delete_teampage($teampage_id); + break; + + case 'move_up': + $group_position->move_up_teampage($teampage_id); + break; + + case 'move_down': + $group_position->move_down_teampage($teampage_id); + break; + } + } + catch (\phpbb\groupposition\exception $exception) + { + trigger_error($user->lang($exception->getMessage()) . adm_back_link($this->u_action), E_USER_WARNING); + } + } + else if ($field == 'legend') + { + try + { + switch ($action) + { + case 'add': + $group_position->add_group($group_id); + break; + + case 'delete': + $group_position->delete_group($group_id); + break; + + case 'move_up': + $group_position->move_up($group_id); + break; + + case 'move_down': + $group_position->move_down($group_id); + break; + } + } + catch (\phpbb\groupposition\exception $exception) + { + trigger_error($user->lang($exception->getMessage()) . adm_back_link($this->u_action), E_USER_WARNING); + } + } + else + { + switch ($action) + { + case 'set_config_teampage': + $config->set('teampage_forums', $request->variable('teampage_forums', 0)); + $config->set('teampage_memberships', $request->variable('teampage_memberships', 0)); + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + break; + + case 'set_config_legend': + $config->set('legend_sort_groupname', $request->variable('legend_sort_groupname', 0)); + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + break; + } + } + + if (($action == 'move_up' || $action == 'move_down') && $request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array('success' => true)); + } + + $sql = 'SELECT group_id, group_name, group_colour, group_type, group_legend + FROM ' . GROUPS_TABLE . ' + ORDER BY group_legend ASC, group_type DESC, group_name ASC'; + $result = $db->sql_query($sql); + + $s_group_select_legend = ''; + while ($row = $db->sql_fetchrow($result)) + { + $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']; + if ($row['group_legend']) + { + $template->assign_block_vars('legend', array( + 'GROUP_NAME' => $group_name, + 'GROUP_COLOUR' => ($row['group_colour']) ? '#' . $row['group_colour'] : '', + 'GROUP_TYPE' => $user->lang[\phpbb\groupposition\legend::group_type_language($row['group_type'])], + + 'U_MOVE_DOWN' => "{$this->u_action}&field=legend&action=move_down&g=" . $row['group_id'], + 'U_MOVE_UP' => "{$this->u_action}&field=legend&action=move_up&g=" . $row['group_id'], + 'U_DELETE' => "{$this->u_action}&field=legend&action=delete&g=" . $row['group_id'], + )); + } + else + { + $template->assign_block_vars('add_legend', array( + 'GROUP_ID' => (int) $row['group_id'], + 'GROUP_NAME' => $group_name, + 'GROUP_SPECIAL' => ($row['group_type'] == GROUP_SPECIAL), + )); + } + } + $db->sql_freeresult($result); + + $category_url_param = (($category_id) ? '&c=' . $category_id : ''); + + $sql = 'SELECT t.*, g.group_name, g.group_colour, g.group_type + FROM ' . TEAMPAGE_TABLE . ' t + LEFT JOIN ' . GROUPS_TABLE . ' g + ON (t.group_id = g.group_id) + WHERE t.teampage_parent = ' . $category_id . ' + OR t.teampage_id = ' . $category_id . ' + ORDER BY t.teampage_position ASC'; + $result = $db->sql_query($sql); + + $category_data = array(); + while ($row = $db->sql_fetchrow($result)) + { + if ($row['teampage_id'] == $category_id) + { + $template->assign_vars(array( + 'CURRENT_CATEGORY_NAME' => $row['teampage_name'], + )); + continue; + } + + if ($row['group_id']) + { + $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']; + $group_type = $user->lang[\phpbb\groupposition\teampage::group_type_language($row['group_type'])]; + } + else + { + $group_name = $row['teampage_name']; + $group_type = ''; + } + + $template->assign_block_vars('teampage', array( + 'GROUP_NAME' => $group_name, + 'GROUP_COLOUR' => ($row['group_colour']) ? '#' . $row['group_colour'] : '', + 'GROUP_TYPE' => $group_type, + + 'U_CATEGORY' => (!$row['group_id']) ? "{$this->u_action}&c=" . $row['teampage_id'] : '', + 'U_MOVE_DOWN' => "{$this->u_action}&field=teampage&action=move_down{$category_url_param}&t=" . $row['teampage_id'], + 'U_MOVE_UP' => "{$this->u_action}&field=teampage&action=move_up{$category_url_param}&t=" . $row['teampage_id'], + 'U_DELETE' => "{$this->u_action}&field=teampage&action=delete{$category_url_param}&t=" . $row['teampage_id'], + )); + } + $db->sql_freeresult($result); + + $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type + FROM ' . GROUPS_TABLE . ' g + LEFT JOIN ' . TEAMPAGE_TABLE . ' t + ON (t.group_id = g.group_id) + WHERE t.teampage_id IS NULL + ORDER BY g.group_type DESC, g.group_name ASC'; + $result = $db->sql_query($sql); + + $s_group_select_teampage = ''; + while ($row = $db->sql_fetchrow($result)) + { + $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']; + $template->assign_block_vars('add_teampage', array( + 'GROUP_ID' => (int) $row['group_id'], + 'GROUP_NAME' => $group_name, + 'GROUP_SPECIAL' => ($row['group_type'] == GROUP_SPECIAL), + )); + } + $db->sql_freeresult($result); + + $template->assign_vars(array( + 'U_ACTION' => $this->u_action, + 'U_ACTION_LEGEND' => $this->u_action . '&field=legend', + 'U_ACTION_TEAMPAGE' => $this->u_action . '&field=teampage' . $category_url_param, + 'U_ACTION_TEAMPAGE_CAT' => $this->u_action . '&field=teampage_cat', + + 'S_TEAMPAGE_CATEGORY' => $category_id, + 'DISPLAY_FORUMS' => ($config['teampage_forums']) ? true : false, + 'DISPLAY_MEMBERSHIPS' => $config['teampage_memberships'], + 'LEGEND_SORT_GROUPNAME' => ($config['legend_sort_groupname']) ? true : false, + )); + } +} diff --git a/phpBB/includes/acp/acp_icons.php b/phpBB/includes/acp/acp_icons.php index 24f6cbbcbf..9265415dd1 100644 --- a/phpBB/includes/acp/acp_icons.php +++ b/phpBB/includes/acp/acp_icons.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,7 +21,6 @@ if (!defined('IN_PHPBB')) /** * @todo [smilies] check regular expressions for special char replacements (stored specialchared in db) -* @package acp */ class acp_icons { @@ -28,6 +30,7 @@ class acp_icons { global $db, $user, $auth, $template, $cache; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $request, $phpbb_container; $user->add_lang('acp/posting'); @@ -203,7 +206,6 @@ class acp_icons unset($_images[$row[$fields . '_url']]); } - if ($row[$fields . '_id'] == $icon_id) { $after = true; @@ -307,7 +309,6 @@ class acp_icons 'IMG_SRC' => $phpbb_root_path . $img_path . '/' . $default_row['smiley_url'], 'IMG_PATH' => $img_path, - 'PHPBB_ROOT_PATH' => $phpbb_root_path, 'CODE' => $default_row['code'], 'EMOTION' => $default_row['emotion'], @@ -338,7 +339,7 @@ class acp_icons $image_display_on_posting = (isset($_POST['display_on_posting'])) ? request_var('display_on_posting', array('' => 0)) : array(); // Ok, add the relevant bits if we are adding new codes to existing emoticons... - if (!empty($_POST['add_additional_code'])) + if ($request->variable('add_additional_code', false, false, \phpbb\request\request_interface::POST)) { $add_image = request_var('add_image', ''); $add_code = utf8_normalize_nfc(request_var('add_code', '', true)); @@ -354,7 +355,7 @@ class acp_icons $image_width[$add_image] = request_var('add_width', 0); $image_height[$add_image] = request_var('add_height', 0); - if (!empty($_POST['add_display_on_posting'])) + if ($request->variable('add_display_on_posting', false, false, \phpbb\request\request_interface::POST)) { $image_display_on_posting[$add_image] = 1; } @@ -378,7 +379,7 @@ class acp_icons if ($smiley_count + $addable_smileys_count > SMILEY_LIMIT) { - trigger_error(sprintf($user->lang['TOO_MANY_SMILIES'], SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING); + trigger_error($user->lang('TOO_MANY_SMILIES', SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING); } } @@ -480,27 +481,13 @@ class acp_icons $icons_updated++; } - } + } } $cache->destroy('_icons'); $cache->destroy('sql', $table); - $level = E_USER_NOTICE; - switch ($icons_updated) - { - case 0: - $suc_lang = "{$lang}_NONE"; - $level = E_USER_WARNING; - break; - - case 1: - $suc_lang = "{$lang}_ONE"; - break; - - default: - $suc_lang = $lang; - } + $level = ($icons_updated) ? E_USER_NOTICE : E_USER_WARNING; $errormsgs = ''; foreach ($errors as $img => $error) { @@ -508,11 +495,11 @@ class acp_icons } if ($action == 'modify') { - trigger_error($user->lang[$suc_lang . '_EDITED'] . $errormsgs . adm_back_link($this->u_action), $level); + trigger_error($user->lang($lang . '_EDITED', $icons_updated) . $errormsgs . adm_back_link($this->u_action), $level); } else { - trigger_error($user->lang[$suc_lang . '_ADDED'] . $errormsgs . adm_back_link($this->u_action), $level); + trigger_error($user->lang($lang . '_ADDED', $icons_updated) . $errormsgs . adm_back_link($this->u_action), $level); } break; @@ -551,10 +538,10 @@ class acp_icons // The user has already selected a smilies_pak file if ($current == 'delete') { - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'sqlite': - case 'firebird': + case 'sqlite3': $db->sql_query('DELETE FROM ' . $table); break; @@ -598,7 +585,7 @@ class acp_icons $smiley_count = $this->item_count($table); if ($smiley_count + sizeof($pak_ary) > SMILEY_LIMIT) { - trigger_error(sprintf($user->lang['TOO_MANY_SMILIES'], SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING); + trigger_error($user->lang('TOO_MANY_SMILIES', SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING); } } @@ -750,7 +737,7 @@ class acp_icons { garbage_collection(); - header('Pragma: public'); + header('Cache-Control: public'); // Send out the Headers header('Content-Type: text/x-delimtext; name="' . $mode . '.pak"'); @@ -796,6 +783,18 @@ class acp_icons $cache->destroy('_icons'); $cache->destroy('sql', $table); + + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $notice, + 'REFRESH_DATA' => array( + 'time' => 3 + ) + )); + } } else { @@ -835,9 +834,10 @@ class acp_icons WHERE {$fields}_order = $switch_order_id AND {$fields}_id <> $icon_id"; $db->sql_query($sql); + $move_executed = (bool) $db->sql_affectedrows(); // Only update the other entry too if the previous entry got updated - if ($db->sql_affectedrows()) + if ($move_executed) { $sql = "UPDATE $table SET {$fields}_order = $switch_order_id @@ -849,6 +849,14 @@ class acp_icons $cache->destroy('_icons'); $cache->destroy('sql', $table); + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'success' => $move_executed, + )); + } + break; } @@ -896,6 +904,7 @@ class acp_icons ); $spacer = false; + $pagination = $phpbb_container->get('pagination'); $pagination_start = request_var('start', 0); $item_count = $this->item_count($table); @@ -930,9 +939,7 @@ class acp_icons } $db->sql_freeresult($result); - $template->assign_var('PAGINATION', - generate_pagination($this->u_action, $item_count, $config['smilies_per_page'], $pagination_start, true) - ); + $pagination->generate_template_pagination($this->u_action, 'pagination', 'start', $item_count, $config['smilies_per_page'], $pagination_start); } /** @@ -954,5 +961,3 @@ class acp_icons return $item_count; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php index f3f332d707..e96c42de05 100644 --- a/phpBB/includes/acp/acp_inactive.php +++ b/phpBB/includes/acp/acp_inactive.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_inactive { var $u_action; @@ -31,7 +31,7 @@ class acp_inactive function main($id, $mode) { - global $config, $db, $user, $auth, $template; + global $config, $db, $user, $auth, $template, $phpbb_container; global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix; include($phpbb_root_path . 'includes/functions_user.' . $phpEx); @@ -50,6 +50,7 @@ class acp_inactive $form_key = 'acp_inactive'; add_form_key($form_key); + $pagination = $phpbb_container->get('pagination'); // We build the sort key and per page settings here, because they may be needed later @@ -116,7 +117,7 @@ class acp_inactive { $messenger->template('admin_welcome_activated', $row['user_lang']); - $messenger->to($row['user_email'], $row['username']); + $messenger->set_addresses($row); $messenger->anti_abuse_headers($config, $user); @@ -137,6 +138,8 @@ class acp_inactive add_log('admin', 'LOG_USER_ACTIVE', $row['username']); add_log('user', $row['user_id'], 'LOG_USER_ACTIVE_USER'); } + + trigger_error(sprintf($user->lang['LOG_INACTIVE_ACTIVATE'], implode($user->lang['COMMA_SEPARATOR'], $user_affected) . ' ' . adm_back_link($this->u_action))); } // For activate we really need to redirect, else a refresh can result in users being deactivated again @@ -154,12 +157,11 @@ class acp_inactive trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } - foreach ($mark as $user_id) - { - user_delete('retain', $user_id, $user_affected[$user_id]); - } + user_delete('retain', $mark, true); add_log('admin', 'LOG_INACTIVE_' . strtoupper($action), implode(', ', $user_affected)); + + trigger_error(sprintf($user->lang['LOG_INACTIVE_DELETE'], implode($user->lang['COMMA_SEPARATOR'], $user_affected) . ' ' . adm_back_link($this->u_action))); } else { @@ -203,8 +205,7 @@ class acp_inactive { $messenger->template('user_remind_inactive', $row['user_lang']); - $messenger->to($row['user_email'], $row['username']); - $messenger->im($row['user_jabber'], $row['username']); + $messenger->set_addresses($row); $messenger->anti_abuse_headers($config, $user); @@ -231,7 +232,8 @@ class acp_inactive $db->sql_query($sql); add_log('admin', 'LOG_INACTIVE_REMIND', implode(', ', $usernames)); - unset($usernames); + + trigger_error(sprintf($user->lang['LOG_INACTIVE_REMIND'], implode($user->lang['COMMA_SEPARATOR'], $usernames) . ' ' . adm_back_link($this->u_action))); } $db->sql_freeresult($result); @@ -284,6 +286,9 @@ class acp_inactive $option_ary += array('remind' => 'REMIND'); } + $base_url = $this->u_action . "&$u_sort_param&users_per_page=$per_page"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $inactive_count, $per_page, $start); + $template->assign_vars(array( 'S_INACTIVE_USERS' => true, 'S_INACTIVE_OPTIONS' => build_select($option_ary), @@ -291,8 +296,6 @@ class acp_inactive 'S_LIMIT_DAYS' => $s_limit_days, 'S_SORT_KEY' => $s_sort_key, 'S_SORT_DIR' => $s_sort_dir, - 'S_ON_PAGE' => on_page($inactive_count, $per_page, $start), - 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param&users_per_page=$per_page", $inactive_count, $per_page, $start, true), 'USERS_PER_PAGE' => $per_page, 'U_ACTION' => $this->u_action . "&$u_sort_param&users_per_page=$per_page&start=$start", @@ -302,5 +305,3 @@ class acp_inactive $this->page_title = 'ACP_INACTIVE_USERS'; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_jabber.php b/phpBB/includes/acp/acp_jabber.php index 9925527b34..8d2e9d41a3 100644 --- a/phpBB/includes/acp/acp_jabber.php +++ b/phpBB/includes/acp/acp_jabber.php @@ -1,11 +1,17 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. +* +*/ + +/** * @todo Check/enter/update transport info */ @@ -17,9 +23,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_jabber { var $u_action; @@ -44,13 +47,13 @@ class acp_jabber $this->tpl_name = 'acp_jabber'; $this->page_title = 'ACP_JABBER_SETTINGS'; - $jab_enable = request_var('jab_enable', (bool) $config['jab_enable']); - $jab_host = request_var('jab_host', (string) $config['jab_host']); - $jab_port = request_var('jab_port', (int) $config['jab_port']); - $jab_username = request_var('jab_username', (string) $config['jab_username']); - $jab_password = request_var('jab_password', (string) $config['jab_password']); - $jab_package_size = request_var('jab_package_size', (int) $config['jab_package_size']); - $jab_use_ssl = request_var('jab_use_ssl', (bool) $config['jab_use_ssl']); + $jab_enable = request_var('jab_enable', (bool) $config['jab_enable']); + $jab_host = request_var('jab_host', (string) $config['jab_host']); + $jab_port = request_var('jab_port', (int) $config['jab_port']); + $jab_username = request_var('jab_username', (string) $config['jab_username']); + $jab_password = request_var('jab_password', (string) $config['jab_password']); + $jab_package_size = request_var('jab_package_size', (int) $config['jab_package_size']); + $jab_use_ssl = request_var('jab_use_ssl', (bool) $config['jab_use_ssl']); $form_name = 'acp_jabber'; add_form_key($form_name); @@ -127,5 +130,3 @@ class acp_jabber )); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_language.php b/phpBB/includes/acp/acp_language.php index d560cdd0c5..60e338ae7c 100644 --- a/phpBB/includes/acp/acp_language.php +++ b/phpBB/includes/acp/acp_language.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_language { var $u_action; @@ -31,21 +31,13 @@ class acp_language function main($id, $mode) { - global $config, $db, $user, $auth, $template, $cache; - global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix; - global $safe_mode, $file_uploads; + global $config, $db, $user, $template; + global $phpbb_root_path, $phpEx, $request; include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx); - $this->default_variables(); - // Check and set some common vars - $action = (isset($_POST['update_details'])) ? 'update_details' : ''; - $action = (isset($_POST['download_file'])) ? 'download_file' : $action; - $action = (isset($_POST['upload_file'])) ? 'upload_file' : $action; - $action = (isset($_POST['upload_data'])) ? 'upload_data' : $action; - $action = (isset($_POST['submit_file'])) ? 'submit_file' : $action; $action = (isset($_POST['remove_store'])) ? 'details' : $action; $submit = (empty($action) && !isset($_POST['update']) && !isset($_POST['test_connection'])) ? false : true; @@ -55,11 +47,6 @@ class acp_language add_form_key('acp_lang'); $lang_id = request_var('id', 0); - if (isset($_POST['missing_file'])) - { - $missing_file = request_var('missing_file', array('' => 0)); - list($_REQUEST['language_file'], ) = array_keys($missing_file); - } $selected_lang_file = request_var('language_file', '|common.' . $phpEx); @@ -72,78 +59,8 @@ class 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', ''), request_var('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', ''), request_var('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' => (!empty($_REQUEST[$data])) ? request_var($data, '') : $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' => $_POST['entry']), true, STRIP); - - $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)) @@ -178,255 +95,6 @@ class acp_language trigger_error($user->lang['LANGUAGE_DETAILS_UPDATED'] . adm_back_link($this->u_action)); break; - case 'submit_file': - case 'download_file': - case 'upload_data': - - if (!$submit || !check_form_key($form_name)) - { - trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING); - } - - if (!$lang_id || empty($_POST['entry'])) - { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if ($this->language_directory != 'email' && !is_array($_POST['entry'])) - { - 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 ($this->language_directory == 'email') - { - // Email Template - $entry = $this->prepare_lang_entry($_POST['entry'], 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 (strpos($this->language_file, 'help_') === 0) - { - // Help File - $header .= '$help = array(' . "\n"; - fwrite($fp, $header); - - foreach ($_POST['entry'] 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($_value) . "',\n"; - } - - $entry .= "\t),\n"; - fwrite($fp, $entry); - } - - $footer = ");\n\n?>"; - fwrite($fp, $footer); - } - else - { - // Language File - $header .= $this->lang_header; - fwrite($fp, $header); - - foreach ($_POST['entry'] as $key => $value) - { - $entry = $this->format_lang_array($key, $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', ''), request_var('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) @@ -443,308 +111,82 @@ class acp_language $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) + if (!$lang_entries) { - 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); - } + trigger_error($user->lang['LANGUAGE_PACK_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); } - include_once($phpbb_root_path . 'includes/functions_transfer.' . $phpEx); - - $methods = transfer::methods(); - - foreach ($methods as $method) - { - $template->assign_block_vars('buttons', array( - 'VALUE' => $method - )); - } + $lang_iso = $lang_entries['lang_iso']; $template->assign_vars(array( 'S_DETAILS' => true, 'U_ACTION' => $this->u_action . "&action=details&id=$lang_id", 'U_BACK' => $this->u_action, + 'LANG_LOCAL_NAME' => $lang_entries['lang_local_name'], 'LANG_ENGLISH_NAME' => $lang_entries['lang_english_name'], - 'LANG_ISO' => $lang_entries['lang_iso'], + 'LANG_ISO' => $lang_iso, 'LANG_AUTHOR' => $lang_entries['lang_author'], - 'ALLOW_UPLOAD' => sizeof($methods) - ) - ); + 'L_MISSING_FILES' => $user->lang('THOSE_MISSING_LANG_FILES', $lang_entries['lang_local_name']), + 'L_MISSING_VARS_EXPLAIN' => $user->lang('THOSE_MISSING_LANG_VARIABLES', $lang_entries['lang_local_name']), + )); - // If current lang is different from the default lang, then first try to grab missing/additional vars + // If current lang is different from the default lang, then highlight missing files and variables if ($lang_iso != $config['default_lang']) { - $is_missing_var = false; - - foreach ($this->main_files as $file) + try { - if (file_exists($phpbb_root_path . $this->get_filename($lang_iso, '', $file))) - { - $missing_vars[$file] = $this->compare_language_files($config['default_lang'], $lang_iso, '', $file); - - if (sizeof($missing_vars[$file])) - { - $is_missing_var = true; - } - } - else - { - $missing_files[] = $this->get_filename($lang_iso, '', $file); - } + $iterator = new \RecursiveIteratorIterator( + new \phpbb\recursive_dot_prefix_filter_iterator( + new \RecursiveDirectoryIterator( + $phpbb_root_path . 'language/' . $config['default_lang'] . '/', + \FilesystemIterator::SKIP_DOTS + ) + ), + \RecursiveIteratorIterator::LEAVES_ONLY + ); } - - // Now go through acp/mods directories - foreach ($acp_files as $file) + catch (\Exception $e) { - 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); - } + return array(); } - if (sizeof($mods_files)) + foreach ($iterator as $file_info) { - foreach ($mods_files as $file) + /** @var \RecursiveDirectoryIterator $file_info */ + $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($phpbb_root_path . $this->get_filename($lang_iso, 'mods', $file))) + if (substr($relative_path, 0 - strlen($phpEx)) === $phpEx) { - $missing_vars['mods/' . $file] = $this->compare_language_files($config['default_lang'], $lang_iso, 'mods', $file); + $missing_vars = $this->compare_language_files($config['default_lang'], $lang_iso, $relative_path); - if (sizeof($missing_vars['mods/' . $file])) + if (!empty($missing_vars)) { - $is_missing_var = true; + $template->assign_block_vars('missing_varfile', array( + 'FILE_NAME' => $relative_path, + )); + + foreach ($missing_vars as $var) + { + $template->assign_block_vars('missing_varfile.variable', array( + 'VAR_NAME' => $var, + )); + } } } - else - { - $missing_files[] = $this->get_filename($lang_iso, 'mods', $file); - } - } - } - - // More missing files... for example email templates? - foreach ($email_files as $file) - { - if (!file_exists($phpbb_root_path . $this->get_filename($lang_iso, 'email', $file))) - { - $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('<br />', $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 = '<option value="|common.' . $phpEx . '" class="sep">' . $user->lang['LANGUAGE_FILES'] . '</option>'; - 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 .= '<option value="|' . $file . '"' . $selected . '>' . $prefix . $file . '</option>'; - } - - // Help Files - $s_lang_options .= '<option value="|common.' . $phpEx . '" class="sep">' . $user->lang['HELP_FILES'] . '</option>'; - 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 .= '<option value="|' . $file . '"' . $selected . '>' . $prefix . $file . '</option>'; - } - - // Now every other language directory - $check_files = array('email', 'acp', 'mods'); - - foreach ($check_files as $check) - { - if (!sizeof(${$check . '_files'})) - { - continue; - } - - $s_lang_options .= '<option value="|common.' . $phpEx . '" class="sep">' . $user->lang[strtoupper($check) . '_FILES'] . '</option>'; - - 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 .= '<option value="' . $check . '|' . $file . '"' . $selected . '>' . $prefix . $file . '</option>'; - } - } - - // 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) + else { - $lang = $help; - unset($help); + $template->assign_block_vars('missing_files', array( + 'FILE_NAME' => $relative_path, + )); } } - - $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': @@ -782,11 +224,6 @@ class acp_language $sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . ' WHERE lang_id = ' . $lang_id; $db->sql_query($sql); - $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . " WHERE image_lang = '" . $db->sql_escape($row['lang_iso']) . "'"; - $result = $db->sql_query($sql); - - $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); - 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)); @@ -799,7 +236,7 @@ class acp_language 'action' => $action, 'id' => $lang_id, ); - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); + confirm_box(false, $user->lang('DELETE_LANGUAGE_CONFIRM', $row['lang_english_name']), build_hidden_fields($s_hidden_fields)); } break; @@ -851,66 +288,6 @@ class acp_language $db->sql_query('INSERT INTO ' . LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); $lang_id = $db->sql_nextid(); - $valid_localized = array( - 'icon_back_top', 'icon_contact_aim', 'icon_contact_email', 'icon_contact_icq', 'icon_contact_jabber', 'icon_contact_msnm', 'icon_contact_pm', 'icon_contact_yahoo', 'icon_contact_www', 'icon_post_delete', 'icon_post_edit', 'icon_post_info', 'icon_post_quote', 'icon_post_report', 'icon_user_online', 'icon_user_offline', 'icon_user_profile', 'icon_user_search', 'icon_user_warn', 'button_pm_forward', 'button_pm_new', 'button_pm_reply', 'button_topic_locked', 'button_topic_new', 'button_topic_reply', - ); - - $sql_ary = array(); - - $sql = 'SELECT * - FROM ' . STYLES_IMAGESET_TABLE; - $result = $db->sql_query($sql); - while ($imageset_row = $db->sql_fetchrow($result)) - { - if (@file_exists("{$phpbb_root_path}styles/{$imageset_row['imageset_path']}/imageset/{$lang_pack['iso']}/imageset.cfg")) - { - $cfg_data_imageset_data = parse_cfg_file("{$phpbb_root_path}styles/{$imageset_row['imageset_path']}/imageset/{$lang_pack['iso']}/imageset.cfg"); - foreach ($cfg_data_imageset_data as $image_name => $value) - { - if (strpos($value, '*') !== false) - { - if (substr($value, -1, 1) === '*') - { - list($image_filename, $image_height) = explode('*', $value); - $image_width = 0; - } - else - { - list($image_filename, $image_height, $image_width) = explode('*', $value); - } - } - else - { - $image_filename = $value; - $image_height = $image_width = 0; - } - - if (strpos($image_name, 'img_') === 0 && $image_filename) - { - $image_name = substr($image_name, 4); - if (in_array($image_name, $valid_localized)) - { - $sql_ary[] = array( - 'image_name' => (string) $image_name, - 'image_filename' => (string) $image_filename, - 'image_height' => (int) $image_height, - 'image_width' => (int) $image_width, - 'imageset_id' => (int) $imageset_row['imageset_id'], - 'image_lang' => (string) $lang_pack['iso'], - ); - } - } - } - } - } - $db->sql_freeresult($result); - - if (sizeof($sql_ary)) - { - $db->sql_multi_insert(STYLES_IMAGESET_DATA_TABLE, $sql_ary); - $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); - } - // 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 . " @@ -959,127 +336,6 @@ class acp_language trigger_error($message . adm_back_link($this->u_action)); break; - - case 'download': - - if (!$lang_id) - { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $sql = 'SELECT * - FROM ' . LANG_TABLE . ' - WHERE lang_id = ' . $lang_id; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $use_method = request_var('use_method', ''); - $methods = array('.tar'); - - $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib'); - foreach ($available_methods as $type => $module) - { - if (!@extension_loaded($module)) - { - continue; - } - - $methods[] = $type; - } - - // Let the user decide in which format he wants to have the pack - if (!$use_method) - { - $this->page_title = 'SELECT_DOWNLOAD_FORMAT'; - - $radio_buttons = ''; - foreach ($methods as $method) - { - $radio_buttons .= '<label><input type="radio"' . ((!$radio_buttons) ? ' id="use_method"' : '') . ' class="radio" value="' . $method . '" name="use_method" /> ' . $method . '</label>'; - } - - $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 @@ -1172,294 +428,31 @@ class acp_language unset($new_ary); } - - /** - * Set default language variables/header - */ - function default_variables() - { - global $phpEx; - - $this->language_file_header = '<?php -/** -* -* {FILENAME} [{LANG_NAME}] -* -* @package language -* @version $' . 'Id: ' . '$ -* @copyright (c) ' . date('Y') . ' phpBB Group -* @author {CHANGED} - {AUTHOR} -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* DO NOT CHANGE -*/ -if (!defined(\'IN_PHPBB\')) -{ - exit; -} - -if (empty($lang) || !is_array($lang)) -{ - $lang = array(); -} - -// DEVELOPERS PLEASE NOTE -// -// All language files should use UTF-8 as their encoding and the files must not contain a BOM. -// -// Placeholders can now contain order information, e.g. instead of -// \'Page %s of %s\' you can (and should) write \'Page %1$s of %2$s\', this allows -// translators to re-order the output of data while ensuring it remains correct -// -// You do not need this where single placeholders are used, e.g. \'Message %d\' is fine -// equally where a string contains only two placeholders which are used to wrap text -// in a url you again do not need to specify an order e.g., \'Click %sHERE%s\' is fine -'; - - $this->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 + * Compare two language files */ - function add_to_archive(&$compress, $filelist, $lang_iso, $directory = '') + function compare_language_files($source_lang, $dest_lang, $file) { 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)); + $source_file = $phpbb_root_path . 'language/' . $source_lang . '/' . $file; + $dest_file = $phpbb_root_path . 'language/' . $dest_lang . '/' . $file; - if (!$non_static) + if (!file_exists($dest_file)) { - return '<strong>' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '</strong>'; - } - - // If more then 270 characters, then we present a textarea, else an input field - $textarea = (utf8_strlen($value) > 270) ? true : false; - $tpl = ''; - - $tpl .= ($textarea) ? '<textarea name="' : '<input type="text" name="'; - $tpl .= 'entry[' . implode('][', array_map('utf8_htmlspecialchars', $keys)) . ']"'; - - $tpl .= ($textarea) ? ' cols="80" rows="5" class="langvalue">' : ' class="langvalue" value="'; - $tpl .= htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); - $tpl .= ($textarea) ? '</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 .= ' - <tr> - <td class="row3" colspan="2">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<strong>' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . '</strong></td> - </tr>'; - - foreach ($value as $_key => $_value) - { - if (is_array($_value)) - { - // Write key - $tpl .= ' - <tr> - <td class="row3" colspan="2">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . ' <strong>' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . '</strong></td> - </tr>'; - - foreach ($_value as $__key => $__value) - { - // Write key - $tpl .= ' - <tr> - <td class="row1" style="white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<strong>' . htmlspecialchars($__key, ENT_COMPAT, 'UTF-8') . '</strong></td> - <td class="row2">'; - - $tpl .= $this->add_input_field($input_field, $__value, $key, $_key, $__key); - - $tpl .= '</td> - </tr>'; - } - } - else - { - // Write key - $tpl .= ' - <tr> - <td class="row1" style="white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<strong>' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . '</strong></td> - <td class="row2">'; - - $tpl .= $this->add_input_field($input_field, $_value, $key, $_key); - - $tpl .= '</td> - </tr>'; - } - } - - $tpl .= ' - <tr> - <td class="spacer" colspan="2"> </td> - </tr>'; - } - else - { - // Write key - $tpl .= ' - <tr> - <td class="row1" style="white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<strong>' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . '</strong></td> - <td class="row2">'; - - $tpl .= $this->add_input_field($input_field, $value, $key); - - $tpl .= '</td> - </tr>'; - } + return array(); } - 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); + include($source_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)); - + include($dest_file); $lang_entry_dst = $lang; unset($lang); - $diff_array_keys = array_diff(array_keys($lang_entry_src), array_keys($lang_entry_dst)); - unset($lang_entry_dst); - - foreach ($diff_array_keys as $key) - { - $return_ary[$key] = $lang_entry_src[$key]; - } - - unset($lang_entry_src); - - return $return_ary; - } - - /** - * Return language string value for storage - */ - function prepare_lang_entry($text, $store = true) - { - $text = (STRIP) ? stripslashes($text) : $text; - - // Adjust for storage... - if ($store) - { - $text = str_replace("'", "\\'", str_replace('\\', '\\\\', $text)); - } - - return $text; - } - - /** - * Format language array for storage - */ - function format_lang_array($key, $value, $tabs = "\t") - { - $entry = ''; - - if (!is_array($value)) - { - $entry .= "{$tabs}'" . $this->prepare_lang_entry($key) . "'\t=> '" . $this->prepare_lang_entry($value) . "',\n"; - } - else - { - $_tabs = $tabs . "\t"; - $entry .= "\n{$tabs}'" . $this->prepare_lang_entry($key) . "'\t=> array(\n"; - - foreach ($value as $_key => $_value) - { - $entry .= $this->format_lang_array($_key, $_value, $_tabs); - } - - $entry .= "{$tabs}),\n\n"; - } - - return $entry; + return array_diff(array_keys($lang_entry_src), array_keys($lang_entry_dst)); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_logs.php b/phpBB/includes/acp/acp_logs.php index 2fc86e325f..80dee1d620 100644 --- a/phpBB/includes/acp/acp_logs.php +++ b/phpBB/includes/acp/acp_logs.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,17 +19,15 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_logs { var $u_action; function main($id, $mode) { - global $db, $user, $auth, $template, $cache; + global $db, $user, $auth, $template, $cache, $phpbb_container; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $request; $user->add_lang('mcp'); @@ -35,8 +36,8 @@ class acp_logs $forum_id = request_var('f', 0); $topic_id = request_var('t', 0); $start = request_var('start', 0); - $deletemark = (!empty($_POST['delmarked'])) ? true : false; - $deleteall = (!empty($_POST['delall'])) ? true : false; + $deletemark = $request->variable('delmarked', false, false, \phpbb\request\request_interface::POST); + $deleteall = $request->variable('delall', false, false, \phpbb\request\request_interface::POST); $marked = request_var('mark', array(0)); // Sort keys @@ -46,34 +47,33 @@ class acp_logs $this->tpl_name = 'acp_logs'; $this->log_type = constant('LOG_' . strtoupper($mode)); + $pagination = $phpbb_container->get('pagination'); // Delete entries if requested and able if (($deletemark || $deleteall) && $auth->acl_get('a_clearlogs')) { if (confirm_box(true)) { - $where_sql = ''; + $conditions = array(); if ($deletemark && sizeof($marked)) { - $sql_in = array(); - foreach ($marked as $mark) - { - $sql_in[] = $mark; - } - $where_sql = ' AND ' . $db->sql_in_set('log_id', $sql_in); - unset($sql_in); + $conditions['log_id'] = array('IN' => $marked); } - if ($where_sql || $deleteall) + if ($deleteall) { - $sql = 'DELETE FROM ' . LOG_TABLE . " - WHERE log_type = {$this->log_type} - $where_sql"; - $db->sql_query($sql); + if ($sort_days) + { + $conditions['log_time'] = array('>=', time() - ($sort_days * 86400)); + } - add_log('admin', 'LOG_CLEAR_' . strtoupper($mode)); + $keywords = utf8_normalize_nfc(request_var('keywords', '', true)); + $conditions['keywords'] = $keywords; } + + $phpbb_log = $phpbb_container->get('log'); + $phpbb_log->delete($mode, $conditions); } else { @@ -117,7 +117,7 @@ class acp_logs if ($mode == 'mod') { $forum_box = '<option value="0">' . $user->lang['ALL_FORUMS'] . '</option>' . make_forum_select($forum_id); - + $template->assign_vars(array( 'S_SHOW_FORUMS' => true, 'S_FORUM_BOX' => $forum_box) @@ -129,14 +129,14 @@ class acp_logs $log_count = 0; $start = view_log($mode, $log_data, $log_count, $config['topics_per_page'], $start, $forum_id, 0, 0, $sql_where, $sql_sort, $keywords); + $base_url = $this->u_action . "&$u_sort_param$keywords_param"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); + $template->assign_vars(array( 'L_TITLE' => $l_title, 'L_EXPLAIN' => $l_title_explain, 'U_ACTION' => $this->u_action . "&$u_sort_param$keywords_param&start=$start", - 'S_ON_PAGE' => on_page($log_count, $config['topics_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param$keywords_param", $log_count, $config['topics_per_page'], $start, true), - 'S_LIMIT_DAYS' => $s_limit_days, 'S_SORT_KEY' => $s_sort_key, 'S_SORT_DIR' => $s_sort_dir, @@ -148,7 +148,7 @@ class acp_logs foreach ($log_data as $row) { $data = array(); - + $checks = array('viewtopic', 'viewlogs', 'viewforum'); foreach ($checks as $check) { @@ -172,5 +172,3 @@ class acp_logs } } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php index 79557bb5fd..48ca05a118 100644 --- a/phpBB/includes/acp/acp_main.php +++ b/phpBB/includes/acp/acp_main.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,17 +19,14 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_main { var $u_action; function main($id, $mode) { - global $config, $db, $user, $auth, $template; - global $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $config, $db, $cache, $user, $auth, $template, $request; + global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_container, $phpbb_dispatcher; // Show restore permissions notice if ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) @@ -41,11 +41,7 @@ class acp_main $user_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - $perm_from = '<strong' . (($user_row['user_colour']) ? ' style="color: #' . $user_row['user_colour'] . '">' : '>'); - $perm_from .= ($user_row['user_id'] != ANONYMOUS) ? '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $user_row['user_id']) . '">' : ''; - $perm_from .= $user_row['username']; - $perm_from .= ($user_row['user_id'] != ANONYMOUS) ? '</a>' : ''; - $perm_from .= '</strong>'; + $perm_from = get_username_string('full', $user_row['user_id'], $user_row['username'], $user_row['user_colour']); $template->assign_vars(array( 'S_RESTORE_PERMISSIONS' => true, @@ -64,9 +60,7 @@ class acp_main if ($action === 'admlogout') { $user->unset_admin(); - $redirect_url = append_sid("{$phpbb_root_path}index.$phpEx"); - meta_refresh(3, $redirect_url); - trigger_error($user->lang['ADM_LOGGED_OUT'] . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . $redirect_url . '">', '</a>')); + redirect(append_sid("{$phpbb_root_path}index.$phpEx")); } if (!confirm_box(true)) @@ -130,6 +124,11 @@ class acp_main set_config('record_online_users', 1, true); set_config('record_online_date', time(), true); add_log('admin', 'LOG_RESET_ONLINE'); + + if ($request->is_ajax()) + { + trigger_error('RESET_ONLINE_SUCCESS'); + } break; case 'stats': @@ -140,14 +139,14 @@ class acp_main $sql = 'SELECT COUNT(post_id) AS stat FROM ' . POSTS_TABLE . ' - WHERE post_approved = 1'; + WHERE post_visibility = ' . ITEM_APPROVED; $result = $db->sql_query($sql); set_config('num_posts', (int) $db->sql_fetchfield('stat'), true); $db->sql_freeresult($result); $sql = 'SELECT COUNT(topic_id) AS stat FROM ' . TOPICS_TABLE . ' - WHERE topic_approved = 1'; + WHERE topic_visibility = ' . ITEM_APPROVED; $result = $db->sql_query($sql); set_config('num_topics', (int) $db->sql_fetchfield('stat'), true); $db->sql_freeresult($result); @@ -180,6 +179,11 @@ class acp_main update_last_username(); add_log('admin', 'LOG_RESYNC_STATS'); + + if ($request->is_ajax()) + { + trigger_error('RESYNC_STATS_SUCCESS'); + } break; case 'user': @@ -223,7 +227,7 @@ class acp_main $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id FROM ' . POSTS_TABLE . ' WHERE post_id BETWEEN ' . ($start + 1) . ' AND ' . ($start + $step) . ' - AND post_postcount = 1 AND post_approved = 1 + AND post_postcount = 1 AND post_visibility = ' . ITEM_APPROVED . ' GROUP BY poster_id'; $result = $db->sql_query($sql); @@ -243,6 +247,10 @@ class acp_main add_log('admin', 'LOG_RESYNC_POSTCOUNTS'); + if ($request->is_ajax()) + { + trigger_error('RESYNC_POSTCOUNTS_SUCCESS'); + } break; case 'date': @@ -253,13 +261,18 @@ class acp_main set_config('board_startdate', time() - 1); add_log('admin', 'LOG_RESET_DATE'); + + if ($request->is_ajax()) + { + trigger_error('RESET_DATE_SUCCESS'); + } break; case 'db_track': - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'sqlite': - case 'firebird': + case 'sqlite3': $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); break; @@ -328,22 +341,27 @@ class acp_main } add_log('admin', 'LOG_RESYNC_POST_MARKING'); - break; - case 'purge_cache': - if ((int) $user->data['user_type'] !== USER_FOUNDER) + if ($request->is_ajax()) { - trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); + trigger_error('RESYNC_POST_MARKING_SUCCESS'); } + break; - global $cache; + case 'purge_cache': + $config->increment('assets_version', 1); $cache->purge(); // Clear permissions $auth->acl_clear_prefetch(); - cache_moderators(); + phpbb_cache_moderators($db, $cache, $auth); add_log('admin', 'LOG_PURGE_CACHE'); + + if ($request->is_ajax()) + { + trigger_error('PURGE_CACHE_SUCCESS'); + } break; case 'purge_sessions': @@ -356,10 +374,10 @@ class acp_main foreach ($tables as $table) { - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'sqlite': - case 'firebird': + case 'sqlite3': $db->sql_query("DELETE FROM $table"); break; @@ -390,6 +408,11 @@ class acp_main $db->sql_query($sql); add_log('admin', 'LOG_PURGE_SESSIONS'); + + if ($request->is_ajax()) + { + trigger_error('PURGE_SESSIONS_SUCCESS'); + } break; } } @@ -406,20 +429,30 @@ class acp_main )); } - $latest_version_info = false; - if (($latest_version_info = obtain_latest_version_info(request_var('versioncheck_force', false))) === false) + $version_helper = $phpbb_container->get('version_helper'); + try { - $template->assign_var('S_VERSIONCHECK_FAIL', true); + $recheck = $request->variable('versioncheck_force', false); + $updates_available = $version_helper->get_suggested_updates($recheck); + + $template->assign_var('S_VERSION_UP_TO_DATE', empty($updates_available)); } - else + catch (\RuntimeException $e) { - $latest_version_info = explode("\n", $latest_version_info); - $template->assign_vars(array( - 'S_VERSION_UP_TO_DATE' => phpbb_version_compare(trim($latest_version_info[0]), $config['version'], '<='), + 'S_VERSIONCHECK_FAIL' => true, + 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== $user->lang('VERSIONCHECK_FAIL')) ? $e->getMessage() : '', )); } + /** + * Notice admin + * + * @event core.acp_main_notice + * @since 3.1.0-RC3 + */ + $phpbb_dispatcher->dispatch('core.acp_main_notice'); + // Get forum statistics $total_posts = $config['num_posts']; $total_topics = $config['num_topics']; @@ -594,6 +627,22 @@ class acp_main $template->assign_var('S_REMOVE_INSTALL', true); } + // Warn if no search index is created + if ($config['num_posts'] && class_exists($config['search_type'])) + { + $error = false; + $search_type = $config['search_type']; + $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user); + + if (!$search->index_created()) + { + $template->assign_vars(array( + 'S_SEARCH_INDEX_MISSING' => true, + 'L_NO_SEARCH_INDEX' => $user->lang('NO_SEARCH_INDEX', $search->get_name(), '<a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=acp_search&mode=index') . '">', '</a>'), + )); + } + } + if (!defined('PHPBB_DISABLE_CONFIG_CHECK') && file_exists($phpbb_root_path . 'config.' . $phpEx) && phpbb_is_writable($phpbb_root_path . 'config.' . $phpEx)) { // World-Writable? (000x) @@ -621,5 +670,3 @@ class acp_main $this->page_title = 'ACP_MAIN'; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_modules.php b/phpBB/includes/acp/acp_modules.php index 75bc5766a9..ea6b388328 100644 --- a/phpBB/includes/acp/acp_modules.php +++ b/phpBB/includes/acp/acp_modules.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -26,9 +29,6 @@ if (!defined('IN_PHPBB')) * - category disabled */ -/** -* @package acp -*/ class acp_modules { var $module_class = ''; @@ -37,7 +37,7 @@ class acp_modules function main($id, $mode) { - global $db, $user, $auth, $template, $module; + global $db, $user, $auth, $template, $module, $request; global $config, $phpbb_admin_path, $phpbb_root_path, $phpEx; // Set a global define for modules we might include (the author is able to prevent execution of code by checking this constant) @@ -111,7 +111,7 @@ class acp_modules } break; - + case 'enable': case 'disable': if (!$module_id) @@ -170,7 +170,15 @@ class acp_modules add_log('admin', 'LOG_MODULE_' . strtoupper($action), $this->lang_name($row['module_langname']), $move_module_name); $this->remove_cache_file(); } - + + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'success' => ($move_module_name !== false), + )); + } + break; case 'quickadd': @@ -207,7 +215,7 @@ class acp_modules if (!sizeof($errors)) { $this->remove_cache_file(); - + trigger_error($user->lang['MODULE_ADDED'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); } } @@ -231,7 +239,7 @@ class acp_modules { trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } - + $module_row = $this->get_module_row($module_id); // no break @@ -250,7 +258,7 @@ class acp_modules 'module_auth' => '', ); } - + $module_data = array(); $module_data['module_basename'] = request_var('module_basename', (string) $module_row['module_basename']); @@ -295,7 +303,7 @@ class acp_modules if (!sizeof($errors)) { $this->remove_cache_file(); - + trigger_error((($action == 'add') ? $user->lang['MODULE_ADDED'] : $user->lang['MODULE_EDITED']) . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); } } @@ -316,7 +324,7 @@ class acp_modules } // Name options - $s_name_options .= '<option value="' . $option . '"' . (($option == $module_data['module_basename']) ? ' selected="selected"' : '') . '>' . $this->lang_name($values['title']) . ' [' . $this->module_class . '_' . $option . ']</option>'; + $s_name_options .= '<option value="' . $option . '"' . (($option == $module_data['module_basename']) ? ' selected="selected"' : '') . '>' . $this->lang_name($values['title']) . ' [' . $option . ']</option>'; $template->assign_block_vars('m_names', array('NAME' => $option, 'A_NAME' => addslashes($option))); @@ -327,7 +335,7 @@ class acp_modules { $s_mode_options .= '<option value="' . $m_mode . '"' . (($m_mode == $module_data['module_mode']) ? ' selected="selected"' : '') . '>' . $this->lang_name($m_values['title']) . '</option>'; } - + $template->assign_block_vars('m_names.modes', array( 'OPTION' => $m_mode, 'VALUE' => $this->lang_name($m_values['title']), @@ -336,7 +344,7 @@ class acp_modules ); } } - + $s_cat_option = '<option value="0"' . (($module_data['parent_id'] == 0) ? ' selected="selected"' : '') . '>' . $user->lang['NO_PARENT'] . '</option>'; $template->assign_vars(array_merge(array( @@ -349,7 +357,7 @@ class acp_modules 'U_EDIT_ACTION' => $this->u_action . '&parent_id=' . $this->parent_id, 'L_TITLE' => $user->lang[strtoupper($action) . '_MODULE'], - + 'MODULENAME' => $this->lang_name($module_data['module_langname']), 'ACTION' => $action, 'MODULE_ID' => $module_id, @@ -374,6 +382,16 @@ class acp_modules // Default management page if (sizeof($errors)) { + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'MESSAGE_TITLE' => $user->lang('ERROR'), + 'MESSAGE_TEXT' => implode('<br />', $errors), + 'SUCCESS' => false, + )); + } + $template->assign_vars(array( 'S_ERROR' => true, 'ERROR_MSG' => implode('<br />', $errors)) @@ -480,7 +498,7 @@ class acp_modules foreach ($module_infos as $option => $values) { // Name options - $s_install_options .= '<optgroup label="' . $this->lang_name($values['title']) . ' [' . $this->module_class . '_' . $option . ']">'; + $s_install_options .= '<optgroup label="' . $this->lang_name($values['title']) . ' [' . $option . ']">'; // Build module modes foreach ($values['modes'] as $m_mode => $m_values) @@ -516,7 +534,7 @@ class acp_modules $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - + if (!$row) { trigger_error($user->lang['NO_MODULE'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); @@ -524,72 +542,79 @@ class acp_modules return $row; } - + /** * Get available module information from module files + * + * @param string $module + * @param bool|string $module_class + * @param bool $use_all_available Use all available instead of just all + * enabled extensions + * @return array */ - function get_module_infos($module = '', $module_class = false) + function get_module_infos($module = '', $module_class = false, $use_all_available = false) { - global $phpbb_root_path, $phpEx; - + global $phpbb_extension_manager, $phpbb_root_path, $phpEx; + $module_class = ($module_class === false) ? $this->module_class : $module_class; $directory = $phpbb_root_path . 'includes/' . $module_class . '/info/'; $fileinfo = array(); - if (!$module) - { - $dh = @opendir($directory); + $finder = $phpbb_extension_manager->get_finder($use_all_available); - if (!$dh) + $modules = $finder + ->extension_suffix('_module') + ->extension_directory("/$module_class") + ->core_path("includes/$module_class/info/") + ->core_prefix($module_class . '_') + ->get_classes(true); + + foreach ($modules as $cur_module) + { + // Skip entries we do not need if we know the module we are + // looking for + if ($module && strpos(str_replace('\\', '_', $cur_module), $module) === false && $module !== $cur_module) { - return $fileinfo; + continue; } - while (($file = readdir($dh)) !== false) - { - // Is module? - if (preg_match('/^' . $module_class . '_.+\.' . $phpEx . '$/', $file)) - { - $class = str_replace(".$phpEx", '', $file) . '_info'; + $info_class = preg_replace('/_module$/', '_info', $cur_module); - if (!class_exists($class)) - { - include($directory . $file); - } + // If the class does not exist it might be following the old + // format. phpbb_acp_info_acp_foo needs to be turned into + // acp_foo_info and the respective file has to be included + // manually because it does not support auto loading + $old_info_class_file = str_replace("phpbb_{$module_class}_info_", '', $cur_module); + $old_info_class = $old_info_class_file . '_info'; - // Get module title tag - if (class_exists($class)) - { - $c_class = new $class(); - $module_info = $c_class->module(); - $fileinfo[str_replace($module_class . '_', '', $module_info['filename'])] = $module_info; - } - } + if (class_exists($old_info_class)) + { + $info_class = $old_info_class; } - closedir($dh); - - ksort($fileinfo); - } - else - { - $filename = $module_class . '_' . basename($module); - $class = $module_class . '_' . basename($module) . '_info'; - - if (!class_exists($class)) + else if (!class_exists($info_class)) { - include($directory . $filename . '.' . $phpEx); + $info_class = $old_info_class; + // need to check class exists again because previous checks triggered autoloading + if (!class_exists($info_class) && file_exists($directory . $old_info_class_file . '.' . $phpEx)) + { + include($directory . $old_info_class_file . '.' . $phpEx); + } } - // Get module title tag - if (class_exists($class)) + if (class_exists($info_class)) { - $c_class = new $class(); - $module_info = $c_class->module(); - $fileinfo[str_replace($module_class . '_', '', $module_info['filename'])] = $module_info; + $info = new $info_class(); + $module_info = $info->module(); + + $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $cur_module; + + $fileinfo[$main_class] = $module_info; } } - + + ksort($fileinfo); + return $fileinfo; } @@ -717,15 +742,15 @@ class acp_modules */ function remove_cache_file() { - global $cache; + global $phpbb_container; // Sanitise for future path use, it's escaped as appropriate for queries $p_class = str_replace(array('.', '/', '\\'), '', basename($this->module_class)); - - $cache->destroy('_modules_' . $p_class); + + $phpbb_container->get('cache.driver')->destroy('_modules_' . $p_class); // Additionally remove sql cache - $cache->destroy('sql', MODULES_TABLE); + $phpbb_container->get('cache.driver')->destroy('sql', MODULES_TABLE); } /** @@ -741,7 +766,8 @@ class acp_modules /** * Update/Add module * - * @param bool $run_inline if set to true errors will be returned and no logs being written + * @param array &$module_data The module data + * @param bool $run_inline if set to true errors will be returned and no logs being written */ function update_module_data(&$module_data, $run_inline = false) { @@ -1061,5 +1087,3 @@ class acp_modules return $this->lang_name($target['module_langname']); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_permission_roles.php b/phpBB/includes/acp/acp_permission_roles.php index 03ea5a39dd..cd3616208d 100644 --- a/phpBB/includes/acp/acp_permission_roles.php +++ b/phpBB/includes/acp/acp_permission_roles.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,22 +19,21 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_permission_roles { var $u_action; + protected $auth_admin; function main($id, $mode) { - global $db, $user, $auth, $template, $cache; + global $db, $user, $auth, $template, $cache, $phpbb_container; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $request; include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx); include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx); - $auth_admin = new auth_admin(); + $this->auth_admin = new auth_admin(); $user->add_lang('acp/permissions'); add_permission_language(); @@ -46,6 +48,11 @@ class acp_permission_roles $form_name = 'acp_permissions'; add_form_key($form_name); + if (!$role_id && in_array($action, array('remove', 'edit', 'move_up', 'move_down'))) + { + trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); + } + switch ($mode) { case 'admin_roles': @@ -85,11 +92,6 @@ class acp_permission_roles { case 'remove': - if (!$role_id) - { - trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - $sql = 'SELECT * FROM ' . ACL_ROLES_TABLE . ' WHERE role_id = ' . $role_id; @@ -123,10 +125,6 @@ class acp_permission_roles break; case 'edit': - if (!$role_id) - { - trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); - } // Get role we edit $sql = 'SELECT * @@ -211,7 +209,7 @@ class acp_permission_roles } // Now add the auth settings - $auth_admin->acl_set_role($role_id, $auth_settings); + $this->auth_admin->acl_set_role($role_id, $auth_settings); $role_name = (!empty($user->lang[$role_name])) ? $user->lang[$role_name] : $role_name; add_log('admin', 'LOG_' . strtoupper($permission_type) . 'ROLE_' . strtoupper($action), $role_name); @@ -255,7 +253,7 @@ class acp_permission_roles { $sql = 'SELECT auth_option_id, auth_option FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option " . $db->sql_like_expression($permission_type . $db->any_char) . " + WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char()) . " AND auth_option <> '{$permission_type}' ORDER BY auth_option_id"; $result = $db->sql_query($sql); @@ -274,11 +272,6 @@ class acp_permission_roles if ($action == 'edit') { - if (!$role_id) - { - trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); - } - $sql = 'SELECT * FROM ' . ACL_ROLES_TABLE . ' WHERE role_id = ' . $role_id; @@ -306,6 +299,8 @@ class acp_permission_roles trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); } + $phpbb_permissions = $phpbb_container->get('acl.permissions'); + $template->assign_vars(array( 'S_EDIT' => true, @@ -314,14 +309,13 @@ class acp_permission_roles 'ROLE_NAME' => $role_row['role_name'], 'ROLE_DESCRIPTION' => $role_row['role_description'], - 'L_ACL_TYPE' => $user->lang['ACL_TYPE_' . strtoupper($permission_type)], - ) - ); + 'L_ACL_TYPE' => $phpbb_permissions->get_type_lang($permission_type), + )); // We need to fill the auth options array with ACL_NO options ;) $sql = 'SELECT auth_option_id, auth_option FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option " . $db->sql_like_expression($permission_type . $db->any_char) . " + WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char()) . " AND auth_option <> '{$permission_type}' ORDER BY auth_option_id"; $result = $db->sql_query($sql); @@ -344,7 +338,7 @@ class acp_permission_roles // Get users/groups/forums using this preset... if ($action == 'edit') { - $hold_ary = $auth_admin->get_role_mask($role_id); + $hold_ary = $this->auth_admin->get_role_mask($role_id); if (sizeof($hold_ary)) { @@ -355,7 +349,7 @@ class acp_permission_roles 'L_ROLE_ASSIGNED_TO' => sprintf($user->lang['ROLE_ASSIGNED_TO'], $role_name)) ); - $auth_admin->display_role_mask($hold_ary); + $this->auth_admin->display_role_mask($hold_ary); } } @@ -365,7 +359,18 @@ class acp_permission_roles case 'move_up': case 'move_down': - $order = request_var('order', 0); + $sql = 'SELECT role_order + FROM ' . ACL_ROLES_TABLE . " + WHERE role_id = $role_id"; + $result = $db->sql_query($sql); + $order = $db->sql_fetchfield('role_order'); + $db->sql_freeresult($result); + + if ($order === false || ($order == 0 && $action == 'move_up')) + { + break; + } + $order = (int) $order; $order_total = $order * 2 + (($action == 'move_up') ? -1 : 1); $sql = 'UPDATE ' . ACL_ROLES_TABLE . ' @@ -374,6 +379,14 @@ class acp_permission_roles AND role_order IN ($order, " . (($action == 'move_up') ? $order - 1 : $order + 1) . ')'; $db->sql_query($sql); + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'success' => (bool) $db->sql_affectedrows(), + )); + } + break; } @@ -420,8 +433,8 @@ class acp_permission_roles 'U_EDIT' => $this->u_action . '&action=edit&role_id=' . $row['role_id'], 'U_REMOVE' => $this->u_action . '&action=remove&role_id=' . $row['role_id'], - 'U_MOVE_UP' => $this->u_action . '&action=move_up&order=' . $row['role_order'], - 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&order=' . $row['role_order'], + 'U_MOVE_UP' => $this->u_action . '&action=move_up&role_id=' . $row['role_id'], + 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&role_id=' . $row['role_id'], 'U_DISPLAY_ITEMS' => ($row['role_id'] == $display_item) ? '' : $this->u_action . '&display_item=' . $row['role_id'] . '#assigned_to') ); @@ -446,8 +459,8 @@ class acp_permission_roles 'S_DISPLAY_ROLE_MASK' => true) ); - $hold_ary = $auth_admin->get_role_mask($display_item); - $auth_admin->display_role_mask($hold_ary); + $hold_ary = $this->auth_admin->get_role_mask($display_item); + $this->auth_admin->display_role_mask($hold_ary); } } @@ -456,14 +469,16 @@ class acp_permission_roles */ function display_auth_options($auth_options) { - global $template, $user; + global $template, $user, $phpbb_container; + + $phpbb_permissions = $phpbb_container->get('acl.permissions'); $content_array = $categories = array(); $key_sort_array = array(0); $auth_options = array(0 => $auth_options); // Making use of auth_admin method here (we do not really want to change two similar code fragments) - auth_admin::build_permission_array($auth_options, $content_array, $categories, $key_sort_array); + $this->auth_admin->build_permission_array($auth_options, $content_array, $categories, $key_sort_array); $content_array = $content_array[0]; @@ -473,7 +488,7 @@ class acp_permission_roles foreach ($content_array as $cat => $cat_array) { $template->assign_block_vars('auth', array( - 'CAT_NAME' => $user->lang['permission_cat'][$cat], + 'CAT_NAME' => $phpbb_permissions->get_category_lang($cat), 'S_YES' => ($cat_array['S_YES'] && !$cat_array['S_NEVER'] && !$cat_array['S_NO']) ? true : false, 'S_NEVER' => ($cat_array['S_NEVER'] && !$cat_array['S_YES'] && !$cat_array['S_NO']) ? true : false, @@ -488,8 +503,8 @@ class acp_permission_roles 'S_NO' => ($allowed == ACL_NO) ? true : false, 'FIELD_NAME' => $permission, - 'PERMISSION' => $user->lang['acl_' . $permission]['lang']) - ); + 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission), + )); } } } @@ -501,12 +516,10 @@ class acp_permission_roles { global $db; - $auth_admin = new auth_admin(); - // Get complete auth array $sql = 'SELECT auth_option, auth_option_id FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option " . $db->sql_like_expression($permission_type . $db->any_char); + WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char()); $result = $db->sql_query($sql); $auth_settings = array(); @@ -530,19 +543,19 @@ class acp_permission_roles $db->sql_freeresult($result); // Get role assignments - $hold_ary = $auth_admin->get_role_mask($role_id); + $hold_ary = $this->auth_admin->get_role_mask($role_id); // Re-assign permissions foreach ($hold_ary as $forum_id => $forum_ary) { if (isset($forum_ary['users'])) { - $auth_admin->acl_set('user', $forum_id, $forum_ary['users'], $auth_settings, 0, false); + $this->auth_admin->acl_set('user', $forum_id, $forum_ary['users'], $auth_settings, 0, false); } if (isset($forum_ary['groups'])) { - $auth_admin->acl_set('group', $forum_id, $forum_ary['groups'], $auth_settings, 0, false); + $this->auth_admin->acl_set('group', $forum_id, $forum_ary['groups'], $auth_settings, 0, false); } } @@ -564,8 +577,6 @@ class acp_permission_roles WHERE role_id = ' . $role_id; $db->sql_query($sql); - $auth_admin->acl_clear_prefetch(); + $this->auth_admin->acl_clear_prefetch(); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_permissions.php b/phpBB/includes/acp/acp_permissions.php index e9f0af5071..cb408e304f 100644 --- a/phpBB/includes/acp/acp_permissions.php +++ b/phpBB/includes/acp/acp_permissions.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,22 +19,22 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_permissions { var $u_action; var $permission_dropdown; + protected $permissions; function main($id, $mode) { - global $db, $user, $auth, $template, $cache; + global $db, $user, $auth, $template, $cache, $phpbb_container; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx); include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx); + $this->permissions = $phpbb_container->get('acl.permissions'); + $auth_admin = new auth_admin(); $user->add_lang('acp/permissions'); @@ -50,7 +53,7 @@ class acp_permissions if ($user_id && isset($auth_admin->acl_options['id'][$permission]) && $auth->acl_get('a_viewauth')) { - $this->page_title = sprintf($user->lang['TRACE_PERMISSION'], $user->lang['acl_' . $permission]['lang']); + $this->page_title = sprintf($user->lang['TRACE_PERMISSION'], $this->permissions->get_permission_lang($permission)); $this->permission_trace($user_id, $forum_id, $permission); return; } @@ -328,15 +331,6 @@ class acp_permissions } } - - // Setting permissions screen - $s_hidden_fields = build_hidden_fields(array( - 'user_id' => $user_id, - 'group_id' => $group_id, - 'forum_id' => $forum_id, - 'type' => $permission_type) - ); - // Go through the screens/options needed and present them in correct order foreach ($permission_victim as $victim) { @@ -469,6 +463,14 @@ class acp_permissions // If there are more than 5 forums selected the admin is not able to select all users/groups too. // We need to see if the number of forums can be increased or need to be decreased. + // Setting permissions screen + $s_hidden_fields = build_hidden_fields(array( + 'user_id' => $user_id, + 'group_id' => $group_id, + 'forum_id' => $forum_id, + 'type' => $permission_type, + )); + $template->assign_vars(array( 'U_ACTION' => $this->u_action, 'ANONYMOUS_USER_ID' => ANONYMOUS, @@ -498,13 +500,21 @@ class acp_permissions $template->assign_vars(array( 'S_FORUM_NAMES' => (sizeof($forum_names)) ? true : false, - 'FORUM_NAMES' => implode(', ', $forum_names)) + 'FORUM_NAMES' => implode($user->lang['COMMA_SEPARATOR'], $forum_names)) ); } return; } + // Setting permissions screen + $s_hidden_fields = build_hidden_fields(array( + 'user_id' => $user_id, + 'group_id' => $group_id, + 'forum_id' => $forum_id, + 'type' => $permission_type, + )); + // Do not allow forum_ids being set and no other setting defined (will bog down the server too much) if (sizeof($forum_id) && !sizeof($user_id) && !sizeof($group_id)) { @@ -513,7 +523,7 @@ class acp_permissions $template->assign_vars(array( 'S_PERMISSION_DROPDOWN' => (sizeof($this->permission_dropdown) > 1) ? $this->build_permission_dropdown($this->permission_dropdown, $permission_type, $permission_scope) : false, - 'L_PERMISSION_TYPE' => $user->lang['ACL_TYPE_' . strtoupper($permission_type)], + 'L_PERMISSION_TYPE' => $this->permissions->get_type_lang($permission_type), 'U_ACTION' => $this->u_action, 'S_HIDDEN_FIELDS' => $s_hidden_fields) @@ -588,7 +598,7 @@ class acp_permissions */ function build_permission_dropdown($options, $default_option, $permission_scope) { - global $user, $auth; + global $auth; $s_dropdown_options = ''; foreach ($options as $setting) @@ -599,7 +609,7 @@ class acp_permissions } $selected = ($setting == $default_option) ? ' selected="selected"' : ''; - $l_setting = (isset($user->lang['permission_type'][$permission_scope][$setting])) ? $user->lang['permission_type'][$permission_scope][$setting] : $user->lang['permission_type'][$setting]; + $l_setting = $this->permissions->get_type_lang($setting, $permission_scope); $s_dropdown_options .= '<option value="' . $setting . '"' . $selected . '>' . $l_setting . '</option>'; } @@ -657,7 +667,8 @@ class acp_permissions */ function set_permissions($mode, $permission_type, &$auth_admin, &$user_id, &$group_id) { - global $user, $auth; + global $db, $cache, $user, $auth; + global $request; $psubmit = request_var('psubmit', array(0 => array(0 => 0))); @@ -676,18 +687,17 @@ class acp_permissions list($ug_id, ) = each($psubmit); list($forum_id, ) = each($psubmit[$ug_id]); - if (empty($_POST['setting']) || empty($_POST['setting'][$ug_id]) || empty($_POST['setting'][$ug_id][$forum_id]) || !is_array($_POST['setting'][$ug_id][$forum_id])) + $settings = $request->variable('setting', array(0 => array(0 => array('' => 0))), false, \phpbb\request\request_interface::POST); + if (empty($settings) || empty($settings[$ug_id]) || empty($settings[$ug_id][$forum_id])) { trigger_error('WRONG_PERMISSION_SETTING_FORMAT', E_USER_WARNING); } - // We obtain and check $_POST['setting'][$ug_id][$forum_id] directly and not using request_var() because request_var() - // currently does not support the amount of dimensions required. ;) - // $auth_settings = request_var('setting', array(0 => array(0 => array('' => 0)))); - $auth_settings = array_map('intval', $_POST['setting'][$ug_id][$forum_id]); + $auth_settings = $settings[$ug_id][$forum_id]; // Do we have a role we want to set? - $assigned_role = (isset($_POST['role'][$ug_id][$forum_id])) ? (int) $_POST['role'][$ug_id][$forum_id] : 0; + $roles = $request->variable('role', array(0 => array(0 => 0)), false, \phpbb\request\request_interface::POST); + $assigned_role = (isset($roles[$ug_id][$forum_id])) ? (int) $roles[$ug_id][$forum_id] : 0; // Do the admin want to set these permissions to other items too? $inherit = request_var('inherit', array(0 => array(0))); @@ -727,13 +737,13 @@ class acp_permissions // Do we need to recache the moderator lists? if ($permission_type == 'm_') { - cache_moderators(); + phpbb_cache_moderators($db, $cache, $auth); } // Remove users who are now moderators or admins from everyones foes list if ($permission_type == 'm_' || $permission_type == 'a_') { - update_foes($group_id, $user_id); + phpbb_update_foes($db, $auth, $group_id, $user_id); } $this->log_action($mode, 'add', $permission_type, $ug_type, $ug_id, $forum_id); @@ -746,7 +756,8 @@ class acp_permissions */ function set_all_permissions($mode, $permission_type, &$auth_admin, &$user_id, &$group_id) { - global $user, $auth; + global $db, $cache, $user, $auth; + global $request; // User or group to be set? $ug_type = (sizeof($user_id)) ? 'user' : 'group'; @@ -757,8 +768,8 @@ class acp_permissions trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } - $auth_settings = (isset($_POST['setting'])) ? $_POST['setting'] : array(); - $auth_roles = (isset($_POST['role'])) ? $_POST['role'] : array(); + $auth_settings = $request->variable('setting', array(0 => array(0 => array('' => 0))), false, \phpbb\request\request_interface::POST); + $auth_roles = $request->variable('role', array(0 => array(0 => 0)), false, \phpbb\request\request_interface::POST); $ug_ids = $forum_ids = array(); // We need to go through the auth settings @@ -794,13 +805,13 @@ class acp_permissions // Do we need to recache the moderator lists? if ($permission_type == 'm_') { - cache_moderators(); + phpbb_cache_moderators($db, $cache, $auth); } // Remove users who are now moderators or admins from everyones foes list if ($permission_type == 'm_' || $permission_type == 'a_') { - update_foes($group_id, $user_id); + phpbb_update_foes($db, $auth, $group_id, $user_id); } $this->log_action($mode, 'add', $permission_type, $ug_type, $ug_ids, $forum_ids); @@ -858,7 +869,7 @@ class acp_permissions */ function remove_permissions($mode, $permission_type, &$auth_admin, &$user_id, &$group_id, &$forum_id) { - global $user, $db, $auth; + global $user, $db, $cache, $auth; // User or group to be set? $ug_type = (sizeof($user_id)) ? 'user' : 'group'; @@ -874,7 +885,7 @@ class acp_permissions // Do we need to recache the moderator lists? if ($permission_type == 'm_') { - cache_moderators(); + phpbb_cache_moderators($db, $cache, $auth); } $this->log_action($mode, 'del', $permission_type, $ug_type, (($ug_type == 'user') ? $user_id : $group_id), (sizeof($forum_id) ? $forum_id : array(0 => 0))); @@ -952,12 +963,7 @@ class acp_permissions if ($user_id != $user->data['user_id']) { - $sql = 'SELECT user_id, username, user_permissions, user_type - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - $userdata = $db->sql_fetchrow($result); - $db->sql_freeresult($result); + $userdata = $auth->obtain_user_data($user_id); } else { @@ -984,7 +990,7 @@ class acp_permissions $back = request_var('back', 0); $template->assign_vars(array( - 'PERMISSION' => $user->lang['acl_' . $permission]['lang'], + 'PERMISSION' => $this->permissions->get_permission_lang($permission), 'PERMISSION_USERNAME' => $userdata['username'], 'FORUM_NAME' => $forum_name, @@ -1105,7 +1111,7 @@ class acp_permissions { if ($user_id != $user->data['user_id']) { - $auth2 = new auth(); + $auth2 = new \phpbb\auth\auth(); $auth2->acl($userdata); $auth_setting = $auth2->acl_get($permission); } @@ -1172,7 +1178,7 @@ class acp_permissions */ function copy_forum_permissions() { - global $auth, $cache, $template, $user; + global $db, $auth, $cache, $template, $user; $user->add_lang('acp/forums'); @@ -1187,7 +1193,7 @@ class acp_permissions { if (copy_forum_permissions($src, $dest)) { - cache_moderators(); + phpbb_cache_moderators($db, $cache, $auth); $auth->acl_clear_prefetch(); $cache->destroy('sql', FORUMS_TABLE); @@ -1232,7 +1238,7 @@ class acp_permissions $sql = 'SELECT auth_option_id FROM ' . ACL_OPTIONS_TABLE . ' - WHERE auth_option ' . $db->sql_like_expression($permission_type . $db->any_char); + WHERE auth_option ' . $db->sql_like_expression($permission_type . $db->get_any_char()); $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -1311,5 +1317,3 @@ class acp_permissions ); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_php_info.php b/phpBB/includes/acp/acp_php_info.php index 88e2ac3f8d..810a111edb 100644 --- a/phpBB/includes/acp/acp_php_info.php +++ b/phpBB/includes/acp/acp_php_info.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_php_info { var $u_action; @@ -82,11 +82,9 @@ class acp_php_info $template->assign_var('PHPINFO', $output); } - + function remove_spaces($matches) { return '<a name="' . str_replace(' ', '_', $matches[1]) . '">'; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index 19223847f0..97c1f62077 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,45 +19,40 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_profile { var $u_action; var $edit_lang_id; var $lang_defs; + protected $type_collection; function main($id, $mode) { global $config, $db, $user, $auth, $template, $cache; global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix; + global $request, $phpbb_container; include($phpbb_root_path . 'includes/functions_posting.' . $phpEx); include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); $user->add_lang(array('ucp', 'acp/profile')); $this->tpl_name = 'acp_profile'; $this->page_title = 'ACP_CUSTOM_PROFILE_FIELDS'; + $field_id = $request->variable('field_id', 0); $action = (isset($_POST['create'])) ? 'create' : request_var('action', ''); $error = array(); $s_hidden_fields = ''; - // Define some default values for each field type - $default_values = array( - FIELD_STRING => array('field_length' => 10, 'field_minlen' => 0, 'field_maxlen' => 20, 'field_validation' => '.*', 'field_novalue' => '', 'field_default_value' => ''), - FIELD_TEXT => array('field_length' => '5|80', 'field_minlen' => 0, 'field_maxlen' => 1000, 'field_validation' => '.*', 'field_novalue' => '', 'field_default_value' => ''), - FIELD_INT => array('field_length' => 5, 'field_minlen' => 0, 'field_maxlen' => 100, 'field_validation' => '', 'field_novalue' => 0, 'field_default_value' => 0), - FIELD_DATE => array('field_length' => 10, 'field_minlen' => 10, 'field_maxlen' => 10, 'field_validation' => '', 'field_novalue' => ' 0- 0- 0', 'field_default_value' => ' 0- 0- 0'), - FIELD_BOOL => array('field_length' => 1, 'field_minlen' => 0, 'field_maxlen' => 0, 'field_validation' => '', 'field_novalue' => 0, 'field_default_value' => 0), - FIELD_DROPDOWN => array('field_length' => 0, 'field_minlen' => 0, 'field_maxlen' => 5, 'field_validation' => '', 'field_novalue' => 0, 'field_default_value' => 0), - ); + if (!$field_id && in_array($action, array('delete','activate', 'deactivate', 'move_up', 'move_down', 'edit'))) + { + trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING); + } - $cp = new custom_profile_admin(); + $cp = $phpbb_container->get('profilefields.manager'); + $this->type_collection = $phpbb_container->get('profilefields.type_collection'); // Build Language array // Based on this, we decide which elements need to be edited later and which language items are missing @@ -88,22 +86,16 @@ class acp_profile // Have some fields been defined? if (isset($this->lang_defs['entry'])) { - foreach ($this->lang_defs['entry'] as $field_id => $field_ary) + foreach ($this->lang_defs['entry'] as $field_ident => $field_ary) { // Fill an array with the languages that are missing for each field - $this->lang_defs['diff'][$field_id] = array_diff(array_values($this->lang_defs['iso']), $field_ary); + $this->lang_defs['diff'][$field_ident] = array_diff(array_values($this->lang_defs['iso']), $field_ary); } } switch ($action) { case 'delete': - $field_id = request_var('field_id', 0); - - if (!$field_id) - { - trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } if (confirm_box(true)) { @@ -120,57 +112,8 @@ class acp_profile $db->sql_query('DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . " WHERE field_id = $field_id"); $db->sql_query('DELETE FROM ' . PROFILE_LANG_TABLE . " WHERE field_id = $field_id"); - switch ($db->sql_layer) - { - case 'sqlite': - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '" . PROFILE_FIELDS_DATA_TABLE . "' - ORDER BY type DESC, name;"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Create a temp table and populate it, destroy the existing one - $db->sql_query(preg_replace('#CREATE\s+TABLE\s+"?' . PROFILE_FIELDS_DATA_TABLE . '"?#i', 'CREATE TEMPORARY TABLE ' . PROFILE_FIELDS_DATA_TABLE . '_temp', $row['sql'])); - $db->sql_query('INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . '_temp SELECT * FROM ' . PROFILE_FIELDS_DATA_TABLE); - $db->sql_query('DROP TABLE ' . PROFILE_FIELDS_DATA_TABLE); - - preg_match('#\((.*)\)#s', $row['sql'], $matches); - - $new_table_cols = trim($matches[1]); - $old_table_cols = preg_split('/,(?=[\\sa-z])/im', $new_table_cols); - $column_list = array(); - - foreach ($old_table_cols as $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - - if ($entities[0] == 'PRIMARY') - { - continue; - } - - if ($entities[0] !== 'pf_' . $field_ident) - { - $column_list[] = $entities[0]; - } - } - - $columns = implode(',', $column_list); - - $new_table_cols = preg_replace('/' . 'pf_' . $field_ident . '[^,]+,/', '', $new_table_cols); - - // create a new table and fill it up. destroy the temp one - $db->sql_query('CREATE TABLE ' . PROFILE_FIELDS_DATA_TABLE . ' (' . $new_table_cols . ');'); - $db->sql_query('INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . PROFILE_FIELDS_DATA_TABLE . '_temp;'); - $db->sql_query('DROP TABLE ' . PROFILE_FIELDS_DATA_TABLE . '_temp'); - break; - - default: - $db->sql_query('ALTER TABLE ' . PROFILE_FIELDS_DATA_TABLE . " DROP COLUMN pf_$field_ident"); - } + $db_tools = $phpbb_container->get('dbal.tools'); + $db_tools->sql_column_remove(PROFILE_FIELDS_DATA_TABLE, 'pf_' . $field_ident); $order = 0; @@ -210,12 +153,6 @@ class acp_profile break; case 'activate': - $field_id = request_var('field_id', 0); - - if (!$field_id) - { - trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } $sql = 'SELECT lang_id FROM ' . LANG_TABLE . " @@ -242,17 +179,20 @@ class acp_profile $db->sql_freeresult($result); add_log('admin', 'LOG_PROFILE_FIELD_ACTIVATE', $field_ident); + + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response(); + $json_response->send(array( + 'text' => $user->lang('DEACTIVATE'), + )); + } + trigger_error($user->lang['PROFILE_FIELD_ACTIVATED'] . adm_back_link($this->u_action)); break; case 'deactivate': - $field_id = request_var('field_id', 0); - - if (!$field_id) - { - trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . " SET field_active = 0 @@ -266,14 +206,35 @@ class acp_profile $field_ident = (string) $db->sql_fetchfield('field_ident'); $db->sql_freeresult($result); + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response(); + $json_response->send(array( + 'text' => $user->lang('ACTIVATE'), + )); + } + add_log('admin', 'LOG_PROFILE_FIELD_DEACTIVATE', $field_ident); + trigger_error($user->lang['PROFILE_FIELD_DEACTIVATED'] . adm_back_link($this->u_action)); break; case 'move_up': case 'move_down': - $field_order = request_var('order', 0); + + $sql = 'SELECT field_order + FROM ' . PROFILE_FIELDS_TABLE . " + WHERE field_id = $field_id"; + $result = $db->sql_query($sql); + $field_order = $db->sql_fetchfield('field_order'); + $db->sql_freeresult($result); + + if ($field_order === false || ($field_order == 0 && $action == 'move_up')) + { + break; + } + $field_order = (int) $field_order; $order_total = $field_order * 2 + (($action == 'move_up') ? -1 : 1); $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . " @@ -281,12 +242,19 @@ class acp_profile WHERE field_order IN ($field_order, " . (($action == 'move_up') ? $field_order - 1 : $field_order + 1) . ')'; $db->sql_query($sql); + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'success' => (bool) $db->sql_affectedrows(), + )); + } + break; case 'create': case 'edit': - $field_id = request_var('field_id', 0); $step = request_var('step', 1); $submit = (isset($_REQUEST['next']) || isset($_REQUEST['prev'])) ? true : false; @@ -298,11 +266,6 @@ class acp_profile // We are editing... we need to grab basic things if ($action == 'edit') { - if (!$field_id) - { - trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - $sql = 'SELECT l.*, f.* FROM ' . PROFILE_LANG_TABLE . ' l, ' . PROFILE_FIELDS_TABLE . ' f WHERE l.lang_id = ' . $this->edit_lang_id . " @@ -332,6 +295,7 @@ class acp_profile $this->edit_lang_id = $field_row['lang_id']; } $field_type = $field_row['field_type']; + $profile_field = $this->type_collection[$field_type]; // Get language entries $sql = 'SELECT * @@ -355,14 +319,15 @@ class acp_profile // We are adding a new field, define basic params $lang_options = $field_row = array(); - $field_type = request_var('field_type', 0); + $field_type = request_var('field_type', ''); - if (!$field_type) + if (!isset($this->type_collection[$field_type])) { trigger_error($user->lang['NO_FIELD_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); } - $field_row = array_merge($default_values[$field_type], array( + $profile_field = $this->type_collection[$field_type]; + $field_row = array_merge($profile_field->get_default_option_values(), array( 'field_ident' => str_replace(' ', '_', utf8_clean_string(request_var('field_ident', '', true))), 'field_required' => 0, 'field_show_novalue'=> 0, @@ -370,7 +335,12 @@ class acp_profile 'field_show_profile'=> 0, 'field_no_view' => 0, 'field_show_on_reg' => 0, + 'field_show_on_pm' => 0, 'field_show_on_vt' => 0, + 'field_show_on_ml' => 0, + 'field_is_contact' => 0, + 'field_contact_desc'=> '', + 'field_contact_url' => '', 'lang_name' => utf8_normalize_nfc(request_var('field_ident', '', true)), 'lang_explain' => '', 'lang_default_value'=> '') @@ -381,55 +351,40 @@ class acp_profile // $exclude contains the data we gather in each step $exclude = array( - 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_vt', 'field_required', 'field_show_novalue', 'field_hide', 'field_show_profile', 'field_no_view'), + 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_pm', 'field_show_on_vt', 'field_show_on_ml', 'field_required', 'field_show_novalue', 'field_hide', 'field_show_profile', 'field_no_view', 'field_is_contact', 'field_contact_desc', 'field_contact_url'), 2 => array('field_length', 'field_maxlen', 'field_minlen', 'field_validation', 'field_novalue', 'field_default_value'), 3 => array('l_lang_name', 'l_lang_explain', 'l_lang_default_value', 'l_lang_options') ); - // Text-based fields require the lang_default_value to be excluded - if ($field_type == FIELD_STRING || $field_type == FIELD_TEXT) - { - $exclude[1][] = 'lang_default_value'; - } - - // option-specific fields require lang_options to be excluded - if ($field_type == FIELD_BOOL || $field_type == FIELD_DROPDOWN) - { - $exclude[1][] = 'lang_options'; - } - - $cp->vars['field_ident'] = ($action == 'create' && $step == 1) ? utf8_clean_string(request_var('field_ident', $field_row['field_ident'], true)) : request_var('field_ident', $field_row['field_ident']); - $cp->vars['lang_name'] = utf8_normalize_nfc(request_var('lang_name', $field_row['lang_name'], true)); - $cp->vars['lang_explain'] = utf8_normalize_nfc(request_var('lang_explain', $field_row['lang_explain'], true)); - $cp->vars['lang_default_value'] = utf8_normalize_nfc(request_var('lang_default_value', $field_row['lang_default_value'], true)); - // Visibility Options... $visibility_ary = array( 'field_required', 'field_show_novalue', 'field_show_on_reg', + 'field_show_on_pm', 'field_show_on_vt', + 'field_show_on_ml', 'field_show_profile', 'field_hide', + 'field_is_contact', ); - foreach ($visibility_ary as $val) - { - $cp->vars[$val] = ($submit || $save) ? request_var($val, 0) : $field_row[$val]; - } + $options = $profile_field->prepare_options_form($exclude, $visibility_ary); - $cp->vars['field_no_view'] = request_var('field_no_view', (int) $field_row['field_no_view']); + $cp->vars['field_ident'] = ($action == 'create' && $step == 1) ? utf8_clean_string(request_var('field_ident', $field_row['field_ident'], true)) : request_var('field_ident', $field_row['field_ident']); + $cp->vars['lang_name'] = $request->variable('lang_name', $field_row['lang_name'], true); + $cp->vars['lang_explain'] = $request->variable('lang_explain', $field_row['lang_explain'], true); + $cp->vars['lang_default_value'] = $request->variable('lang_default_value', $field_row['lang_default_value'], true); + $cp->vars['field_contact_desc'] = $request->variable('field_contact_desc', $field_row['field_contact_desc'], true); + $cp->vars['field_contact_url'] = $request->variable('field_contact_url', $field_row['field_contact_url'], true); - // A boolean field expects an array as the lang options - if ($field_type == FIELD_BOOL) - { - $options = utf8_normalize_nfc(request_var('lang_options', array(''), true)); - } - else + foreach ($visibility_ary as $val) { - $options = utf8_normalize_nfc(request_var('lang_options', '', true)); + $cp->vars[$val] = ($submit || $save) ? $request->variable($val, 0) : $field_row[$val]; } + $cp->vars['field_no_view'] = $request->variable('field_no_view', (int) $field_row['field_no_view']); + // If the user has submitted a form with options (i.e. dropdown field) if ($options) { @@ -457,91 +412,9 @@ class acp_profile { $var = utf8_normalize_nfc(request_var($key, $field_row[$key], true)); - // Manipulate the intended variables a little bit if needed - if ($field_type == FIELD_DROPDOWN && $key == 'field_maxlen') - { - // Get the number of options if this key is 'field_maxlen' - $var = sizeof(explode("\n", utf8_normalize_nfc(request_var('lang_options', '', true)))); - } - else if ($field_type == FIELD_TEXT && $key == 'field_length') - { - if (isset($_REQUEST['rows'])) - { - $cp->vars['rows'] = request_var('rows', 0); - $cp->vars['columns'] = request_var('columns', 0); - $var = $cp->vars['rows'] . '|' . $cp->vars['columns']; - } - else - { - $row_col = explode('|', $var); - $cp->vars['rows'] = $row_col[0]; - $cp->vars['columns'] = $row_col[1]; - } - } - else if ($field_type == FIELD_DATE && $key == 'field_default_value') - { - $always_now = request_var('always_now', -1); - - if ($always_now == 1 || ($always_now === -1 && $var == 'now')) - { - $now = getdate(); - - $cp->vars['field_default_value_day'] = $now['mday']; - $cp->vars['field_default_value_month'] = $now['mon']; - $cp->vars['field_default_value_year'] = $now['year']; - $var = $_POST['field_default_value'] = 'now'; - } - else - { - if (isset($_REQUEST['field_default_value_day'])) - { - $cp->vars['field_default_value_day'] = request_var('field_default_value_day', 0); - $cp->vars['field_default_value_month'] = request_var('field_default_value_month', 0); - $cp->vars['field_default_value_year'] = request_var('field_default_value_year', 0); - $var = $_POST['field_default_value'] = sprintf('%2d-%2d-%4d', $cp->vars['field_default_value_day'], $cp->vars['field_default_value_month'], $cp->vars['field_default_value_year']); - } - else - { - list($cp->vars['field_default_value_day'], $cp->vars['field_default_value_month'], $cp->vars['field_default_value_year']) = explode('-', $var); - } - } - } - else if ($field_type == FIELD_BOOL && $key == 'field_default_value') - { - // 'field_length' == 1 defines radio buttons. Possible values are 1 or 2 only. - // 'field_length' == 2 defines checkbox. Possible values are 0 or 1 only. - // If we switch the type on step 2, we have to adjust field value. - // 1 is a common value for the checkbox and radio buttons. - - // Adjust unchecked checkbox value. - // If we return or save settings from 2nd/3rd page - // and the checkbox is unchecked, set the value to 0. - if (isset($_REQUEST['step']) && !isset($_REQUEST[$key])) - { - $var = 0; - } - - // If we switch to the checkbox type but former radio buttons value was 2, - // which is not the case for the checkbox, set it to 0 (unchecked). - if ($cp->vars['field_length'] == 2 && $var == 2) - { - $var = 0; - } - // If we switch to the radio buttons but the former checkbox value was 0, - // which is not the case for the radio buttons, set it to 0. - else if ($cp->vars['field_length'] == 1 && $var == 0) - { - $var = 2; - } - } - else if ($field_type == FIELD_INT && $key == 'field_default_value') - { - // Permit an empty string - if ($action == 'create' && request_var('field_default_value', '') === '') - { - $var = ''; - } - } + $field_data = $cp->vars; + $var = $profile_field->get_excluded_options($key, $action, $var, $field_data, 2); + $cp->vars = $field_data; $cp->vars[$key] = $var; } @@ -564,7 +437,6 @@ class acp_profile } $db->sql_freeresult($result); - $sql = 'SELECT lang_id, lang_name, lang_explain, lang_default_value FROM ' . PROFILE_LANG_TABLE . ' WHERE lang_id <> ' . $this->edit_lang_id . " @@ -588,20 +460,12 @@ class acp_profile if (!$cp->vars[$key] && $action == 'edit') { - $cp->vars[$key] = $$key; - } - else if ($key == 'l_lang_options' && $field_type == FIELD_BOOL) - { - $cp->vars[$key] = utf8_normalize_nfc(request_var($key, array(0 => array('')), true)); + $cp->vars[$key] = ${$key}; } - else if ($key == 'l_lang_options' && is_array($cp->vars[$key])) - { - foreach ($cp->vars[$key] as $lang_id => $options) - { - $cp->vars[$key][$lang_id] = explode("\n", $options); - } - } + $field_data = $cp->vars; + $var = $profile_field->get_excluded_options($key, $action, $var, $field_data, 3); + $cp->vars = $field_data; } // Check for general issues in every step @@ -628,15 +492,7 @@ class acp_profile $error[] = $user->lang['EMPTY_USER_FIELD_NAME']; } - if ($field_type == FIELD_DROPDOWN && !sizeof($cp->vars['lang_options'])) - { - $error[] = $user->lang['NO_FIELD_ENTRIES']; - } - - if ($field_type == FIELD_BOOL && (empty($cp->vars['lang_options'][0]) || empty($cp->vars['lang_options'][1]))) - { - $error[] = $user->lang['NO_FIELD_ENTRIES']; - } + $error = $profile_field->validate_options_on_submit($error, $cp->vars); // Check for already existing field ident if ($action != 'edit') @@ -673,54 +529,16 @@ class acp_profile $_new_key_ary = array(); + $field_data = $cp->vars; foreach ($key_ary as $key) { - if ($field_type == FIELD_TEXT && $key == 'field_length' && isset($_REQUEST['rows'])) + $var = $profile_field->prepare_hidden_fields($step, $key, $action, $field_data); + if ($var !== null) { - $cp->vars['rows'] = request_var('rows', 0); - $cp->vars['columns'] = request_var('columns', 0); - $_new_key_ary[$key] = $cp->vars['rows'] . '|' . $cp->vars['columns']; - } - else if ($field_type == FIELD_DATE && $key == 'field_default_value') - { - $always_now = request_var('always_now', 0); - - if ($always_now) - { - $_new_key_ary[$key] = 'now'; - } - else if (isset($_REQUEST['field_default_value_day'])) - { - $cp->vars['field_default_value_day'] = request_var('field_default_value_day', 0); - $cp->vars['field_default_value_month'] = request_var('field_default_value_month', 0); - $cp->vars['field_default_value_year'] = request_var('field_default_value_year', 0); - $_new_key_ary[$key] = sprintf('%2d-%2d-%4d', $cp->vars['field_default_value_day'], $cp->vars['field_default_value_month'], $cp->vars['field_default_value_year']); - } - } - else if ($field_type == FIELD_BOOL && $key == 'l_lang_options' && isset($_REQUEST['l_lang_options'])) - { - $_new_key_ary[$key] = utf8_normalize_nfc(request_var($key, array(array('')), true)); - } - else if ($field_type == FIELD_BOOL && $key == 'field_default_value') - { - $_new_key_ary[$key] = request_var($key, $cp->vars[$key]); - } - else - { - if (!isset($_REQUEST[$key])) - { - $var = false; - } - else if ($key == 'field_ident' && isset($cp->vars[$key])) - { - $_new_key_ary[$key]= $cp->vars[$key]; - } - else - { - $_new_key_ary[$key] = (is_array($_REQUEST[$key])) ? utf8_normalize_nfc(request_var($key, array(''), true)) : utf8_normalize_nfc(request_var($key, '', true)); - } + $_new_key_ary[$key] = $profile_field->prepare_hidden_fields($step, $key, $action, $field_data); } } + $cp->vars = $field_data; $s_hidden_fields .= build_hidden_fields($_new_key_ary); } @@ -754,66 +572,34 @@ class acp_profile { // Create basic options - only small differences between field types case 1: - - // Build common create options - $template->assign_vars(array( + $template_vars = array( 'S_STEP_ONE' => true, 'S_FIELD_REQUIRED' => ($cp->vars['field_required']) ? true : false, 'S_FIELD_SHOW_NOVALUE'=> ($cp->vars['field_show_novalue']) ? true : false, 'S_SHOW_ON_REG' => ($cp->vars['field_show_on_reg']) ? true : false, + 'S_SHOW_ON_PM' => ($cp->vars['field_show_on_pm']) ? true : false, 'S_SHOW_ON_VT' => ($cp->vars['field_show_on_vt']) ? true : false, + 'S_SHOW_ON_MEMBERLIST'=> ($cp->vars['field_show_on_ml']) ? true : false, 'S_FIELD_HIDE' => ($cp->vars['field_hide']) ? true : false, 'S_SHOW_PROFILE' => ($cp->vars['field_show_profile']) ? true : false, 'S_FIELD_NO_VIEW' => ($cp->vars['field_no_view']) ? true : false, + 'S_FIELD_CONTACT' => $cp->vars['field_is_contact'], + 'FIELD_CONTACT_DESC'=> $cp->vars['field_contact_desc'], + 'FIELD_CONTACT_URL' => $cp->vars['field_contact_url'], 'L_LANG_SPECIFIC' => sprintf($user->lang['LANG_SPECIFIC_OPTIONS'], $config['default_lang']), - 'FIELD_TYPE' => $user->lang['FIELD_' . strtoupper($cp->profile_types[$field_type])], + 'FIELD_TYPE' => $profile_field->get_name(), 'FIELD_IDENT' => $cp->vars['field_ident'], 'LANG_NAME' => $cp->vars['lang_name'], - 'LANG_EXPLAIN' => $cp->vars['lang_explain']) + 'LANG_EXPLAIN' => $cp->vars['lang_explain'], ); - // String and Text needs to set default values here... - if ($field_type == FIELD_STRING || $field_type == FIELD_TEXT) - { - $template->assign_vars(array( - 'S_TEXT' => ($field_type == FIELD_TEXT) ? true : false, - 'S_STRING' => ($field_type == FIELD_STRING) ? true : false, - - 'L_DEFAULT_VALUE_EXPLAIN' => $user->lang[strtoupper($cp->profile_types[$field_type]) . '_DEFAULT_VALUE_EXPLAIN'], - 'LANG_DEFAULT_VALUE' => $cp->vars['lang_default_value']) - ); - } - - if ($field_type == FIELD_BOOL || $field_type == FIELD_DROPDOWN) - { - // Initialize these array elements if we are creating a new field - if (!sizeof($cp->vars['lang_options'])) - { - if ($field_type == FIELD_BOOL) - { - // No options have been defined for a boolean field. - $cp->vars['lang_options'][0] = ''; - $cp->vars['lang_options'][1] = ''; - } - else - { - // No options have been defined for the dropdown menu - $cp->vars['lang_options'] = array(); - } - } - - $template->assign_vars(array( - 'S_BOOL' => ($field_type == FIELD_BOOL) ? true : false, - 'S_DROPDOWN' => ($field_type == FIELD_DROPDOWN) ? true : false, - - 'L_LANG_OPTIONS_EXPLAIN' => $user->lang[strtoupper($cp->profile_types[$field_type]) . '_ENTRIES_EXPLAIN'], - 'LANG_OPTIONS' => ($field_type == FIELD_DROPDOWN) ? implode("\n", $cp->vars['lang_options']) : '', - 'FIRST_LANG_OPTION' => ($field_type == FIELD_BOOL) ? $cp->vars['lang_options'][0] : '', - 'SECOND_LANG_OPTION' => ($field_type == FIELD_BOOL) ? $cp->vars['lang_options'][1] : '') - ); - } + $field_data = $cp->vars; + $profile_field->display_options($template_vars, $field_data); + $cp->vars = $field_data; + // Build common create options + $template->assign_vars($template_vars); break; case 2: @@ -824,8 +610,7 @@ class acp_profile ); // Build options based on profile type - $function = 'get_' . $cp->profile_types[$field_type] . '_options'; - $options = $cp->$function(); + $options = $profile_field->get_options($this->lang_defs['iso'][$config['default_lang']], $cp->vars); foreach ($options as $num => $option_ary) { @@ -887,17 +672,18 @@ class acp_profile $s_one_need_edit = true; } + $profile_field = $this->type_collection[$row['field_type']]; $template->assign_block_vars('fields', array( 'FIELD_IDENT' => $row['field_ident'], - 'FIELD_TYPE' => $user->lang['FIELD_' . strtoupper($cp->profile_types[$row['field_type']])], + 'FIELD_TYPE' => $profile_field->get_name(), 'L_ACTIVATE_DEACTIVATE' => $user->lang[$active_lang], 'U_ACTIVATE_DEACTIVATE' => $this->u_action . "&action=$active_value&field_id=$id", 'U_EDIT' => $this->u_action . "&action=edit&field_id=$id", 'U_TRANSLATE' => $this->u_action . "&action=edit&field_id=$id&step=3", 'U_DELETE' => $this->u_action . "&action=delete&field_id=$id", - 'U_MOVE_UP' => $this->u_action . "&action=move_up&order={$row['field_order']}", - 'U_MOVE_DOWN' => $this->u_action . "&action=move_down&order={$row['field_order']}", + 'U_MOVE_UP' => $this->u_action . "&action=move_up&field_id=$id", + 'U_MOVE_DOWN' => $this->u_action . "&action=move_down&field_id=$id", 'S_NEED_EDIT' => $s_need_edit) ); @@ -911,15 +697,15 @@ class acp_profile } $s_select_type = ''; - foreach ($cp->profile_types as $key => $value) + foreach ($this->type_collection as $key => $profile_field) { - $s_select_type .= '<option value="' . $key . '">' . $user->lang['FIELD_' . strtoupper($value)] . '</option>'; + $s_select_type .= '<option value="' . $key . '">' . $profile_field->get_name() . '</option>'; } $template->assign_vars(array( 'U_ACTION' => $this->u_action, - 'S_TYPE_OPTIONS' => $s_select_type) - ); + 'S_TYPE_OPTIONS' => $s_select_type, + )); } /** @@ -927,7 +713,7 @@ class acp_profile */ function build_language_options(&$cp, $field_type, $action = 'create') { - global $user, $config, $db; + global $user, $config, $db, $phpbb_container; $default_lang_id = (!empty($this->edit_lang_id)) ? $this->edit_lang_id : $this->lang_defs['iso'][$config['default_lang']]; @@ -944,31 +730,8 @@ class acp_profile } $db->sql_freeresult($result); - $options = array(); - $options['lang_name'] = 'string'; - if ($cp->vars['lang_explain']) - { - $options['lang_explain'] = 'text'; - } - - switch ($field_type) - { - case FIELD_BOOL: - $options['lang_options'] = 'two_options'; - break; - - case FIELD_DROPDOWN: - $options['lang_options'] = 'optionfield'; - break; - - case FIELD_TEXT: - case FIELD_STRING: - if (strlen($cp->vars['lang_default_value'])) - { - $options['lang_default_value'] = ($field_type == FIELD_STRING) ? 'string' : 'text'; - } - break; - } + $profile_field = $this->type_collection[$field_type]; + $options = $profile_field->get_language_options($cp->vars); $lang_options = array(); @@ -1047,7 +810,7 @@ class acp_profile */ function save_profile_field(&$cp, $field_type, $action = 'create') { - global $db, $config, $user; + global $db, $config, $user, $phpbb_container; $field_id = request_var('field_id', 0); @@ -1078,10 +841,15 @@ class acp_profile 'field_required' => $cp->vars['field_required'], 'field_show_novalue' => $cp->vars['field_show_novalue'], 'field_show_on_reg' => $cp->vars['field_show_on_reg'], + 'field_show_on_pm' => $cp->vars['field_show_on_pm'], 'field_show_on_vt' => $cp->vars['field_show_on_vt'], + 'field_show_on_ml' => $cp->vars['field_show_on_ml'], 'field_hide' => $cp->vars['field_hide'], 'field_show_profile' => $cp->vars['field_show_profile'], - 'field_no_view' => $cp->vars['field_no_view'] + 'field_no_view' => $cp->vars['field_no_view'], + 'field_is_contact' => $cp->vars['field_is_contact'], + 'field_contact_desc' => $cp->vars['field_contact_desc'], + 'field_contact_url' => $cp->vars['field_contact_url'], ); if ($action == 'create') @@ -1107,10 +875,14 @@ class acp_profile $db->sql_query($sql); } + $profile_field = $this->type_collection[$field_type]; + if ($action == 'create') { $field_ident = 'pf_' . $field_ident; - $profile_sql[] = $this->add_field_ident($field_ident, $field_type); + + $db_tools = $phpbb_container->get('dbal.tools'); + $db_tools->sql_column_add(PROFILE_FIELDS_DATA_TABLE, $field_ident, array($profile_field->get_database_column_type(), null)); } $sql_ary = array( @@ -1164,23 +936,7 @@ class acp_profile } } - // These are always arrays because the key is the language id... - $cp->vars['l_lang_name'] = utf8_normalize_nfc(request_var('l_lang_name', array(0 => ''), true)); - $cp->vars['l_lang_explain'] = utf8_normalize_nfc(request_var('l_lang_explain', array(0 => ''), true)); - $cp->vars['l_lang_default_value'] = utf8_normalize_nfc(request_var('l_lang_default_value', array(0 => ''), true)); - - if ($field_type != FIELD_BOOL) - { - $cp->vars['l_lang_options'] = utf8_normalize_nfc(request_var('l_lang_options', array(0 => ''), true)); - } - else - { - /** - * @todo check if this line is correct... - $cp->vars['l_lang_default_value'] = request_var('l_lang_default_value', array(0 => array('')), true); - */ - $cp->vars['l_lang_options'] = utf8_normalize_nfc(request_var('l_lang_options', array(0 => array('')), true)); - } + $cp->vars = $profile_field->get_language_options_input($cp->vars); if ($cp->vars['lang_options']) { @@ -1200,7 +956,7 @@ class acp_profile foreach ($cp->vars['lang_options'] as $option_id => $value) { $sql_ary = array( - 'field_type' => (int) $field_type, + 'field_type' => $field_type, 'lang_value' => $value ); @@ -1255,7 +1011,7 @@ class acp_profile 'field_id' => (int) $field_id, 'lang_id' => (int) $lang_id, 'option_id' => (int) $option_id, - 'field_type' => (int) $field_type, + 'field_type' => $field_type, 'lang_value' => $value ); } @@ -1309,7 +1065,6 @@ class acp_profile } } - $db->sql_transaction('begin'); if ($action == 'create') @@ -1381,277 +1136,4 @@ class acp_profile } } } - - /** - * Return sql statement for adding a new field ident (profile field) to the profile fields data table - */ - function add_field_ident($field_ident, $field_type) - { - global $db; - - switch ($db->sql_layer) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - - // We are defining the biggest common value, because of the possibility to edit the min/max values of each field. - $sql = 'ALTER TABLE ' . PROFILE_FIELDS_DATA_TABLE . " ADD `$field_ident` "; - - switch ($field_type) - { - case FIELD_STRING: - $sql .= ' VARCHAR(255) '; - break; - - case FIELD_DATE: - $sql .= 'VARCHAR(10) '; - break; - - case FIELD_TEXT: - $sql .= "TEXT"; - // ADD {$field_ident}_bbcode_uid VARCHAR(5) NOT NULL, - // ADD {$field_ident}_bbcode_bitfield INT(11) UNSIGNED"; - break; - - case FIELD_BOOL: - $sql .= 'TINYINT(2) '; - break; - - case FIELD_DROPDOWN: - $sql .= 'MEDIUMINT(8) '; - break; - - case FIELD_INT: - $sql .= 'BIGINT(20) '; - break; - } - - break; - - case 'sqlite': - - switch ($field_type) - { - case FIELD_STRING: - $type = ' VARCHAR(255) '; - break; - - case FIELD_DATE: - $type = 'VARCHAR(10) '; - break; - - case FIELD_TEXT: - $type = "TEXT(65535)"; - // ADD {$field_ident}_bbcode_uid VARCHAR(5) NOT NULL, - // ADD {$field_ident}_bbcode_bitfield INT(11) UNSIGNED"; - break; - - case FIELD_BOOL: - $type = 'TINYINT(2) '; - break; - - case FIELD_DROPDOWN: - $type = 'MEDIUMINT(8) '; - break; - - case FIELD_INT: - $type = 'BIGINT(20) '; - break; - } - - // We are defining the biggest common value, because of the possibility to edit the min/max values of each field. - if (version_compare(sqlite_libversion(), '3.0') == -1) - { - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '" . PROFILE_FIELDS_DATA_TABLE . "' - ORDER BY type DESC, name;"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Create a temp table and populate it, destroy the existing one - $db->sql_query(preg_replace('#CREATE\s+TABLE\s+"?' . PROFILE_FIELDS_DATA_TABLE . '"?#i', 'CREATE TEMPORARY TABLE ' . PROFILE_FIELDS_DATA_TABLE . '_temp', $row['sql'])); - $db->sql_query('INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . '_temp SELECT * FROM ' . PROFILE_FIELDS_DATA_TABLE); - $db->sql_query('DROP TABLE ' . PROFILE_FIELDS_DATA_TABLE); - - preg_match('#\((.*)\)#s', $row['sql'], $matches); - - $new_table_cols = trim($matches[1]); - $old_table_cols = explode(',', $new_table_cols); - $column_list = array(); - - foreach ($old_table_cols as $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY') - { - continue; - } - $column_list[] = $entities[0]; - } - - $columns = implode(',', $column_list); - - $new_table_cols = $field_ident . ' ' . $type . ',' . $new_table_cols; - - // create a new table and fill it up. destroy the temp one - $db->sql_query('CREATE TABLE ' . PROFILE_FIELDS_DATA_TABLE . ' (' . $new_table_cols . ');'); - $db->sql_query('INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . PROFILE_FIELDS_DATA_TABLE . '_temp;'); - $db->sql_query('DROP TABLE ' . PROFILE_FIELDS_DATA_TABLE . '_temp'); - } - else - { - $sql = 'ALTER TABLE ' . PROFILE_FIELDS_DATA_TABLE . " ADD $field_ident [$type]"; - } - - break; - - case 'mssql': - case 'mssql_odbc': - case 'mssqlnative': - - // We are defining the biggest common value, because of the possibility to edit the min/max values of each field. - $sql = 'ALTER TABLE [' . PROFILE_FIELDS_DATA_TABLE . "] ADD [$field_ident] "; - - switch ($field_type) - { - case FIELD_STRING: - $sql .= ' [VARCHAR] (255) '; - break; - - case FIELD_DATE: - $sql .= '[VARCHAR] (10) '; - break; - - case FIELD_TEXT: - $sql .= "[TEXT]"; - // ADD {$field_ident}_bbcode_uid [VARCHAR] (5) NOT NULL, - // ADD {$field_ident}_bbcode_bitfield [INT] UNSIGNED"; - break; - - case FIELD_BOOL: - case FIELD_DROPDOWN: - $sql .= '[INT] '; - break; - - case FIELD_INT: - $sql .= '[FLOAT] '; - break; - } - - break; - - case 'postgres': - - // We are defining the biggest common value, because of the possibility to edit the min/max values of each field. - $sql = 'ALTER TABLE ' . PROFILE_FIELDS_DATA_TABLE . " ADD COLUMN \"$field_ident\" "; - - switch ($field_type) - { - case FIELD_STRING: - $sql .= ' VARCHAR(255) '; - break; - - case FIELD_DATE: - $sql .= 'VARCHAR(10) '; - break; - - case FIELD_TEXT: - $sql .= "TEXT"; - // ADD {$field_ident}_bbcode_uid VARCHAR(5) NOT NULL, - // ADD {$field_ident}_bbcode_bitfield INT4 UNSIGNED"; - break; - - case FIELD_BOOL: - $sql .= 'INT2 '; - break; - - case FIELD_DROPDOWN: - $sql .= 'INT4 '; - break; - - case FIELD_INT: - $sql .= 'INT8 '; - break; - } - - break; - - case 'firebird': - - // We are defining the biggest common value, because of the possibility to edit the min/max values of each field. - $sql = 'ALTER TABLE ' . PROFILE_FIELDS_DATA_TABLE . ' ADD "' . strtoupper($field_ident) . '" '; - - switch ($field_type) - { - case FIELD_STRING: - $sql .= ' VARCHAR(255) '; - break; - - case FIELD_DATE: - $sql .= 'VARCHAR(10) '; - break; - - case FIELD_TEXT: - $sql .= "BLOB SUB_TYPE TEXT"; - // ADD {$field_ident}_bbcode_uid VARCHAR(5) NOT NULL, - // ADD {$field_ident}_bbcode_bitfield INTEGER UNSIGNED"; - break; - - case FIELD_BOOL: - case FIELD_DROPDOWN: - $sql .= 'INTEGER '; - break; - - case FIELD_INT: - $sql .= 'DOUBLE PRECISION '; - break; - } - - break; - - case 'oracle': - - // We are defining the biggest common value, because of the possibility to edit the min/max values of each field. - $sql = 'ALTER TABLE ' . PROFILE_FIELDS_DATA_TABLE . " ADD $field_ident "; - - switch ($field_type) - { - case FIELD_STRING: - $sql .= ' VARCHAR2(255) '; - break; - - case FIELD_DATE: - $sql .= 'VARCHAR2(10) '; - break; - - case FIELD_TEXT: - $sql .= "CLOB"; - // ADD {$field_ident}_bbcode_uid VARCHAR2(5) NOT NULL, - // ADD {$field_ident}_bbcode_bitfield NUMBER(11) UNSIGNED"; - break; - - case FIELD_BOOL: - $sql .= 'NUMBER(2) '; - break; - - case FIELD_DROPDOWN: - $sql .= 'NUMBER(8) '; - break; - - case FIELD_INT: - $sql .= 'NUMBER(20) '; - break; - } - - break; - } - - return $sql; - } } - -?> diff --git a/phpBB/includes/acp/acp_prune.php b/phpBB/includes/acp/acp_prune.php index ffe20f86f5..6eb213fd7a 100644 --- a/phpBB/includes/acp/acp_prune.php +++ b/phpBB/includes/acp/acp_prune.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_prune { var $u_action; @@ -80,7 +80,7 @@ class acp_prune $prune_posted = request_var('prune_days', 0); $prune_viewed = request_var('prune_vieweddays', 0); $prune_all = (!$prune_posted && !$prune_viewed) ? true : false; - + $prune_flags = 0; $prune_flags += (request_var('prune_old_polls', 0)) ? 2 : 0; $prune_flags += (request_var('prune_announce', 0)) ? 4 : 0; @@ -110,7 +110,7 @@ class acp_prune $p_result['topics'] = 0; $p_result['posts'] = 0; $log_data = ''; - + do { if (!$auth->acl_get('f_list', $row['forum_id'])) @@ -130,7 +130,7 @@ class acp_prune $p_result['topics'] += $return['topics']; $p_result['posts'] += $return['posts']; } - + if ($prune_viewed) { $return = prune($row['forum_id'], 'viewed', $prunedate_viewed, $prune_flags, false); @@ -146,11 +146,11 @@ class acp_prune 'NUM_TOPICS' => $p_result['topics'], 'NUM_POSTS' => $p_result['posts']) ); - + $log_data .= (($log_data != '') ? ', ' : '') . $row['forum_name']; } while ($row = $db->sql_fetchrow($result)); - + // Sync all pruned forums at once sync('forum', 'forum_id', $prune_ids, true, true); add_log('admin', 'LOG_PRUNE', $log_data); @@ -243,8 +243,8 @@ class acp_prune if (confirm_box(true)) { $user_ids = $usernames = array(); - $this->get_prune_users($user_ids, $usernames); + $this->get_prune_users($user_ids, $usernames); if (sizeof($user_ids)) { if ($action == 'deactivate') @@ -256,19 +256,13 @@ class acp_prune { if ($deleteposts) { - foreach ($user_ids as $user_id) - { - user_delete('remove', $user_id); - } - + user_delete('remove', $user_ids); + $l_log = 'LOG_PRUNE_USER_DEL_DEL'; } else { - foreach ($user_ids as $user_id) - { - user_delete('retain', $user_id, $usernames[$user_id]); - } + user_delete('retain', $user_ids, true); $l_log = 'LOG_PRUNE_USER_DEL_ANON'; } @@ -300,7 +294,8 @@ class acp_prune { $template->assign_block_vars('users', array( 'USERNAME' => $usernames[$user_id], - 'U_PROFILE' => append_sid($phpbb_root_path . 'memberlist.' . $phpEx, 'mode=viewprofile&u=' . $user_id), + 'USER_ID' => $user_id, + 'U_PROFILE' => get_username_string('profile', $user_id, $usernames[$user_id]), 'U_USER_ADMIN' => ($auth->acl_get('a_user')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview&u=' . $user_id, true, $user->session_id) : '', )); } @@ -315,17 +310,7 @@ class acp_prune 'mode' => $mode, 'prune' => 1, - 'users' => utf8_normalize_nfc(request_var('users', '', true)), - 'username' => utf8_normalize_nfc(request_var('username', '', true)), - 'email' => request_var('email', ''), - 'joined_select' => request_var('joined_select', ''), - 'joined' => request_var('joined', ''), - 'active_select' => request_var('active_select', ''), - 'active' => request_var('active', ''), - 'count_select' => request_var('count_select', ''), - 'count' => request_var('count', ''), 'deleteposts' => request_var('deleteposts', 0), - 'action' => request_var('action', ''), )), 'confirm_body_prune.html'); } @@ -341,22 +326,36 @@ class acp_prune } $find_time = array('lt' => $user->lang['BEFORE'], 'gt' => $user->lang['AFTER']); - $s_find_join_time = ''; - foreach ($find_time as $key => $value) - { - $s_find_join_time .= '<option value="' . $key . '">' . $value . '</option>'; - } - $s_find_active_time = ''; foreach ($find_time as $key => $value) { $s_find_active_time .= '<option value="' . $key . '">' . $value . '</option>'; } + $sql = 'SELECT group_id, group_name + FROM ' . GROUPS_TABLE . ' + WHERE group_type <> ' . GROUP_SPECIAL . ' + ORDER BY group_name ASC'; + $result = $db->sql_query($sql); + + $s_group_list = ''; + while ($row = $db->sql_fetchrow($result)) + { + $s_group_list .= '<option value="' . $row['group_id'] . '">' . $row['group_name'] . '</option>'; + } + $db->sql_freeresult($result); + + if ($s_group_list) + { + // Only prepend the "All groups" option if there are groups, + // otherwise we don't want to display this option at all. + $s_group_list = '<option value="0">' . $user->lang['PRUNE_USERS_GROUP_NONE'] . '</option>' . $s_group_list; + } + $template->assign_vars(array( 'U_ACTION' => $this->u_action, - 'S_JOINED_OPTIONS' => $s_find_join_time, 'S_ACTIVE_OPTIONS' => $s_find_active_time, + 'S_GROUP_LIST' => $s_group_list, 'S_COUNT_OPTIONS' => $s_find_count, 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=acp_prune&field=users'), )); @@ -367,50 +366,86 @@ class acp_prune */ function get_prune_users(&$user_ids, &$usernames) { - global $user, $db; + global $user, $db, $request; - $users = utf8_normalize_nfc(request_var('users', '', true)); - - if ($users) + $users_by_name = request_var('users', '', true); + $users_by_id = request_var('user_ids', array(0)); + $group_id = request_var('group_id', 0); + $posts_on_queue = (trim($request->variable('posts_on_queue', '')) === '') ? false : $request->variable('posts_on_queue', 0); + + if ($users_by_name) { - $users = explode("\n", $users); + $users = explode("\n", $users_by_name); $where_sql = ' AND ' . $db->sql_in_set('username_clean', array_map('utf8_clean_string', $users)); } + else if (!empty($users_by_id)) + { + $user_ids = $users_by_id; + user_get_id_name($user_ids, $usernames); + + $where_sql = ' AND ' . $db->sql_in_set('user_id', $user_ids); + } else { - $username = utf8_normalize_nfc(request_var('username', '', true)); + $username = request_var('username', '', true); $email = request_var('email', ''); - $joined_select = request_var('joined_select', 'lt'); $active_select = request_var('active_select', 'lt'); $count_select = request_var('count_select', 'eq'); - $joined = request_var('joined', ''); + $queue_select = request_var('queue_select', 'gt'); + $joined_before = request_var('joined_before', ''); + $joined_after = request_var('joined_after', ''); $active = request_var('active', ''); + $count = ($request->variable('count', '') === '') ? false : $request->variable('count', 0); + $active = ($active) ? explode('-', $active) : array(); - $joined = ($joined) ? explode('-', $joined) : array(); + $joined_before = ($joined_before) ? explode('-', $joined_before) : array(); + $joined_after = ($joined_after) ? explode('-', $joined_after) : array(); - if ((sizeof($active) && sizeof($active) != 3) || (sizeof($joined) && sizeof($joined) != 3)) + // calculate the conditions required by the join time criteria + $joined_sql = ''; + if (!empty($joined_before) && !empty($joined_after)) { - trigger_error($user->lang['WRONG_ACTIVE_JOINED_DATE'] . adm_back_link($this->u_action), E_USER_WARNING); + // if the two entered dates are equal, we need to adjust + // so that our time range is a full day instead of 1 second + if ($joined_after == $joined_before) + { + $joined_after[2] += 1; + } + + $joined_sql = ' AND user_regdate BETWEEN ' . gmmktime(0, 0, 0, (int) $joined_after[1], (int) $joined_after[2], (int) $joined_after[0]) . + ' AND ' . gmmktime(0, 0, 0, (int) $joined_before[1], (int) $joined_before[2], (int) $joined_before[0]); + } + else if (empty($joined_before) && !empty($joined_after)) + { + $joined_sql = ' AND user_regdate > ' . gmmktime(0, 0, 0, (int) $joined_after[1], (int) $joined_after[2], (int) $joined_after[0]); + } + else if (empty($joined_after) && !empty($joined_before)) + { + $joined_sql = ' AND user_regdate < ' . gmmktime(0, 0, 0, (int) $joined_before[1], (int) $joined_before[2], (int) $joined_before[0]); } + // implicit else when both arrays are empty do nothing - $count = request_var('count', ''); + if ((sizeof($active) && sizeof($active) != 3) || (sizeof($joined_before) && sizeof($joined_before) != 3) || (sizeof($joined_after) && sizeof($joined_after) != 3)) + { + trigger_error($user->lang['WRONG_ACTIVE_JOINED_DATE'] . adm_back_link($this->u_action), E_USER_WARNING); + } $key_match = array('lt' => '<', 'gt' => '>', 'eq' => '='); $sort_by_types = array('username', 'user_email', 'user_posts', 'user_regdate', 'user_lastvisit'); $where_sql = ''; - $where_sql .= ($username) ? ' AND username_clean ' . $db->sql_like_expression(str_replace('*', $db->any_char, utf8_clean_string($username))) : ''; - $where_sql .= ($email) ? ' AND user_email ' . $db->sql_like_expression(str_replace('*', $db->any_char, $email)) . ' ' : ''; - $where_sql .= (sizeof($joined)) ? " AND user_regdate " . $key_match[$joined_select] . ' ' . gmmktime(0, 0, 0, (int) $joined[1], (int) $joined[2], (int) $joined[0]) : ''; - $where_sql .= ($count !== '') ? " AND user_posts " . $key_match[$count_select] . ' ' . (int) $count . ' ' : ''; + $where_sql .= ($username) ? ' AND username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($username))) : ''; + $where_sql .= ($email) ? ' AND user_email ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), $email)) . ' ' : ''; + $where_sql .= $joined_sql; + $where_sql .= ($count !== false) ? " AND user_posts " . $key_match[$count_select] . ' ' . (int) $count . ' ' : ''; // First handle pruning of users who never logged in, last active date is 0000-00-00 if (sizeof($active) && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0) { $where_sql .= ' AND user_lastvisit = 0'; - } + } else if (sizeof($active) && $active_select != 'lt') { $where_sql .= ' AND user_lastvisit ' . $key_match[$active_select] . ' ' . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]); @@ -421,8 +456,8 @@ class acp_prune } } - // Protect the admin, do not prune if no options are given... - if (!$where_sql) + // If no search criteria were provided, go no further. + if (!$where_sql && !$group_id && $posts_on_queue === false) { return; } @@ -439,28 +474,84 @@ class acp_prune } $db->sql_freeresult($result); - // Do not prune founder members - $sql = 'SELECT user_id, username - FROM ' . USERS_TABLE . ' - WHERE user_id <> ' . ANONYMOUS . ' - AND user_type <> ' . USER_FOUNDER . " - $where_sql"; - $result = $db->sql_query($sql); + // Protect the admin, do not prune if no options are given... + if ($where_sql) + { + // Do not prune founder members + $sql = 'SELECT user_id, username + FROM ' . USERS_TABLE . ' + WHERE user_id <> ' . ANONYMOUS . ' + AND user_type <> ' . USER_FOUNDER . " + $where_sql"; + $result = $db->sql_query($sql); - $where_sql = ''; - $user_ids = $usernames = array(); + $user_ids = $usernames = array(); - while ($row = $db->sql_fetchrow($result)) + while ($row = $db->sql_fetchrow($result)) + { + // Do not prune bots and the user currently pruning. + if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) + { + $user_ids[] = $row['user_id']; + $usernames[$row['user_id']] = $row['username']; + } + } + $db->sql_freeresult($result); + } + + if ($group_id) { - // Do not prune bots and the user currently pruning. - if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) + $sql = 'SELECT u.user_id, u.username + FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u + WHERE ug.group_id = ' . (int) $group_id . ' + AND ug.user_id <> ' . ANONYMOUS . ' + AND u.user_type <> ' . USER_FOUNDER . ' + AND ug.user_pending = 0 ' . + ((!empty($user_ids)) ? ' AND ' . $db->sql_in_set('ug.user_id', $user_ids) : '') . ' + AND u.user_id = ug.user_id'; + $result = $db->sql_query($sql); + + // we're performing an intersection operation, so all the relevant users + // come from this most recent query (which was limited to the results of the + // previous query) + $user_ids = $usernames = array(); + while ($row = $db->sql_fetchrow($result)) { - $user_ids[] = $row['user_id']; - $usernames[$row['user_id']] = $row['username']; + // Do not prune bots and the user currently pruning. + if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) + { + $user_ids[] = $row['user_id']; + $usernames[$row['user_id']] = $row['username']; + } } + $db->sql_freeresult($result); + } + + if ($posts_on_queue !== false) + { + $sql = 'SELECT u.user_id, u.username, COUNT(p.post_id) AS queue_posts + FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u + WHERE u.user_id <> ' . ANONYMOUS . ' + AND u.user_type <> ' . USER_FOUNDER . + ((!empty($user_ids)) ? ' AND ' . $db->sql_in_set('p.poster_id', $user_ids) : '') . ' + AND ' . $db->sql_in_set('p.post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)) . ' + AND u.user_id = p.poster_id + GROUP BY p.poster_id + HAVING queue_posts ' . $key_match[$queue_select] . ' ' . $posts_on_queue; + $result = $db->sql_query($sql); + + // same intersection logic as the above group ID portion + $user_ids = $usernames = array(); + while ($row = $db->sql_fetchrow($result)) + { + // Do not prune bots and the user currently pruning. + if ($row['user_id'] != $user->data['user_id'] && !in_array($row['user_id'], $bot_ids)) + { + $user_ids[] = $row['user_id']; + $usernames[$row['user_id']] = $row['username']; + } + } + $db->sql_freeresult($result); } - $db->sql_freeresult($result); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_ranks.php b/phpBB/includes/acp/acp_ranks.php index ea057cd84c..5885de57ec 100644 --- a/phpBB/includes/acp/acp_ranks.php +++ b/phpBB/includes/acp/acp_ranks.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,16 +19,13 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_ranks { var $u_action; function main($id, $mode) { - global $db, $user, $auth, $template, $cache; + global $db, $user, $auth, $template, $cache, $request, $phpbb_dispatcher; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; $user->add_lang('acp/posting'); @@ -72,7 +72,18 @@ class acp_ranks 'rank_min' => $min_posts, 'rank_image' => htmlspecialchars_decode($rank_image) ); - + + /** + * Modify the SQL array when saving a rank + * + * @event core.acp_ranks_save_modify_sql_ary + * @var int rank_id The ID of the rank (if available) + * @var array sql_ary Array with the rank's data + * @since 3.1.0-RC3 + */ + $vars = array('rank_id', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.acp_ranks_save_modify_sql_ary', compact($vars))); + if ($rank_id) { $sql = 'UPDATE ' . RANKS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " WHERE rank_id = $rank_id"; @@ -123,6 +134,18 @@ class acp_ranks $cache->destroy('_ranks'); add_log('admin', 'LOG_RANK_REMOVED', $rank_title); + + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $user->lang['RANK_REMOVED'], + 'REFRESH_DATA' => array( + 'time' => 3 + ) + )); + } } else { @@ -140,7 +163,7 @@ class acp_ranks case 'add': $data = $ranks = $existing_imgs = array(); - + $sql = 'SELECT * FROM ' . RANKS_TABLE . ' ORDER BY rank_min ASC, rank_special ASC'; @@ -190,7 +213,7 @@ class acp_ranks $filename_list = '<option value=""' . (($edit_img == '') ? ' selected="selected"' : '') . '>----------</option>' . $filename_list; unset($existing_imgs, $imglist); - $template->assign_vars(array( + $tpl_ary = array( 'S_EDIT' => true, 'U_BACK' => $this->u_action, 'RANKS_PATH' => $phpbb_root_path . $config['ranks_path'], @@ -198,17 +221,28 @@ class acp_ranks 'RANK_TITLE' => (isset($ranks['rank_title'])) ? $ranks['rank_title'] : '', 'S_FILENAME_LIST' => $filename_list, - 'RANK_IMAGE' => ($edit_img) ? $phpbb_root_path . $config['ranks_path'] . '/' . $edit_img : $phpbb_admin_path . 'images/spacer.gif', + 'RANK_IMAGE' => ($edit_img) ? $phpbb_root_path . $config['ranks_path'] . '/' . $edit_img : htmlspecialchars($phpbb_admin_path) . 'images/spacer.gif', 'S_SPECIAL_RANK' => (isset($ranks['rank_special']) && $ranks['rank_special']) ? true : false, - 'MIN_POSTS' => (isset($ranks['rank_min']) && !$ranks['rank_special']) ? $ranks['rank_min'] : 0) + 'MIN_POSTS' => (isset($ranks['rank_min']) && !$ranks['rank_special']) ? $ranks['rank_min'] : 0, ); - + /** + * Modify the template output array for editing/adding ranks + * + * @event core.acp_ranks_edit_modify_tpl_ary + * @var array ranks Array with the rank's data + * @var array tpl_ary Array with the rank's template data + * @since 3.1.0-RC3 + */ + $vars = array('ranks', 'tpl_ary'); + extract($phpbb_dispatcher->trigger_event('core.acp_ranks_edit_modify_tpl_ary', compact($vars))); + + $template->assign_vars($tpl_ary); return; break; } - + $template->assign_vars(array( 'U_ACTION' => $this->u_action) ); @@ -220,7 +254,7 @@ class acp_ranks while ($row = $db->sql_fetchrow($result)) { - $template->assign_block_vars('ranks', array( + $rank_row = array( 'S_RANK_IMAGE' => ($row['rank_image']) ? true : false, 'S_SPECIAL_RANK' => ($row['rank_special']) ? true : false, @@ -229,12 +263,23 @@ class acp_ranks 'MIN_POSTS' => $row['rank_min'], 'U_EDIT' => $this->u_action . '&action=edit&id=' . $row['rank_id'], - 'U_DELETE' => $this->u_action . '&action=delete&id=' . $row['rank_id']) - ); + 'U_DELETE' => $this->u_action . '&action=delete&id=' . $row['rank_id'], + ); + + /** + * Modify the template output array for each listed rank + * + * @event core.acp_ranks_list_modify_rank_row + * @var array row Array with the rank's data + * @var array rank_row Array with the rank's template data + * @since 3.1.0-RC3 + */ + $vars = array('row', 'rank_row'); + extract($phpbb_dispatcher->trigger_event('core.acp_ranks_list_modify_rank_row', compact($vars))); + + $template->assign_block_vars('ranks', $rank_row); } $db->sql_freeresult($result); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_reasons.php b/phpBB/includes/acp/acp_reasons.php index dbc9fcb6cc..3d7ccf422c 100644 --- a/phpBB/includes/acp/acp_reasons.php +++ b/phpBB/includes/acp/acp_reasons.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_reasons { var $u_action; @@ -27,6 +27,7 @@ class acp_reasons { global $db, $user, $auth, $template, $cache; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $request; $user->add_lang(array('mcp', 'acp/posting')); @@ -114,7 +115,7 @@ class acp_reasons $result = $db->sql_query($sql); $max_order = (int) $db->sql_fetchfield('max_reason_order'); $db->sql_freeresult($result); - + $sql_ary = array( 'reason_title' => (string) $reason_row['reason_title'], 'reason_description' => (string) $reason_row['reason_description'], @@ -172,14 +173,14 @@ class acp_reasons 'U_ACTION' => $this->u_action . "&id=$reason_id&action=$action", 'U_BACK' => $this->u_action, 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '', - + 'REASON_TITLE' => $reason_row['reason_title'], 'REASON_DESCRIPTION' => $reason_row['reason_description'], 'TRANSLATED_TITLE' => ($translated) ? $user->lang['report_reasons']['TITLE'][strtoupper($reason_row['reason_title'])] : '', 'TRANSLATED_DESCRIPTION'=> ($translated) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason_row['reason_title'])] : '', - 'S_AVAILABLE_TITLES' => implode(', ', array_map('htmlspecialchars', array_keys($user->lang['report_reasons']['TITLE']))), + 'S_AVAILABLE_TITLES' => implode($user->lang['COMMA_SEPARATOR'], array_map('htmlspecialchars', array_keys($user->lang['report_reasons']['TITLE']))), 'S_EDIT_REASON' => true, 'S_TRANSLATED' => $translated, 'S_ERROR' => (sizeof($error)) ? true : false, @@ -218,7 +219,7 @@ class acp_reasons $other_reason_id = (int) $db->sql_fetchfield('reason_id'); $db->sql_freeresult($result); - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { // The ugly one! case 'mysqli': @@ -251,8 +252,8 @@ class acp_reasons // Teh standard case 'postgres': case 'oracle': - case 'firebird': case 'sqlite': + case 'sqlite3': // Change the reports using this reason to 'other' $sql = 'UPDATE ' . REPORTS_TABLE . ' SET reason_id = ' . $other_reason_id . ", report_text = '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' || report_text @@ -281,7 +282,18 @@ class acp_reasons case 'move_up': case 'move_down': - $order = request_var('order', 0); + $sql = 'SELECT reason_order + FROM ' . REPORTS_REASONS_TABLE . " + WHERE reason_id = $reason_id"; + $result = $db->sql_query($sql); + $order = $db->sql_fetchfield('reason_order'); + $db->sql_freeresult($result); + + if ($order === false || ($order == 0 && $action == 'move_up')) + { + break; + } + $order = (int) $order; $order_total = $order * 2 + (($action == 'move_up') ? -1 : 1); $sql = 'UPDATE ' . REPORTS_REASONS_TABLE . ' @@ -289,6 +301,13 @@ class acp_reasons WHERE reason_order IN (' . $order . ', ' . (($action == 'move_up') ? $order - 1 : $order + 1) . ')'; $db->sql_query($sql); + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'success' => (bool) $db->sql_affectedrows(), + )); + } break; } @@ -304,7 +323,7 @@ class acp_reasons do { ++$order; - + if ($row['reason_order'] != $order) { $sql = 'UPDATE ' . REPORTS_REASONS_TABLE . " @@ -364,12 +383,10 @@ class acp_reasons 'U_EDIT' => $this->u_action . '&action=edit&id=' . $row['reason_id'], 'U_DELETE' => (!$other_reason) ? $this->u_action . '&action=delete&id=' . $row['reason_id'] : '', - 'U_MOVE_UP' => $this->u_action . '&action=move_up&order=' . $row['reason_order'], - 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&order=' . $row['reason_order']) + 'U_MOVE_UP' => $this->u_action . '&action=move_up&id=' . $row['reason_id'], + 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&id=' . $row['reason_id']) ); } $db->sql_freeresult($result); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_search.php b/phpBB/includes/acp/acp_search.php index 0cd67b1c34..9ff999567a 100644 --- a/phpBB/includes/acp/acp_search.php +++ b/phpBB/includes/acp/acp_search.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_search { var $u_action; @@ -77,9 +77,11 @@ class acp_search continue; } - $name = ucfirst(strtolower(str_replace('_', ' ', $type))); + $name = $search->get_name(); + $selected = ($config['search_type'] == $type) ? ' selected="selected"' : ''; - $search_options .= '<option value="' . $type . '"' . $selected . '>' . $name . '</option>'; + $identifier = substr($type, strrpos($type, '\\') + 1); + $search_options .= "<option value=\"$type\"$selected data-toggle-setting=\"#search_{$identifier}_settings\">$name</option>"; if (method_exists($search, 'acp')) { @@ -88,9 +90,10 @@ class acp_search if (!$submit) { $template->assign_block_vars('backend', array( - 'NAME' => $name, - 'SETTINGS' => $vars['tpl']) - ); + 'NAME' => $name, + 'SETTINGS' => $vars['tpl'], + 'IDENTIFIER' => $identifier, + )); } else if (is_array($vars['config'])) { @@ -232,15 +235,7 @@ class acp_search global $db, $user, $auth, $template, $cache; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; - if (isset($_REQUEST['action']) && is_array($_REQUEST['action'])) - { - $action = request_var('action', array('' => false)); - $action = key($action); - } - else - { - $action = request_var('action', ''); - } + $action = request_var('action', ''); $this->state = explode(',', $config['search_indexing_state']); if (isset($_POST['cancel'])) @@ -283,7 +278,7 @@ class acp_search { trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING); } - $name = ucfirst(strtolower(str_replace('_', ' ', $this->state[0]))); + $name = $this->search->get_name(); $action = &$this->state[1]; @@ -345,7 +340,7 @@ class acp_search $totaltime = $mtime[0] + $mtime[1] - $starttime; $rows_per_second = $row_count / $totaltime; meta_refresh(1, append_sid($this->u_action . '&action=delete&skip_rows=' . $post_counter)); - trigger_error(sprintf($user->lang['SEARCH_INDEX_DELETE_REDIRECT'], $post_counter, $row_count, $rows_per_second)); + trigger_error($user->lang('SEARCH_INDEX_DELETE_REDIRECT', (int) $row_count, $post_counter, $rows_per_second)); } } @@ -405,9 +400,8 @@ class acp_search $i = 0; while ($row = ($buffer ? $rows[$i++] : $db->sql_fetchrow($result))) { - // Indexing enabled for this forum or global announcement? - // Global announcements get indexed by default. - if (!$row['forum_id'] || (isset($forums[$row['forum_id']]) && $forums[$row['forum_id']])) + // Indexing enabled for this forum + if (isset($forums[$row['forum_id']]) && $forums[$row['forum_id']]) { $this->search->index('post', $row['post_id'], $row['post_text'], $row['post_subject'], $row['poster_id'], $row['forum_id']); } @@ -436,7 +430,7 @@ class acp_search $totaltime = $mtime[0] + $mtime[1] - $starttime; $rows_per_second = $row_count / $totaltime; meta_refresh(1, append_sid($this->u_action . '&action=create&skip_rows=' . $post_counter)); - trigger_error(sprintf($user->lang['SEARCH_INDEX_CREATE_REDIRECT'], $post_counter, $row_count, $rows_per_second)); + trigger_error($user->lang('SEARCH_INDEX_CREATE_REDIRECT', (int) $row_count, $post_counter) . $user->lang('SEARCH_INDEX_CREATE_REDIRECT_RATE', $rows_per_second)); } } @@ -455,7 +449,6 @@ class acp_search $search = null; $error = false; - $search_options = ''; foreach ($search_types as $type) { if ($this->init_search($type, $search, $error) || !method_exists($search, 'index_created')) @@ -463,7 +456,7 @@ class acp_search continue; } - $name = ucfirst(strtolower(str_replace('_', ' ', $type))); + $name = $search->get_name(); $data = array(); if (method_exists($search, 'index_stats')) @@ -562,27 +555,15 @@ class acp_search function get_search_types() { - global $phpbb_root_path, $phpEx; - - $search_types = array(); - - $dp = @opendir($phpbb_root_path . 'includes/search'); - - if ($dp) - { - while (($file = readdir($dp)) !== false) - { - if ((preg_match('#\.' . $phpEx . '$#', $file)) && ($file != "search.$phpEx")) - { - $search_types[] = preg_replace('#^(.*?)\.' . $phpEx . '$#', '\1', $file); - } - } - closedir($dp); + global $phpbb_root_path, $phpEx, $phpbb_extension_manager; - sort($search_types); - } + $finder = $phpbb_extension_manager->get_finder(); - return $search_types; + return $finder + ->extension_suffix('_backend') + ->extension_directory('/search') + ->core_path('phpbb/search/') + ->get_classes(); } function get_max_post_id() @@ -617,27 +598,17 @@ class acp_search */ function init_search($type, &$search, &$error) { - global $phpbb_root_path, $phpEx, $user; + global $phpbb_root_path, $phpEx, $user, $auth, $config, $db; - if (!preg_match('#^\w+$#', $type) || !file_exists("{$phpbb_root_path}includes/search/$type.$phpEx")) - { - $error = $user->lang['NO_SUCH_SEARCH_MODULE']; - return $error; - } - - include_once("{$phpbb_root_path}includes/search/$type.$phpEx"); - - if (!class_exists($type)) + if (!class_exists($type) || !method_exists($type, 'keyword_search')) { $error = $user->lang['NO_SUCH_SEARCH_MODULE']; return $error; } $error = false; - $search = new $type($error); + $search = new $type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user); return $error; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_send_statistics.php b/phpBB/includes/acp/acp_send_statistics.php index b8fc2d2c45..d178be2fb0 100644 --- a/phpBB/includes/acp/acp_send_statistics.php +++ b/phpBB/includes/acp/acp_send_statistics.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,18 +19,15 @@ if (!defined('IN_PHPBB')) exit; } -include($phpbb_root_path . 'includes/questionnaire/questionnaire.' . $phpEx); - -/** -* @package acp -*/ class acp_send_statistics { var $u_action; function main($id, $mode) { - global $config, $template, $phpbb_admin_path, $phpEx; + global $config, $template, $phpbb_admin_path, $phpbb_root_path, $phpEx; + + include($phpbb_root_path . 'includes/questionnaire/questionnaire.' . $phpEx); $collect_url = "https://www.phpbb.com/stats/receive_stats.php"; @@ -86,5 +86,3 @@ class acp_send_statistics } } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index 47cd02bca7..6bd27a8bca 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,3961 +19,1316 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_styles { - var $u_action; - - var $style_cfg; - var $template_cfg; - var $theme_cfg; - var $imageset_cfg; - var $imageset_keys; - - function main($id, $mode) - { - global $db, $user, $auth, $template, $cache; - global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; - - // Hardcoded template bitfield to add for new templates - $bitfield = new bitfield(); - $bitfield->set(0); - $bitfield->set(1); - $bitfield->set(2); - $bitfield->set(3); - $bitfield->set(4); - $bitfield->set(8); - $bitfield->set(9); - $bitfield->set(11); - $bitfield->set(12); - define('TEMPLATE_BITFIELD', $bitfield->get_base64()); - unset($bitfield); + public $u_action; - $user->add_lang('acp/styles'); + protected $u_base_action; + protected $s_hidden_fields; + protected $mode; + protected $styles_path; + protected $styles_path_absolute = 'styles'; + protected $default_style = 0; + protected $styles_list_cols = 0; + protected $reserved_style_names = array('adm', 'admin', 'all'); - $this->tpl_name = 'acp_styles'; - $this->page_title = 'ACP_CAT_STYLES'; + /** @var \phpbb\db\driver\driver_interface */ + protected $db; - $action = request_var('action', ''); - $action = (isset($_POST['add'])) ? 'add' : $action; - $style_id = request_var('id', 0); - - // Fill the configuration variables - $this->style_cfg = $this->template_cfg = $this->theme_cfg = $this->imageset_cfg = ' -# -# phpBB {MODE} configuration file -# -# @package phpBB3 -# @copyright (c) 2005 phpBB Group -# @license http://opensource.org/licenses/gpl-license.php GNU Public License -# -# -# At the left is the name, please do not change this -# At the right the value is entered -# For on/off options the valid values are on, off, 1, 0, true and false -# -# 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 {MODE} -name = {NAME} -copyright = {COPYRIGHT} -version = {VERSION} -'; - - $this->theme_cfg .= ' -# Some configuration options - -# -# You have to turn this option on if you want to use the -# path template variables ({T_IMAGESET_PATH} for example) within -# your css file. -# This is mostly the case if you want to use language specific -# images within your css file. -# -parse_css_file = {PARSE_CSS_FILE} -'; - - $this->template_cfg .= ' -# Some configuration options - -# Template inheritance -# See http://blog.phpbb.com/2008/07/31/templating-just-got-easier/ -# Set value to empty or this template name to ignore template inheritance. -inherit_from = {INHERIT_FROM} -'; - - $this->imageset_keys = array( - 'logos' => array( - 'site_logo', - ), - 'buttons' => array( - 'icon_back_top', 'icon_contact_aim', 'icon_contact_email', 'icon_contact_icq', 'icon_contact_jabber', 'icon_contact_msnm', 'icon_contact_pm', 'icon_contact_yahoo', 'icon_contact_www', 'icon_post_delete', 'icon_post_edit', 'icon_post_info', 'icon_post_quote', 'icon_post_report', 'icon_user_online', 'icon_user_offline', 'icon_user_profile', 'icon_user_search', 'icon_user_warn', 'button_pm_forward', 'button_pm_new', 'button_pm_reply', 'button_topic_locked', 'button_topic_new', 'button_topic_reply', - ), - 'icons' => array( - 'icon_post_target', 'icon_post_target_unread', 'icon_topic_attach', 'icon_topic_latest', 'icon_topic_newest', 'icon_topic_reported', 'icon_topic_unapproved', 'icon_friend', 'icon_foe', - ), - 'forums' => array( - 'forum_link', 'forum_read', 'forum_read_locked', 'forum_read_subforum', 'forum_unread', 'forum_unread_locked', 'forum_unread_subforum', 'subforum_read', 'subforum_unread' - ), - 'folders' => array( - 'topic_moved', 'topic_read', 'topic_read_mine', 'topic_read_hot', 'topic_read_hot_mine', 'topic_read_locked', 'topic_read_locked_mine', 'topic_unread', 'topic_unread_mine', 'topic_unread_hot', 'topic_unread_hot_mine', 'topic_unread_locked', 'topic_unread_locked_mine', 'sticky_read', 'sticky_read_mine', 'sticky_read_locked', 'sticky_read_locked_mine', 'sticky_unread', 'sticky_unread_mine', 'sticky_unread_locked', 'sticky_unread_locked_mine', 'announce_read', 'announce_read_mine', 'announce_read_locked', 'announce_read_locked_mine', 'announce_unread', 'announce_unread_mine', 'announce_unread_locked', 'announce_unread_locked_mine', 'global_read', 'global_read_mine', 'global_read_locked', 'global_read_locked_mine', 'global_unread', 'global_unread_mine', 'global_unread_locked', 'global_unread_locked_mine', 'pm_read', 'pm_unread', - ), - 'polls' => array( - 'poll_left', 'poll_center', 'poll_right', - ), - 'ui' => array( - 'upload_bar', - ), - 'user' => array( - 'user_icon1', 'user_icon2', 'user_icon3', 'user_icon4', 'user_icon5', 'user_icon6', 'user_icon7', 'user_icon8', 'user_icon9', 'user_icon10', - ), - ); + /** @var \phpbb\user */ + protected $user; - // Execute overall actions - switch ($action) - { - case 'delete': - if ($style_id) - { - $this->remove($mode, $style_id); - return; - } - break; + /** @var \phpbb\template\template */ + protected $template; - case 'export': - if ($style_id) - { - $this->export($mode, $style_id); - return; - } - break; + /** @var \phpbb\request\request_interface */ + protected $request; - case 'install': - $this->install($mode); - return; - break; + /** @var \phpbb\cache\driver\driver_interface */ + protected $cache; - case 'add': - $this->add($mode); - return; - break; + /** @var \phpbb\auth\auth */ + protected $auth; - case 'details': - if ($style_id) - { - $this->details($mode, $style_id); - return; - } - break; + /** @var string */ + protected $phpbb_root_path; - case 'edit': - if ($style_id) - { - switch ($mode) - { - case 'imageset': - return $this->edit_imageset($style_id); - case 'template': - return $this->edit_template($style_id); - case 'theme': - return $this->edit_theme($style_id); - } - } - break; + /** @var string */ + protected $php_ext; - case 'cache': - if ($style_id) - { - switch ($mode) - { - case 'template': - return $this->template_cache($style_id); - } - } - break; - } - - switch ($mode) - { - case 'style': - - switch ($action) - { - case 'activate': - case 'deactivate': - - if ($style_id == $config['default_style']) - { - trigger_error($user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (($action == 'deactivate' && confirm_box(true)) || $action == 'activate') - { - $sql = 'UPDATE ' . STYLES_TABLE . ' - SET style_active = ' . (($action == 'activate') ? 1 : 0) . ' - WHERE style_id = ' . $style_id; - $db->sql_query($sql); - - // Set style to default for any member using deactivated style - if ($action == 'deactivate') - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_style = ' . $config['default_style'] . " - WHERE user_style = $style_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_style = 0 - WHERE forum_style = ' . $style_id; - $db->sql_query($sql); - } - } - else if ($action == 'deactivate') - { - $s_hidden_fields = array( - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'style_id' => $style_id, - ); - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); - } - break; - } - - $this->frontend('style', array('details'), array('export', 'delete')); - break; - - case 'template': - - switch ($action) - { - // Refresh template data stored in db and clear cache - case 'refresh': - - $sql = 'SELECT * - FROM ' . STYLES_TEMPLATE_TABLE . " - WHERE template_id = $style_id"; - $result = $db->sql_query($sql); - $template_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$template_row) - { - trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (confirm_box(true)) - { - $template_refreshed = ''; - - // Only refresh database if the template is stored in the database - if ($template_row['template_storedb'] && file_exists("{$phpbb_root_path}styles/{$template_row['template_path']}/template/")) - { - $filelist = array('' => array()); - - $sql = 'SELECT template_filename, template_mtime - FROM ' . STYLES_TEMPLATE_DATA_TABLE . " - WHERE template_id = $style_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { -// if (@filemtime("{$phpbb_root_path}styles/{$template_row['template_path']}/template/" . $row['template_filename']) > $row['template_mtime']) -// { - // get folder info from the filename - if (($slash_pos = strrpos($row['template_filename'], '/')) === false) - { - $filelist[''][] = $row['template_filename']; - } - else - { - $filelist[substr($row['template_filename'], 0, $slash_pos + 1)][] = substr($row['template_filename'], $slash_pos + 1, strlen($row['template_filename']) - $slash_pos - 1); - } -// } - } - $db->sql_freeresult($result); - - $this->store_templates('update', $style_id, $template_row['template_path'], $filelist); - unset($filelist); - - $template_refreshed = $user->lang['TEMPLATE_REFRESHED'] . '<br />'; - add_log('admin', 'LOG_TEMPLATE_REFRESHED', $template_row['template_name']); - } - - $this->clear_template_cache($template_row); - - trigger_error($template_refreshed . $user->lang['TEMPLATE_CACHE_CLEARED'] . adm_back_link($this->u_action)); - } - else - { - confirm_box(false, ($template_row['template_storedb']) ? $user->lang['CONFIRM_TEMPLATE_REFRESH'] : $user->lang['CONFIRM_TEMPLATE_CLEAR_CACHE'], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'id' => $style_id - ))); - } - - break; - } - - $this->frontend('template', array('edit', 'cache', 'details'), array('refresh', 'export', 'delete')); - break; - - case 'theme': - - switch ($action) - { - // Refresh theme data stored in the database - case 'refresh': - - $sql = 'SELECT * - FROM ' . STYLES_THEME_TABLE . " - WHERE theme_id = $style_id"; - $result = $db->sql_query($sql); - $theme_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$theme_row) - { - trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (!$theme_row['theme_storedb']) - { - trigger_error($user->lang['THEME_ERR_REFRESH_FS'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (confirm_box(true)) - { - if ($theme_row['theme_storedb'] && file_exists("{$phpbb_root_path}styles/{$theme_row['theme_path']}/theme/stylesheet.css")) - { - // Save CSS contents - $sql_ary = array( - 'theme_mtime' => (int) filemtime("{$phpbb_root_path}styles/{$theme_row['theme_path']}/theme/stylesheet.css"), - 'theme_data' => $this->db_theme_data($theme_row) - ); - - $sql = 'UPDATE ' . STYLES_THEME_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE theme_id = $style_id"; - $db->sql_query($sql); - - $cache->destroy('sql', STYLES_THEME_TABLE); - - add_log('admin', 'LOG_THEME_REFRESHED', $theme_row['theme_name']); - trigger_error($user->lang['THEME_REFRESHED'] . adm_back_link($this->u_action)); - } - } - else - { - confirm_box(false, $user->lang['CONFIRM_THEME_REFRESH'], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'id' => $style_id - ))); - } - break; - } - - $this->frontend('theme', array('edit', 'details'), array('refresh', 'export', 'delete')); - break; - - case 'imageset': - - switch ($action) - { - case 'refresh': - - $sql = 'SELECT * - FROM ' . STYLES_IMAGESET_TABLE . " - WHERE imageset_id = $style_id"; - $result = $db->sql_query($sql); - $imageset_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$imageset_row) - { - trigger_error($user->lang['NO_IMAGESET'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if (confirm_box(true)) - { - $sql_ary = array(); - - $imageset_definitions = array(); - foreach ($this->imageset_keys as $topic => $key_array) - { - $imageset_definitions = array_merge($imageset_definitions, $key_array); - } - - $cfg_data_imageset = parse_cfg_file("{$phpbb_root_path}styles/{$imageset_row['imageset_path']}/imageset/imageset.cfg"); - - $db->sql_transaction('begin'); - - $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . ' - WHERE imageset_id = ' . $style_id; - $result = $db->sql_query($sql); - - foreach ($cfg_data_imageset as $image_name => $value) - { - if (strpos($value, '*') !== false) - { - if (substr($value, -1, 1) === '*') - { - list($image_filename, $image_height) = explode('*', $value); - $image_width = 0; - } - else - { - list($image_filename, $image_height, $image_width) = explode('*', $value); - } - } - else - { - $image_filename = $value; - $image_height = $image_width = 0; - } - - if (strpos($image_name, 'img_') === 0 && $image_filename) - { - $image_name = substr($image_name, 4); - if (in_array($image_name, $imageset_definitions)) - { - $sql_ary[] = array( - 'image_name' => (string) $image_name, - 'image_filename' => (string) $image_filename, - 'image_height' => (int) $image_height, - 'image_width' => (int) $image_width, - 'imageset_id' => (int) $style_id, - 'image_lang' => '', - ); - } - } - } - - $sql = 'SELECT lang_dir - FROM ' . LANG_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (@file_exists("{$phpbb_root_path}styles/{$imageset_row['imageset_path']}/imageset/{$row['lang_dir']}/imageset.cfg")) - { - $cfg_data_imageset_data = parse_cfg_file("{$phpbb_root_path}styles/{$imageset_row['imageset_path']}/imageset/{$row['lang_dir']}/imageset.cfg"); - foreach ($cfg_data_imageset_data as $image_name => $value) - { - if (strpos($value, '*') !== false) - { - if (substr($value, -1, 1) === '*') - { - list($image_filename, $image_height) = explode('*', $value); - $image_width = 0; - } - else - { - list($image_filename, $image_height, $image_width) = explode('*', $value); - } - } - else - { - $image_filename = $value; - $image_height = $image_width = 0; - } - - if (strpos($image_name, 'img_') === 0 && $image_filename) - { - $image_name = substr($image_name, 4); - if (in_array($image_name, $imageset_definitions)) - { - $sql_ary[] = array( - 'image_name' => (string) $image_name, - 'image_filename' => (string) $image_filename, - 'image_height' => (int) $image_height, - 'image_width' => (int) $image_width, - 'imageset_id' => (int) $style_id, - 'image_lang' => (string) $row['lang_dir'], - ); - } - } - } - } - } - $db->sql_freeresult($result); - - $db->sql_multi_insert(STYLES_IMAGESET_DATA_TABLE, $sql_ary); - - $db->sql_transaction('commit'); - - $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); - $cache->destroy('imageset_site_logo_md5'); - - add_log('admin', 'LOG_IMAGESET_REFRESHED', $imageset_row['imageset_name']); - trigger_error($user->lang['IMAGESET_REFRESHED'] . adm_back_link($this->u_action)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_IMAGESET_REFRESH'], build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'action' => $action, - 'id' => $style_id - ))); - } - break; - } - - $this->frontend('imageset', array('edit', 'details'), array('refresh', 'export', 'delete')); - break; - } - } - - /** - * Build Frontend with supplied options - */ - function frontend($mode, $options, $actions) + public function main($id, $mode) { - global $user, $template, $db, $config, $phpbb_root_path, $phpEx; - - $sql_from = ''; - $sql_sort = 'LOWER(' . $mode . '_name)'; - $style_count = array(); - - switch ($mode) - { - case 'style': - $sql_from = STYLES_TABLE; - $sql_sort = 'style_active DESC, ' . $sql_sort; - - $sql = 'SELECT user_style, COUNT(user_style) AS style_count - FROM ' . USERS_TABLE . ' - GROUP BY user_style'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $style_count[$row['user_style']] = $row['style_count']; - } - $db->sql_freeresult($result); - - break; - - case 'template': - $sql_from = STYLES_TEMPLATE_TABLE; - break; - - case 'theme': - $sql_from = STYLES_THEME_TABLE; - break; - - case 'imageset': - $sql_from = STYLES_IMAGESET_TABLE; - break; - - default: - trigger_error($user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $l_prefix = strtoupper($mode); - - $this->page_title = 'ACP_' . $l_prefix . 'S'; - - $template->assign_vars(array( - 'S_FRONTEND' => true, - 'S_STYLE' => ($mode == 'style') ? true : false, - - 'L_TITLE' => $user->lang[$this->page_title], - 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'], - 'L_NAME' => $user->lang[$l_prefix . '_NAME'], - 'L_INSTALLED' => $user->lang['INSTALLED_' . $l_prefix], - 'L_UNINSTALLED' => $user->lang['UNINSTALLED_' . $l_prefix], - 'L_NO_UNINSTALLED' => $user->lang['NO_UNINSTALLED_' . $l_prefix], - 'L_CREATE' => $user->lang['CREATE_' . $l_prefix], - - 'U_ACTION' => $this->u_action, - ) + global $db, $user, $phpbb_admin_path, $phpbb_root_path, $phpEx, $template, $request, $cache, $auth, $config; + + $this->db = $db; + $this->user = $user; + $this->template = $template; + $this->request = $request; + $this->cache = $cache; + $this->auth = $auth; + $this->config = $config; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $phpEx; + + $this->default_style = $config['default_style']; + $this->styles_path = $this->phpbb_root_path . $this->styles_path_absolute . '/'; + + $this->u_base_action = append_sid("{$phpbb_admin_path}index.{$this->php_ext}", "i={$id}"); + $this->s_hidden_fields = array( + 'mode' => $mode, ); - $sql = "SELECT * - FROM $sql_from - ORDER BY $sql_sort ASC"; - $result = $db->sql_query($sql); - - $installed = array(); - - $basis_options = '<option class="sep" value="">' . $user->lang['OPTIONAL_BASIS'] . '</option>'; - while ($row = $db->sql_fetchrow($result)) - { - $installed[] = $row[$mode . '_name']; - $basis_options .= '<option value="' . $row[$mode . '_id'] . '">' . $row[$mode . '_name'] . '</option>'; + $this->user->add_lang('acp/styles'); - $stylevis = ($mode == 'style' && !$row['style_active']) ? 'activate' : 'deactivate'; + $this->tpl_name = 'acp_styles'; + $this->page_title = 'ACP_CAT_STYLES'; + $this->mode = $mode; - $s_options = array(); - foreach ($options as $option) - { - $s_options[] = '<a href="' . $this->u_action . "&action=$option&id=" . $row[$mode . '_id'] . '">' . $user->lang[strtoupper($option)] . '</a>'; - } + $action = $this->request->variable('action', ''); + $post_actions = array('install', 'activate', 'deactivate', 'uninstall'); - $s_actions = array(); - foreach ($actions as $option) + foreach ($post_actions as $key) + { + if ($this->request->is_set_post($key)) { - $s_actions[] = '<a href="' . $this->u_action . "&action=$option&id=" . $row[$mode . '_id'] . '">' . $user->lang[strtoupper($option)] . '</a>'; + $action = $key; } - - $template->assign_block_vars('installed', array( - 'S_DEFAULT_STYLE' => ($mode == 'style' && $row['style_id'] == $config['default_style']) ? true : false, - 'U_EDIT' => $this->u_action . '&action=' . (($mode == 'style') ? 'details' : 'edit') . '&id=' . $row[$mode . '_id'], - 'U_STYLE_ACT_DEACT' => $this->u_action . '&action=' . $stylevis . '&id=' . $row[$mode . '_id'], - 'L_STYLE_ACT_DEACT' => $user->lang['STYLE_' . strtoupper($stylevis)], - 'S_OPTIONS' => implode(' | ', $s_options), - 'S_ACTIONS' => implode(' | ', $s_actions), - 'U_PREVIEW' => ($mode == 'style') ? append_sid("{$phpbb_root_path}index.$phpEx", "$mode=" . $row[$mode . '_id']) : '', - - 'NAME' => $row[$mode . '_name'], - 'STYLE_COUNT' => ($mode == 'style' && isset($style_count[$row['style_id']])) ? $style_count[$row['style_id']] : 0, - - 'S_INACTIVE' => ($mode == 'style' && !$row['style_active']) ? true : false, - ) - ); } - $db->sql_freeresult($result); - // Grab uninstalled items - $new_ary = $cfg = array(); - - $dp = @opendir("{$phpbb_root_path}styles"); - - if ($dp) + // The uninstall action uses confirm_box() to verify the validity of the request, + // so there is no need to check for a valid token here. + if (in_array($action, $post_actions) && $action != 'uninstall') { - while (($file = readdir($dp)) !== false) - { - if ($file[0] == '.' || !is_dir($phpbb_root_path . 'styles/' . $file)) - { - continue; - } + $is_valid_request = check_link_hash($request->variable('hash', ''), $action) || check_form_key('styles_management'); - $subpath = ($mode != 'style') ? "$mode/" : ''; - if (file_exists("{$phpbb_root_path}styles/$file/$subpath$mode.cfg")) - { - if ($cfg = file("{$phpbb_root_path}styles/$file/$subpath$mode.cfg")) - { - $items = parse_cfg_file('', $cfg); - $name = (isset($items['name'])) ? trim($items['name']) : false; - - if ($name && !in_array($name, $installed)) - { - // The array key is used for sorting later on. - // $file is appended because $name doesn't have to be unique. - $new_ary[$name . $file] = array( - 'path' => $file, - 'name' => $name, - 'copyright' => $items['copyright'], - ); - } - } - } + if (!$is_valid_request) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); } - closedir($dp); } - unset($installed); - - if (sizeof($new_ary)) + if ($action != '') { - ksort($new_ary); - - foreach ($new_ary as $cfg) - { - $template->assign_block_vars('uninstalled', array( - 'NAME' => $cfg['name'], - 'COPYRIGHT' => $cfg['copyright'], - 'U_INSTALL' => $this->u_action . '&action=install&path=' . urlencode($cfg['path'])) - ); - } + $this->s_hidden_fields['action'] = $action; } - unset($new_ary); - $template->assign_vars(array( - 'S_BASIS_OPTIONS' => $basis_options) + $this->template->assign_vars(array( + 'U_ACTION' => $this->u_base_action, + 'S_HIDDEN_FIELDS' => build_hidden_fields($this->s_hidden_fields) + ) ); + // Execute actions + switch ($action) + { + case 'install': + $this->action_install(); + return; + case 'uninstall': + $this->action_uninstall(); + return; + case 'activate': + $this->action_activate(); + return; + case 'deactivate': + $this->action_deactivate(); + return; + case 'details': + $this->action_details(); + return; + default: + $this->frontend(); + } } /** - * Provides a template editor which allows saving changes to template files on the filesystem or in the database. - * - * @param int $template_id specifies which template set is being edited + * Main page */ - function edit_template($template_id) + protected function frontend() { - global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template, $safe_mode; + add_form_key('styles_management'); - if (defined('PHPBB_DISABLE_ACP_EDITOR')) + // Check mode + switch ($this->mode) { - trigger_error($user->lang['EDITOR_DISABLED'] . adm_back_link($this->u_action)); + case 'style': + $this->welcome_message('ACP_STYLES', 'ACP_STYLES_EXPLAIN'); + $this->show_installed(); + return; + case 'install': + $this->welcome_message('INSTALL_STYLES', 'INSTALL_STYLES_EXPLAIN'); + $this->show_available(); + return; } + trigger_error($this->user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING); + } - $this->page_title = 'EDIT_TEMPLATE'; - - $filelist = $filelist_cats = array(); - - $template_data = utf8_normalize_nfc(request_var('template_data', '', true)); - $template_data = htmlspecialchars_decode($template_data); - $template_file = utf8_normalize_nfc(request_var('template_file', '', true)); - $text_rows = max(5, min(999, request_var('text_rows', 20))); - $save_changes = (isset($_POST['save'])) ? true : false; - - // make sure template_file path doesn't go upwards - $template_file = preg_replace('#\.{2,}#', '.', $template_file); - - // Retrieve some information about the template - $sql = 'SELECT template_storedb, template_path, template_name - FROM ' . STYLES_TEMPLATE_TABLE . " - WHERE template_id = $template_id"; - $result = $db->sql_query($sql); - $template_info = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$template_info) - { - trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); - } + /** + * Install style(s) + */ + protected function action_install() + { + // Get list of styles to install + $dirs = $this->request_vars('dir', '', true); - if ($save_changes && !check_form_key('acp_styles')) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); - } - else if (!$save_changes) - { - add_form_key('acp_styles'); - } + // Get list of styles that can be installed + $styles = $this->find_available(false); - // save changes to the template if the user submitted any - if ($save_changes && $template_file) + // Install each style + $messages = array(); + $installed_names = array(); + $installed_dirs = array(); + $last_installed = false; + foreach ($dirs as $dir) { - // Get the filesystem location of the current file - $file = "{$phpbb_root_path}styles/{$template_info['template_path']}/template/$template_file"; - $additional = ''; - - // If the template is stored on the filesystem try to write the file else store it in the database - if (!$safe_mode && !$template_info['template_storedb'] && file_exists($file) && phpbb_is_writable($file)) - { - if (!($fp = @fopen($file, 'wb'))) - { - // File exists and is writeable, but still not able to be written to - trigger_error(sprintf($user->lang['TEMPLATE_FILE_NOT_WRITABLE'], htmlspecialchars($template_file)) . adm_back_link($this->u_action), E_USER_WARNING); - } - fwrite($fp, $template_data); - fclose($fp); - } - else + if (in_array($dir, $this->reserved_style_names)) { - $db->sql_transaction('begin'); - - // If it's not stored in the db yet, then update the template setting and store all template files in the db - if (!$template_info['template_storedb']) - { - if ($super = $this->get_super('template', $template_id)) - { - $this->store_in_db('template', $super['template_id']); - } - else - { - $this->store_in_db('template', $template_id); - } - - add_log('admin', 'LOG_TEMPLATE_EDIT_DETAILS', $template_info['template_name']); - $additional .= '<br />' . $user->lang['EDIT_TEMPLATE_STORED_DB']; - } - - // Update the template_data table entry for this template file - $sql = 'UPDATE ' . STYLES_TEMPLATE_DATA_TABLE . " - SET template_data = '" . $db->sql_escape($template_data) . "', template_mtime = " . time() . " - WHERE template_id = $template_id - AND template_filename = '" . $db->sql_escape($template_file) . "'"; - $db->sql_query($sql); - - $db->sql_transaction('commit'); + $messages[] = $this->user->lang('STYLE_NAME_RESERVED', htmlspecialchars($dir)); + continue; } - // destroy the cached version of the template (filename without extension) - $this->clear_template_cache($template_info, array(substr($template_file, 0, -5))); - - $cache->destroy('sql', STYLES_TABLE); - - add_log('admin', 'LOG_TEMPLATE_EDIT', $template_info['template_name'], $template_file); - trigger_error($user->lang['TEMPLATE_FILE_UPDATED'] . $additional . adm_back_link($this->u_action . "&action=edit&id=$template_id&text_rows=$text_rows&template_file=$template_file")); - } - - // Generate a category array containing template filenames - if (!$template_info['template_storedb']) - { - $template_path = "{$phpbb_root_path}styles/{$template_info['template_path']}/template"; - - $filelist = filelist($template_path, '', 'html'); - $filelist[''] = array_diff($filelist[''], array('bbcode.html')); - - if ($template_file) + $found = false; + foreach ($styles as &$style) { - if (!file_exists($template_path . "/$template_file") || !($template_data = file_get_contents($template_path . "/$template_file"))) + // Check if: + // 1. Directory matches directory we are looking for + // 2. Style is not installed yet + // 3. Style with same name or directory hasn't been installed already within this function + if ($style['style_path'] == $dir && empty($style['_installed']) && !in_array($style['style_path'], $installed_dirs) && !in_array($style['style_name'], $installed_names)) { - trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); + // Install style + $style['style_active'] = 1; + $style['style_id'] = $this->install_style($style); + $style['_installed'] = true; + $found = true; + $last_installed = $style['style_id']; + $installed_names[] = $style['style_name']; + $installed_dirs[] = $style['style_path']; + $messages[] = sprintf($this->user->lang['STYLE_INSTALLED'], htmlspecialchars($style['style_name'])); } } - } - else - { - $sql = 'SELECT * - FROM ' . STYLES_TEMPLATE_DATA_TABLE . " - WHERE template_id = $template_id"; - $result = $db->sql_query($sql); - - $filelist = array('' => array()); - while ($row = $db->sql_fetchrow($result)) + if (!$found) { - $file_info = pathinfo($row['template_filename']); - - if (($file_info['basename'] != 'bbcode') && ($file_info['extension'] == 'html')) - { - if (($file_info['dirname'] == '.') || empty($file_info['dirname'])) - { - $filelist[''][] = $row['template_filename']; - } - else - { - $filelist[$file_info['dirname'] . '/'][] = $file_info['basename']; - } - } - - if ($row['template_filename'] == $template_file) - { - $template_data = $row['template_data']; - } + $messages[] = sprintf($this->user->lang['STYLE_NOT_INSTALLED'], htmlspecialchars($dir)); } - $db->sql_freeresult($result); - unset($file_info); } - if (empty($filelist[''])) + // Show message + if (!count($messages)) { - trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); + trigger_error($this->user->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 . '&mode=style' . '">« ' . $this->user->lang('STYLE_INSTALLED_RETURN_INSTALLED_STYLES') . '</a>'; + $message .= '<br /><br /><a href="' . $this->u_base_action . '&mode=install' . '">» ' . $this->user->lang('STYLE_INSTALLED_RETURN_UNINSTALLED_STYLES') . '</a>'; + trigger_error($message, E_USER_NOTICE); + } - // Now create the categories - $filelist_cats[''] = array(); - foreach ($filelist as $pathfile => $file_ary) - { - // Use the directory name as category name - if (!empty($pathfile)) - { - $filelist_cats[$pathfile] = array(); - foreach ($file_ary as $file) - { - $filelist_cats[$pathfile][$pathfile . $file] = $file; - } - } - // or if it's in the main category use the word before the first underscore to group files - else - { - $cats = array(); - foreach ($file_ary as $file) - { - $cats[] = substr($file, 0, strpos($file, '_')); - $filelist_cats[substr($file, 0, strpos($file, '_'))][$file] = $file; - } - - $cats = array_values(array_unique($cats)); - - // we don't need any single element categories so put them into the misc '' category - for ($i = 0, $n = sizeof($cats); $i < $n; $i++) - { - if (sizeof($filelist_cats[$cats[$i]]) == 1 && $cats[$i] !== '') - { - $filelist_cats[''][key($filelist_cats[$cats[$i]])] = current($filelist_cats[$cats[$i]]); - unset($filelist_cats[$cats[$i]]); - } - } - unset($cats); - } - } - unset($filelist); + /** + * Confirm styles removal + */ + protected function action_uninstall() + { + // Get list of styles to uninstall + $ids = $this->request_vars('id', 0, true); - // Generate list of categorised template files - $tpl_options = ''; - ksort($filelist_cats); - foreach ($filelist_cats as $category => $tpl_ary) + // Check if confirmation box was submitted + if (confirm_box(true)) { - ksort($tpl_ary); - - if (!empty($category)) - { - $tpl_options .= '<option class="sep" value="">' . $category . '</option>'; - } - - foreach ($tpl_ary as $filename => $file) - { - $selected = ($template_file == $filename) ? ' selected="selected"' : ''; - $tpl_options .= '<option value="' . $filename . '"' . $selected . '>' . $file . '</option>'; - } + // Uninstall + $this->action_uninstall_confirmed($ids, $this->request->variable('confirm_delete_files', false)); + return; } - $template->assign_vars(array( - 'S_EDIT_TEMPLATE' => true, - 'S_HIDDEN_FIELDS' => build_hidden_fields(array('template_file' => $template_file)), - 'S_TEMPLATES' => $tpl_options, - - 'U_ACTION' => $this->u_action . "&action=edit&id=$template_id&text_rows=$text_rows", - 'U_BACK' => $this->u_action, - - 'L_EDIT' => $user->lang['EDIT_TEMPLATE'], - 'L_EDIT_EXPLAIN' => $user->lang['EDIT_TEMPLATE_EXPLAIN'], - 'L_EDITOR' => $user->lang['TEMPLATE_EDITOR'], - 'L_EDITOR_HEIGHT' => $user->lang['TEMPLATE_EDITOR_HEIGHT'], - 'L_FILE' => $user->lang['TEMPLATE_FILE'], - 'L_SELECT' => $user->lang['SELECT_TEMPLATE'], - 'L_SELECTED' => $user->lang['SELECTED_TEMPLATE'], - 'L_SELECTED_FILE' => $user->lang['SELECTED_TEMPLATE_FILE'], - - 'SELECTED_TEMPLATE' => $template_info['template_name'], - 'TEMPLATE_FILE' => $template_file, - 'TEMPLATE_DATA' => utf8_htmlspecialchars($template_data), - 'TEXT_ROWS' => $text_rows) - ); + // Confirm box + $s_hidden = build_hidden_fields(array( + 'action' => 'uninstall', + 'ids' => $ids + )); + $this->template->assign_var('S_CONFIRM_DELETE', true); + confirm_box(false, $this->user->lang['CONFIRM_UNINSTALL_STYLES'], $s_hidden, 'acp_styles.html'); + + // Canceled - show styles list + $this->frontend(); } /** - * Allows the admin to view cached versions of template files and clear single template cache files + * Uninstall styles(s) * - * @param int $template_id specifies which template's cache is shown + * @param array $ids List of style IDs + * @param bool $delete_files If true, script will attempt to remove files for selected styles */ - function template_cache($template_id) + protected function action_uninstall_confirmed($ids, $delete_files) { - global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template; - - $source = str_replace('/', '.', request_var('source', '')); - $file_ary = array_diff(request_var('delete', array('')), array('')); - $submit = isset($_POST['submit']) ? true : false; - - $sql = 'SELECT * - FROM ' . STYLES_TEMPLATE_TABLE . " - WHERE template_id = $template_id"; - $result = $db->sql_query($sql); - $template_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$template_row) - { - trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - // User wants to delete one or more files ... - if ($submit && $file_ary) - { - $this->clear_template_cache($template_row, $file_ary); - trigger_error($user->lang['TEMPLATE_CACHE_CLEARED'] . adm_back_link($this->u_action . "&action=cache&id=$template_id")); - } + $default = $this->default_style; + $uninstalled = array(); + $messages = array(); - $cache_prefix = 'tpl_' . str_replace('_', '-', $template_row['template_path']); - - // Someone wants to see the cached source ... so we'll highlight it, - // add line numbers and indent it appropriately. This could be nasty - // on larger source files ... - if ($source && file_exists("{$phpbb_root_path}cache/{$cache_prefix}_$source.html.$phpEx")) + // Check styles list + foreach ($ids as $id) { - adm_page_header($user->lang['TEMPLATE_CACHE']); - - $template->set_filenames(array( - 'body' => 'viewsource.html') - ); - - $template->assign_vars(array( - 'FILENAME' => str_replace('.', '/', $source) . '.html') - ); - - $code = str_replace(array("\r\n", "\r"), array("\n", "\n"), file_get_contents("{$phpbb_root_path}cache/{$cache_prefix}_$source.html.$phpEx")); - - $conf = array('highlight.bg', 'highlight.comment', 'highlight.default', 'highlight.html', 'highlight.keyword', 'highlight.string'); - foreach ($conf as $ini_var) + if (!$id) { - @ini_set($ini_var, str_replace('highlight.', 'syntax', $ini_var)); + trigger_error($this->user->lang['INVALID_STYLE_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } - - $marker = 'MARKER' . time(); - $code = highlight_string(str_replace("\n", $marker, $code), true); - $code = str_replace($marker, "\n", $code); - $str_from = array('<span style="color: ', '<font color="syntax', '</font>', '<code>', '</code>','[', ']', '.', ':'); - $str_to = array('<span class="', '<span class="syntax', '</span>', '', '', '[', ']', '.', ':'); - - $code = str_replace($str_from, $str_to, $code); - $code = preg_replace('#^(<span class="[a-z_]+">)\n?(.*?)\n?(</span>)$#ism', '$1$2$3', $code); - $code = substr($code, strlen('<span class="syntaxhtml">')); - $code = substr($code, 0, -1 * strlen('</ span>')); - $code = explode("\n", $code); - - foreach ($code as $key => $line) + if ($id == $default) { - $template->assign_block_vars('source', array( - 'LINENUM' => $key + 1, - 'LINE' => preg_replace('#([^ ;]) ([^ &])#', '$1 $2', $line)) - ); - unset($code[$key]); + trigger_error($this->user->lang['UNINSTALL_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); } - - adm_page_footer(); + $uninstalled[$id] = false; } - $filemtime = array(); - if ($template_row['template_storedb']) - { - $ids = array(); - if (isset($template_row['template_inherits_id']) && $template_row['template_inherits_id']) - { - $ids[] = $template_row['template_inherits_id']; - } - $ids[] = $template_row['template_id']; - - $filemtime = array(); - $file_template_db = array(); - - foreach ($ids as $id) - { - $sql = 'SELECT template_filename, template_mtime - FROM ' . STYLES_TEMPLATE_DATA_TABLE . " - WHERE template_id = $id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $filemtime[$row['template_filename']] = $row['template_mtime']; - $file_template_db[$row['template_filename']] = $id; - } - $db->sql_freeresult($result); - } - } + // Order by reversed style_id, so parent styles would be removed after child styles + // This way parent and child styles can be removed in same function call + $sql = 'SELECT * + FROM ' . STYLES_TABLE . ' + WHERE style_id IN (' . implode(', ', $ids) . ') + ORDER BY style_id DESC'; + $result = $this->db->sql_query($sql); - // Get a list of cached template files and then retrieve additional information about them - $file_ary = $this->template_cache_filelist($template_row['template_path']); + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); - foreach ($file_ary as $file) + // Uinstall each style + $uninstalled = array(); + foreach ($rows as $style) { - $file = str_replace('/', '.', $file); - - // perform some dirty guessing to get the path right. - // We assume that three dots in a row were '../' - $tpl_file = str_replace('.', '/', $file); - $tpl_file = str_replace('///', '../', $tpl_file); + $result = $this->uninstall_style($style, $delete_files); - $filename = "{$cache_prefix}_$file.html.$phpEx"; - - if (!file_exists("{$phpbb_root_path}cache/$filename")) + if (is_string($result)) { + $messages[] = $result; continue; } + $messages[] = sprintf($this->user->lang['STYLE_UNINSTALLED'], $style['style_name']); + $uninstalled[] = $style['style_name']; - $file_tpl = "{$phpbb_root_path}styles/{$template_row['template_path']}/template/$tpl_file.html"; - $inherited = false; - - if (isset($template_row['template_inherits_id']) && $template_row['template_inherits_id']) - { - if (!$template_row['template_storedb']) - { - if (!file_exists($file_tpl)) - { - $file_tpl = "{$phpbb_root_path}styles/{$template_row['template_inherit_path']}/template/$tpl_file.html"; - $inherited = true; - } - } - else - { - if ($file_template_db[$file . '.html'] == $template_row['template_inherits_id']) - { - $file_tpl = "{$phpbb_root_path}styles/{$template_row['template_inherit_path']}/template/$tpl_file.html"; - $inherited = true; - } - } - } - - // Correct the filename if it is stored in database and the file is in a subfolder. - if ($template_row['template_storedb']) + // Attempt to delete files + if ($delete_files) { - $file = str_replace('.', '/', $file); + $messages[] = sprintf($this->user->lang[$this->delete_style_files($style['style_path']) ? 'DELETE_STYLE_FILES_SUCCESS' : 'DELETE_STYLE_FILES_FAILED'], $style['style_name']); } + } - $template->assign_block_vars('file', array( - 'U_VIEWSOURCE' => $this->u_action . "&action=cache&id=$template_id&source=$file", + if (empty($messages)) + { + // Nothing to uninstall? + trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); + } - 'CACHED' => $user->format_date(filemtime("{$phpbb_root_path}cache/$filename")), - 'FILENAME' => $file, - 'FILENAME_PATH' => $file_tpl, - 'FILESIZE' => get_formatted_filesize(filesize("{$phpbb_root_path}cache/$filename")), - 'MODIFIED' => $user->format_date((!$template_row['template_storedb']) ? filemtime($file_tpl) : $filemtime[$file . '.html'])) - ); + // Log action + if (count($uninstalled)) + { + add_log('admin', 'LOG_STYLE_DELETE', implode(', ', $uninstalled)); } - unset($filemtime); - $template->assign_vars(array( - 'S_CACHE' => true, - 'S_TEMPLATE' => true, + // Clear cache + $this->cache->purge(); - 'U_ACTION' => $this->u_action . "&action=cache&id=$template_id", - 'U_BACK' => $this->u_action) - ); + // Show message + trigger_error(implode('<br />', $messages) . adm_back_link($this->u_action), E_USER_NOTICE); } /** - * Provides a css editor and a basic easier to use stylesheet editing tool for less experienced (or lazy) users - * - * @param int $theme_id specifies which theme is being edited + * Activate styles */ - function edit_theme($theme_id) + protected function action_activate() { - global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template, $safe_mode; - - $this->page_title = 'EDIT_THEME'; - - $filelist = $filelist_cats = array(); - - $theme_data = utf8_normalize_nfc(request_var('template_data', '', true)); - $theme_data = htmlspecialchars_decode($theme_data); - $theme_file = utf8_normalize_nfc(request_var('template_file', '', true)); - $text_rows = max(5, min(999, request_var('text_rows', 20))); - $save_changes = (isset($_POST['save'])) ? true : false; - - // make sure theme_file path doesn't go upwards - $theme_file = str_replace('..', '.', $theme_file); - - // Retrieve some information about the theme - $sql = 'SELECT theme_storedb, theme_path, theme_name, theme_data - FROM ' . STYLES_THEME_TABLE . " - WHERE theme_id = $theme_id"; - $result = $db->sql_query($sql); - - if (!($theme_info = $db->sql_fetchrow($result))) - { - trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING); - } - $db->sql_freeresult($result); - - // save changes to the theme if the user submitted any - if ($save_changes) - { - // Get the filesystem location of the current file - $file = "{$phpbb_root_path}styles/{$theme_info['theme_path']}/theme/$theme_file"; - $additional = ''; - $message = $user->lang['THEME_UPDATED']; - - // If the theme is stored on the filesystem try to write the file else store it in the database - if (!$safe_mode && !$theme_info['theme_storedb'] && file_exists($file) && phpbb_is_writable($file)) - { - if (!($fp = @fopen($file, 'wb'))) - { - trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING); - } - fwrite($fp, $theme_data); - fclose($fp); - } - else - { - // Write stylesheet to db - $sql_ary = array( - 'theme_mtime' => time(), - 'theme_storedb' => 1, - 'theme_data' => $this->db_theme_data($theme_info, $theme_data), - ); - $sql = 'UPDATE ' . STYLES_THEME_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE theme_id = ' . $theme_id; - $db->sql_query($sql); - - $cache->destroy('sql', STYLES_THEME_TABLE); - - // notify the user if the theme was not stored in the db before his modification - if (!$theme_info['theme_storedb']) - { - add_log('admin', 'LOG_THEME_EDIT_DETAILS', $theme_info['theme_name']); - $message .= '<br />' . $user->lang['EDIT_THEME_STORED_DB']; - } - } - $cache->destroy('sql', STYLES_THEME_TABLE); - add_log('admin', (!$theme_info['theme_storedb']) ? 'LOG_THEME_EDIT_FILE' : 'LOG_THEME_EDIT', $theme_info['theme_name'], (!$theme_info['theme_storedb']) ? $theme_file : ''); + // Get list of styles to activate + $ids = $this->request_vars('id', 0, true); - trigger_error($message . adm_back_link($this->u_action . "&action=edit&id=$theme_id&template_file=$theme_file&text_rows=$text_rows")); - } + // Activate styles + $sql = 'UPDATE ' . STYLES_TABLE . ' + SET style_active = 1 + WHERE style_id IN (' . implode(', ', $ids) . ')'; + $this->db->sql_query($sql); - // Generate a category array containing theme filenames - if (!$theme_info['theme_storedb']) - { - $theme_path = "{$phpbb_root_path}styles/{$theme_info['theme_path']}/theme"; + // Purge cache + $this->cache->destroy('sql', STYLES_TABLE); - $filelist = filelist($theme_path, '', 'css'); + // Show styles list + $this->frontend(); + } - if ($theme_file) - { - if (!file_exists($theme_path . "/$theme_file") || !($theme_data = file_get_contents($theme_path . "/$theme_file"))) - { - trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING); - } - } - } - else - { - $theme_data = &$theme_info['theme_data']; - } + /** + * Deactivate styles + */ + protected function action_deactivate() + { + // Get list of styles to deactivate + $ids = $this->request_vars('id', 0, true); - // Now create the categories - $filelist_cats[''] = array(); - foreach ($filelist as $pathfile => $file_ary) + // Check for default style + foreach ($ids as $id) { - // Use the directory name as category name - if (!empty($pathfile)) - { - $filelist_cats[$pathfile] = array(); - foreach ($file_ary as $file) - { - $filelist_cats[$pathfile][$pathfile . $file] = $file; - } - } - // or if it's in the main category use the word before the first underscore to group files - else + if ($id == $this->default_style) { - $cats = array(); - foreach ($file_ary as $file) - { - $cats[] = substr($file, 0, strpos($file, '_')); - $filelist_cats[substr($file, 0, strpos($file, '_'))][$file] = $file; - } - - $cats = array_values(array_unique($cats)); - - // we don't need any single element categories so put them into the misc '' category - for ($i = 0, $n = sizeof($cats); $i < $n; $i++) - { - if (sizeof($filelist_cats[$cats[$i]]) == 1 && $cats[$i] !== '') - { - $filelist_cats[''][key($filelist_cats[$cats[$i]])] = current($filelist_cats[$cats[$i]]); - unset($filelist_cats[$cats[$i]]); - } - } - unset($cats); + trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); } } - unset($filelist); - // Generate list of categorised theme files - $tpl_options = ''; - ksort($filelist_cats); - foreach ($filelist_cats as $category => $tpl_ary) - { - ksort($tpl_ary); + // Reset default style for users who use selected styles + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_style = 0 + WHERE user_style IN (' . implode(', ', $ids) . ')'; + $this->db->sql_query($sql); - if (!empty($category)) - { - $tpl_options .= '<option class="sep" value="">' . $category . '</option>'; - } + // Deactivate styles + $sql = 'UPDATE ' . STYLES_TABLE . ' + SET style_active = 0 + WHERE style_id IN (' . implode(', ', $ids) . ')'; + $this->db->sql_query($sql); - foreach ($tpl_ary as $filename => $file) - { - $selected = ($theme_file == $filename) ? ' selected="selected"' : ''; - $tpl_options .= '<option value="' . $filename . '"' . $selected . '>' . $file . '</option>'; - } - } + // Purge cache + $this->cache->destroy('sql', STYLES_TABLE); - $template->assign_vars(array( - 'S_EDIT_THEME' => true, - 'S_HIDDEN_FIELDS' => build_hidden_fields(array('template_file' => $theme_file)), - 'S_THEME_IN_DB' => $theme_info['theme_storedb'], - 'S_TEMPLATES' => $tpl_options, - - 'U_ACTION' => $this->u_action . "&action=edit&id=$theme_id&text_rows=$text_rows", - 'U_BACK' => $this->u_action, - - 'L_EDIT' => $user->lang['EDIT_THEME'], - 'L_EDIT_EXPLAIN' => $user->lang['EDIT_THEME_EXPLAIN'], - 'L_EDITOR' => $user->lang['THEME_EDITOR'], - 'L_EDITOR_HEIGHT' => $user->lang['THEME_EDITOR_HEIGHT'], - 'L_FILE' => $user->lang['THEME_FILE'], - 'L_SELECT' => $user->lang['SELECT_THEME'], - 'L_SELECTED' => $user->lang['SELECTED_THEME'], - 'L_SELECTED_FILE' => $user->lang['SELECTED_THEME_FILE'], - - 'SELECTED_TEMPLATE' => $theme_info['theme_name'], - 'TEMPLATE_FILE' => $theme_file, - 'TEMPLATE_DATA' => utf8_htmlspecialchars($theme_data), - 'TEXT_ROWS' => $text_rows) - ); + // Show styles list + $this->frontend(); } /** - * Edit imagesets - * - * @param int $imageset_id specifies which imageset is being edited + * Show style details */ - function edit_imageset($imageset_id) + protected function action_details() { - global $db, $user, $phpbb_root_path, $cache, $template; - - $this->page_title = 'EDIT_IMAGESET'; - - if (!$imageset_id) + $id = $this->request->variable('id', 0); + if (!$id) { - trigger_error($user->lang['NO_IMAGESET'] . adm_back_link($this->u_action), E_USER_WARNING); + trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); } - $update = (isset($_POST['update'])) ? true : false; - - $imgname = request_var('imgname', 'site_logo'); - $imgname = preg_replace('#[^a-z0-9\-+_]#i', '', $imgname); - $sql_extra = $imgnamelang = ''; + // Get all styles + $styles = $this->get_styles(); + usort($styles, array($this, 'sort_styles')); - $sql = 'SELECT imageset_path, imageset_name - FROM ' . STYLES_IMAGESET_TABLE . " - WHERE imageset_id = $imageset_id"; - $result = $db->sql_query($sql); - $imageset_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$imageset_row) + // Find current style + $style = false; + foreach ($styles as $row) { - trigger_error($user->lang['NO_IMAGESET'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $imageset_path = $imageset_row['imageset_path']; - $imageset_name = $imageset_row['imageset_name']; - - if (strpos($imgname, '-') !== false) - { - list($imgname, $imgnamelang) = explode('-', $imgname); - $sql_extra = " AND image_lang IN ('" . $db->sql_escape($imgnamelang) . "', '')"; - } - - $sql = 'SELECT image_filename, image_width, image_height, image_lang, image_id - FROM ' . STYLES_IMAGESET_DATA_TABLE . " - WHERE imageset_id = $imageset_id - AND image_name = '" . $db->sql_escape($imgname) . "'$sql_extra"; - $result = $db->sql_query($sql); - $imageset_data_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $image_filename = $imageset_data_row['image_filename']; - $image_width = $imageset_data_row['image_width']; - $image_height = $imageset_data_row['image_height']; - $image_lang = $imageset_data_row['image_lang']; - $image_id = $imageset_data_row['image_id']; - $imgsize = ($imageset_data_row['image_width'] && $imageset_data_row['image_height']) ? 1 : 0; - - // Check to see whether the selected image exists in the table - $valid_name = ($update) ? false : true; - - foreach ($this->imageset_keys as $category => $img_ary) - { - if (in_array($imgname, $img_ary)) + if ($row['style_id'] == $id) { - $valid_name = true; + $style = $row; break; } } - if ($update && isset($_POST['imgpath']) && $valid_name) + if ($style === false) { - // If imgwidth and imgheight are non-zero grab the actual size - // from the image itself ... we ignore width settings for the poll center image - $imgwidth = request_var('imgwidth', 0); - $imgheight = request_var('imgheight', 0); - $imgsize = request_var('imgsize', 0); - $imgpath = request_var('imgpath', ''); - $imgpath = str_replace('..', '.', $imgpath); - - // If no dimensions selected, we reset width and height to 0 ;) - if (!$imgsize) - { - $imgwidth = $imgheight = 0; - } - - $imglang = ''; + trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); + } - if ($imgpath && !file_exists("{$phpbb_root_path}styles/$imageset_path/imageset/$imgpath")) - { - trigger_error($user->lang['NO_IMAGE_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING); - } + // Find all available parent styles + $list = $this->find_possible_parents($styles, $id); - // Determine width/height. If dimensions included and no width/height given, we detect them automatically... - if ($imgsize && $imgpath) - { - if (!$imgwidth || !$imgheight) - { - list($imgwidth_file, $imgheight_file) = getimagesize("{$phpbb_root_path}styles/$imageset_path/imageset/$imgpath"); - $imgwidth = ($imgwidth) ? $imgwidth : $imgwidth_file; - $imgheight = ($imgheight) ? $imgheight : $imgheight_file; - } - $imgwidth = ($imgname != 'poll_center') ? (int) $imgwidth : 0; - $imgheight = (int) $imgheight; - } + // Add form key + $form_key = 'acp_styles'; + add_form_key($form_key); - if (strpos($imgpath, '/') !== false) - { - list($imglang, $imgfilename) = explode('/', $imgpath); - } - else + // Change data + if ($this->request->variable('update', false)) + { + if (!check_form_key($form_key)) { - $imgfilename = $imgpath; + trigger_error($this->user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); } - $sql_ary = array( - 'image_filename' => (string) $imgfilename, - 'image_width' => (int) $imgwidth, - 'image_height' => (int) $imgheight, - 'image_lang' => (string) $imglang, + $update = array( + 'style_name' => trim($this->request->variable('style_name', $style['style_name'])), + 'style_parent_id' => $this->request->variable('style_parent', (int) $style['style_parent_id']), + 'style_active' => $this->request->variable('style_active', (int) $style['style_active']), ); + $update_action = $this->u_action . '&action=details&id=' . $id; - // already exists - if ($imageset_data_row) - { - $sql = 'UPDATE ' . STYLES_IMAGESET_DATA_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE image_id = $image_id"; - $db->sql_query($sql); - } - // does not exist - else if (!$imageset_data_row) + // Check style name + if ($update['style_name'] != $style['style_name']) { - $sql_ary['image_name'] = $imgname; - $sql_ary['imageset_id'] = (int) $imageset_id; - $db->sql_query('INSERT INTO ' . STYLES_IMAGESET_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - } - - $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); - - add_log('admin', 'LOG_IMAGESET_EDIT', $imageset_name); - - $template->assign_var('SUCCESS', true); - - $image_filename = $imgfilename; - $image_width = $imgwidth; - $image_height = $imgheight; - $image_lang = $imglang; - } - - $imglang = ''; - $imagesetlist = array('nolang' => array(), 'lang' => array()); - $langs = array(); - - $dir = "{$phpbb_root_path}styles/$imageset_path/imageset"; - $dp = @opendir($dir); - - if ($dp) - { - while (($file = readdir($dp)) !== false) - { - if ($file[0] != '.' && strtoupper($file) != 'CVS' && !is_file($dir . '/' . $file) && !is_link($dir . '/' . $file)) + if (!strlen($update['style_name'])) { - $langs[] = $file; + trigger_error($this->user->lang['STYLE_ERR_STYLE_NAME'] . adm_back_link($update_action), E_USER_WARNING); } - else if (preg_match('#\.(?:gif|jpg|png)$#', $file)) + foreach ($styles as $row) { - $imagesetlist['nolang'][] = $file; + if ($row['style_name'] == $update['style_name']) + { + trigger_error($this->user->lang['STYLE_ERR_NAME_EXIST'] . adm_back_link($update_action), E_USER_WARNING); + } } } - - if ($sql_extra) + else { - $dp2 = @opendir("$dir/$imgnamelang"); + unset($update['style_name']); + } - if ($dp2) + // Check parent style id + if ($update['style_parent_id'] != $style['style_parent_id']) + { + if ($update['style_parent_id'] != 0) { - while (($file2 = readdir($dp2)) !== false) + $found = false; + foreach ($list as $row) { - if (preg_match('#\.(?:gif|jpg|png)$#', $file2)) + if ($row['style_id'] == $update['style_parent_id']) { - $imagesetlist['lang'][] = "$imgnamelang/$file2"; + $found = true; + $update['style_parent_tree'] = ($row['style_parent_tree'] != '' ? $row['style_parent_tree'] . '/' : '') . $row['style_path']; + break; } } - closedir($dp2); - } - } - closedir($dp); - } - - // Generate list of image options - $img_options = ''; - foreach ($this->imageset_keys as $category => $img_ary) - { - $template->assign_block_vars('category', array( - 'NAME' => $user->lang['IMG_CAT_' . strtoupper($category)] - )); - - foreach ($img_ary as $img) - { - if ($category == 'buttons') - { - foreach ($langs as $language) + if (!$found) { - $template->assign_block_vars('category.images', array( - 'SELECTED' => ($img == $imgname && $language == $imgnamelang), - 'VALUE' => $img . '-' . $language, - 'TEXT' => $user->lang['IMG_' . strtoupper($img)] . ' [ ' . $language . ' ]' - )); + trigger_error($this->user->lang['STYLE_ERR_INVALID_PARENT'] . adm_back_link($update_action), E_USER_WARNING); } } else { - $template->assign_block_vars('category.images', array( - 'SELECTED' => ($img == $imgname), - 'VALUE' => $img, - 'TEXT' => (($category == 'custom') ? $img : $user->lang['IMG_' . strtoupper($img)]) - )); + $update['style_parent_tree'] = ''; } } - } - - // Make sure the list of possible images is sorted alphabetically - sort($imagesetlist['lang']); - sort($imagesetlist['nolang']); - - $image_found = false; - $img_val = ''; - foreach ($imagesetlist as $type => $img_ary) - { - if ($type !== 'lang' || $sql_extra) + else { - $template->assign_block_vars('imagesetlist', array( - 'TYPE' => ($type == 'lang') - )); + unset($update['style_parent_id']); } - foreach ($img_ary as $img) + // Check style_active + if ($update['style_active'] != $style['style_active']) { - $imgtext = preg_replace('/^([^\/]+\/)/', '', $img); - $selected = (!empty($imgname) && strpos($image_filename, $imgtext) !== false); - if ($selected) + if (!$update['style_active'] && $this->default_style == $style['style_id']) { - $image_found = true; - $img_val = htmlspecialchars($img); + trigger_error($this->user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($update_action), E_USER_WARNING); } - $template->assign_block_vars('imagesetlist.images', array( - 'SELECTED' => $selected, - 'TEXT' => $imgtext, - 'VALUE' => htmlspecialchars($img) - )); } - } - - $imgsize_bool = (!empty($imgname) && $image_width && $image_height) ? true : false; - $image_request = '../styles/' . $imageset_path . '/imageset/' . ($image_lang ? $imgnamelang . '/' : '') . $image_filename; - - $template->assign_vars(array( - 'S_EDIT_IMAGESET' => true, - 'L_TITLE' => $user->lang[$this->page_title], - 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'], - 'IMAGE_OPTIONS' => $img_options, - 'IMAGE_SIZE' => $image_width, - 'IMAGE_HEIGHT' => $image_height, - 'IMAGE_REQUEST' => (empty($image_filename)) ? 'images/no_image.png' : $image_request, - 'U_ACTION' => $this->u_action . "&action=edit&id=$imageset_id", - 'U_BACK' => $this->u_action, - 'NAME' => $imageset_name, - 'A_NAME' => addslashes($imageset_name), - 'PATH' => $imageset_path, - 'A_PATH' => addslashes($imageset_path), - 'ERROR' => !$valid_name, - 'IMG_SRC' => ($image_found) ? '../styles/' . $imageset_path . '/imageset/' . $img_val : 'images/no_image.png', - 'IMAGE_SELECT' => $image_found - )); - } - - /** - * Remove style/template/theme/imageset - */ - function remove($mode, $style_id) - { - global $db, $template, $user, $phpbb_root_path, $cache, $config; - - $new_id = request_var('new_id', 0); - $update = (isset($_POST['update'])) ? true : false; - $sql_where = ''; - - switch ($mode) - { - case 'style': - $sql_from = STYLES_TABLE; - $sql_select = 'style_id, style_name, template_id, theme_id, imageset_id'; - $sql_where = 'AND style_active = 1'; - break; - - case 'template': - $sql_from = STYLES_TEMPLATE_TABLE; - $sql_select = 'template_id, template_name, template_path, template_storedb'; - break; - - case 'theme': - $sql_from = STYLES_THEME_TABLE; - $sql_select = 'theme_id, theme_name, theme_path, theme_storedb'; - break; - - case 'imageset': - $sql_from = STYLES_IMAGESET_TABLE; - $sql_select = 'imageset_id, imageset_name, imageset_path'; - break; - } - - if ($mode === 'template' && ($conflicts = $this->check_inheritance($mode, $style_id))) - { - $l_type = strtoupper($mode); - $msg = $user->lang[$l_type . '_DELETE_DEPENDENT']; - foreach ($conflicts as $id => $values) + else { - $msg .= '<br />' . $values['template_name']; + unset($update['style_active']); } - trigger_error($msg . adm_back_link($this->u_action), E_USER_WARNING); - } - - $l_prefix = strtoupper($mode); - - $sql = "SELECT $sql_select - FROM $sql_from - WHERE {$mode}_id = $style_id"; - $result = $db->sql_query($sql); - $style_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$style_row) - { - trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $s_only_component = $this->display_component_options($mode, $style_row[$mode . '_id'], $style_row); - - if ($s_only_component) - { - trigger_error($user->lang['ONLY_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING); - } - - if ($update) - { - if ($mode == 'style') + // Update data + if (count($update)) { - $sql = "DELETE FROM $sql_from - WHERE {$mode}_id = $style_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_style = $new_id - WHERE user_style = $style_id"; - $db->sql_query($sql); + $sql = 'UPDATE ' . STYLES_TABLE . ' + SET ' . $this->db->sql_build_array('UPDATE', $update) . " + WHERE style_id = $id"; + $this->db->sql_query($sql); - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_style = $new_id - WHERE forum_style = $style_id"; - $db->sql_query($sql); + $style = array_merge($style, $update); - if ($style_id == $config['default_style']) + if (isset($update['style_parent_id'])) { - set_config('default_style', $new_id); + // Update styles tree + $styles = $this->get_styles(); + if ($this->update_styles_tree($styles, $style)) + { + // Something was changed in styles tree, purge all cache + $this->cache->purge(); + } } + add_log('admin', 'LOG_STYLE_EDIT_DETAILS', $style['style_name']); + } - // Remove the components - $components = array('template', 'theme', 'imageset'); - foreach ($components as $component) + // Update default style + $default = $this->request->variable('style_default', 0); + if ($default) + { + if (!$style['style_active']) { - $new_id = request_var('new_' . $component . '_id', 0); - $component_id = $style_row[$component . '_id']; - $this->remove_component($component, $component_id, $new_id, $style_id); + trigger_error($this->user->lang['STYLE_DEFAULT_CHANGE_INACTIVE'] . adm_back_link($update_action), E_USER_WARNING); } - } - else - { - $this->remove_component($mode, $style_id, $new_id); + set_config('default_style', $id); + $this->cache->purge(); } - $cache->destroy('sql', STYLES_TABLE); - - add_log('admin', 'LOG_' . $l_prefix . '_DELETE', $style_row[$mode . '_name']); - $message = ($mode != 'style') ? $l_prefix . '_DELETED_FS' : $l_prefix . '_DELETED'; - trigger_error($user->lang[$message] . adm_back_link($this->u_action)); + // Show styles list + $this->frontend(); + return; } - $this->page_title = 'DELETE_' . $l_prefix; - - $template->assign_vars(array( - 'S_DELETE' => true, + // Show page title + $this->welcome_message('ACP_STYLES', null); - 'L_TITLE' => $user->lang[$this->page_title], - 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'], - 'L_NAME' => $user->lang[$l_prefix . '_NAME'], - 'L_REPLACE' => $user->lang['REPLACE_' . $l_prefix], - 'L_REPLACE_EXPLAIN' => $user->lang['REPLACE_' . $l_prefix . '_EXPLAIN'], - - 'U_ACTION' => $this->u_action . "&action=delete&id=$style_id", - 'U_BACK' => $this->u_action, + // Show parent styles + foreach ($list as $row) + { + $this->template->assign_block_vars('parent_styles', array( + 'STYLE_ID' => $row['style_id'], + 'STYLE_NAME' => htmlspecialchars($row['style_name']), + 'LEVEL' => $row['level'], + 'SPACER' => str_repeat(' ', $row['level']), + ) + ); + } - 'NAME' => $style_row[$mode . '_name'], + // Show style details + $this->template->assign_vars(array( + 'S_STYLE_DETAILS' => true, + 'STYLE_ID' => $style['style_id'], + 'STYLE_NAME' => htmlspecialchars($style['style_name']), + 'STYLE_PATH' => htmlspecialchars($style['style_path']), + '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) ) ); - - if ($mode == 'style') - { - $template->assign_vars(array( - 'S_DELETE_STYLE' => true, - )); - } } /** - * Remove template/theme/imageset entry from the database + * List installed styles */ - function remove_component($component, $component_id, $new_id, $style_id = false) + protected function show_installed() { - global $db; - - if (($new_id == 0) || ($component === 'template' && ($conflicts = $this->check_inheritance($component, $component_id)))) - { - // We can not delete the template, as the user wants to keep the component or an other template is inheriting from this one. - return; - } + // Get all installed styles + $styles = $this->get_styles(); - $component_in_use = array(); - if ($component != 'style') + if (!count($styles)) { - $component_in_use = $this->component_in_use($component, $component_id, $style_id); + trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); } - if (($new_id == -1) && !empty($component_in_use)) - { - // We can not delete the component, as it is still in use - return; - } + usort($styles, array($this, 'sort_styles')); - if ($component == 'imageset') - { - $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . " - WHERE imageset_id = $component_id"; - $db->sql_query($sql); - } + // Get users + $users = $this->get_users(); - switch ($component) + // Add users counter to rows + foreach ($styles as &$style) { - case 'template': - $sql_from = STYLES_TEMPLATE_TABLE; - break; - - case 'theme': - $sql_from = STYLES_THEME_TABLE; - break; - - case 'imageset': - $sql_from = STYLES_IMAGESET_TABLE;; - break; + $style['_users'] = isset($users[$style['style_id']]) ? $users[$style['style_id']] : 0; } - $sql = "DELETE FROM $sql_from - WHERE {$component}_id = $component_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . STYLES_TABLE . " - SET {$component}_id = $new_id - WHERE {$component}_id = $component_id"; - $db->sql_query($sql); - } - - /** - * Display the options which can be used to replace a style/template/theme/imageset - * - * @return boolean Returns true if the component is the only component and can not be deleted. - */ - function display_component_options($component, $component_id, $style_row = false, $style_id = false) - { - global $db, $template, $user; - - $is_only_component = true; - $component_in_use = array(); - if ($component != 'style') - { - $component_in_use = $this->component_in_use($component, $component_id, $style_id); - } + // Set up styles list variables + // Addons should increase this number and update template variable + $this->styles_list_cols = 4; + $this->template->assign_var('STYLES_LIST_COLS', $this->styles_list_cols); - $sql_where = ''; - switch ($component) - { - case 'style': - $sql_from = STYLES_TABLE; - $sql_where = 'WHERE style_active = 1'; - break; - - case 'template': - $sql_from = STYLES_TEMPLATE_TABLE; - $sql_where = 'WHERE template_inherits_id <> ' . $component_id; - break; - - case 'theme': - $sql_from = STYLES_THEME_TABLE; - break; - - case 'imageset': - $sql_from = STYLES_IMAGESET_TABLE; - break; - } + // Show styles list + $this->show_styles_list($styles, 0, 0); - $s_options = ''; - if (($component != 'style') && empty($component_in_use)) + // Show styles with invalid inherits_id + foreach ($styles as $style) { - // If it is not in use, there must be another component - $is_only_component = false; - - $sql = "SELECT {$component}_id, {$component}_name - FROM $sql_from - WHERE {$component}_id = {$component_id}"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $s_options .= '<option value="-1" selected="selected">' . $user->lang['DELETE_' . strtoupper($component)] . '</option>'; - $s_options .= '<option value="0">' . sprintf($user->lang['KEEP_' . strtoupper($component)], $row[$component . '_name']) . '</option>'; - } - else - { - $sql = "SELECT {$component}_id, {$component}_name - FROM $sql_from - $sql_where - ORDER BY {$component}_name ASC"; - $result = $db->sql_query($sql); - - $s_keep_option = $s_options = ''; - while ($row = $db->sql_fetchrow($result)) - { - if ($row[$component . '_id'] != $component_id) - { - $is_only_component = false; - $s_options .= '<option value="' . $row[$component . '_id'] . '">' . sprintf($user->lang['REPLACE_WITH_OPTION'], $row[$component . '_name']) . '</option>'; - } - else if ($component != 'style') - { - $s_keep_option = '<option value="0" selected="selected">' . sprintf($user->lang['KEEP_' . strtoupper($component)], $row[$component . '_name']) . '</option>'; - } - } - $db->sql_freeresult($result); - $s_options = $s_keep_option . $s_options; - } - - if (!$style_row) - { - $template->assign_var('S_REPLACE_' . strtoupper($component) . '_OPTIONS', $s_options); - } - else - { - $template->assign_var('S_REPLACE_OPTIONS', $s_options); - if ($component == 'style') + if (empty($style['_shown'])) { - $components = array('template', 'theme', 'imageset'); - foreach ($components as $component) - { - $this->display_component_options($component, $style_row[$component . '_id'], false, $component_id, true); - } + $style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($style['style_parent_tree'])); + $this->list_style($style, 0); } } - return $is_only_component; - } - - /** - * Check whether the component is still used by another style or component - */ - function component_in_use($component, $component_id, $style_id = false) - { - global $db; - - $component_in_use = array(); + // Add buttons + $this->template->assign_block_vars('extra_actions', array( + 'ACTION_NAME' => 'activate', + 'L_ACTION' => $this->user->lang['STYLE_ACTIVATE'], + ) + ); - if ($style_id) - { - $sql = 'SELECT style_id, style_name - FROM ' . STYLES_TABLE . " - WHERE {$component}_id = {$component_id} - AND style_id <> {$style_id} - ORDER BY style_name ASC"; - } - else - { - $sql = 'SELECT style_id, style_name - FROM ' . STYLES_TABLE . " - WHERE {$component}_id = {$component_id} - ORDER BY style_name ASC"; - } - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $component_in_use[] = $row['style_name']; - } - $db->sql_freeresult($result); + $this->template->assign_block_vars('extra_actions', array( + 'ACTION_NAME' => 'deactivate', + 'L_ACTION' => $this->user->lang['STYLE_DEACTIVATE'], + ) + ); - if ($component === 'template' && ($conflicts = $this->check_inheritance($component, $component_id))) + if (isset($this->style_counters) && $this->style_counters['total'] > 1) { - foreach ($conflicts as $temp_id => $conflict_data) - { - $component_in_use[] = $conflict_data['template_name']; - } + $this->template->assign_block_vars('extra_actions', array( + 'ACTION_NAME' => 'uninstall', + 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL'], + ) + ); } - - return $component_in_use; } /** - * Export style or style elements + * Show list of styles that can be installed */ - function export($mode, $style_id) + protected function show_available() { - global $db, $template, $user, $phpbb_root_path, $cache, $phpEx, $config; + // Get list of styles + $styles = $this->find_available(true); - $update = (isset($_POST['update'])) ? true : false; - - $inc_template = request_var('inc_template', 0); - $inc_theme = request_var('inc_theme', 0); - $inc_imageset = request_var('inc_imageset', 0); - $store = request_var('store', 0); - $format = request_var('format', ''); - - $error = array(); - $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; - } - - if (!in_array($format, $methods)) + // Show styles + if (empty($styles)) { - $format = 'tar'; + trigger_error($this->user->lang['NO_UNINSTALLED_STYLE'] . adm_back_link($this->u_base_action), E_USER_NOTICE); } - switch ($mode) - { - case 'style': - if ($update && ($inc_template + $inc_theme + $inc_imageset) < 1) - { - $error[] = $user->lang['STYLE_ERR_MORE_ELEMENTS']; - } - - $name = 'style_name'; - - $sql_select = 's.style_id, s.style_name, s.style_copyright'; - $sql_select .= ($inc_template) ? ', t.*' : ', t.template_name'; - $sql_select .= ($inc_theme) ? ', c.*' : ', c.theme_name'; - $sql_select .= ($inc_imageset) ? ', i.*' : ', i.imageset_name'; - $sql_from = STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . ' i'; - $sql_where = "s.style_id = $style_id AND t.template_id = s.template_id AND c.theme_id = s.theme_id AND i.imageset_id = s.imageset_id"; - - $l_prefix = 'STYLE'; - break; - - case 'template': - $name = 'template_name'; - - $sql_select = '*'; - $sql_from = STYLES_TEMPLATE_TABLE; - $sql_where = "template_id = $style_id"; - - $l_prefix = 'TEMPLATE'; - break; + usort($styles, array($this, 'sort_styles')); - case 'theme': - $name = 'theme_name'; - - $sql_select = '*'; - $sql_from = STYLES_THEME_TABLE; - $sql_where = "theme_id = $style_id"; - - $l_prefix = 'THEME'; - break; - - case 'imageset': - $name = 'imageset_name'; - - $sql_select = '*'; - $sql_from = STYLES_IMAGESET_TABLE; - $sql_where = "imageset_id = $style_id"; - - $l_prefix = 'IMAGESET'; - break; - } + $this->styles_list_cols = 3; + $this->template->assign_vars(array( + 'STYLES_LIST_COLS' => $this->styles_list_cols, + 'STYLES_LIST_HIDE_COUNT' => true + ) + ); - if ($update && !sizeof($error)) + // Show styles + foreach ($styles as &$style) { - $sql = "SELECT $sql_select - FROM $sql_from - WHERE $sql_where"; - $result = $db->sql_query($sql); - $style_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$style_row) - { - trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $var_ary = array('style_id', 'style_name', 'style_copyright', 'template_id', 'template_name', 'template_path', 'template_copyright', 'template_storedb', 'template_inherits_id', 'bbcode_bitfield', 'theme_id', 'theme_name', 'theme_path', 'theme_copyright', 'theme_storedb', 'theme_mtime', 'theme_data', 'imageset_id', 'imageset_name', 'imageset_path', 'imageset_copyright'); - - foreach ($var_ary as $var) - { - if (!isset($style_row[$var])) - { - $style_row[$var] = ''; - } - } - - $files = $data = array(); - - if ($mode == 'style') - { - $style_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}'), array($mode, $style_row['style_name'], $style_row['style_copyright'], $config['version']), $this->style_cfg); - - $style_cfg .= (!$inc_template) ? "\nrequired_template = {$style_row['template_name']}" : ''; - $style_cfg .= (!$inc_theme) ? "\nrequired_theme = {$style_row['theme_name']}" : ''; - $style_cfg .= (!$inc_imageset) ? "\nrequired_imageset = {$style_row['imageset_name']}" : ''; - - $data[] = array( - 'src' => $style_cfg, - 'prefix' => 'style.cfg' - ); - - unset($style_cfg); - } - - // Export template core code - if ($mode == 'template' || $inc_template) - { - $use_template_name = $style_row['template_name']; - - // Add the inherit from variable, depending on it's use... - if ($style_row['template_inherits_id']) - { - // Get the template name - $sql = 'SELECT template_name - FROM ' . STYLES_TEMPLATE_TABLE . ' - WHERE template_id = ' . (int) $style_row['template_inherits_id']; - $result = $db->sql_query($sql); - $use_template_name = (string) $db->sql_fetchfield('template_name'); - $db->sql_freeresult($result); - } - - $template_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}', '{INHERIT_FROM}'), array($mode, $style_row['template_name'], $style_row['template_copyright'], $config['version'], $use_template_name), $this->template_cfg); - - $template_cfg .= "\n\nbbcode_bitfield = {$style_row['bbcode_bitfield']}"; - - $data[] = array( - 'src' => $template_cfg, - 'prefix' => 'template/template.cfg' - ); - - // This is potentially nasty memory-wise ... - if (!$style_row['template_storedb']) - { - $files[] = array( - 'src' => "styles/{$style_row['template_path']}/template/", - 'prefix-' => "styles/{$style_row['template_path']}/", - 'prefix+' => false, - 'exclude' => 'template.cfg' - ); - } - else - { - $sql = 'SELECT template_filename, template_data - FROM ' . STYLES_TEMPLATE_DATA_TABLE . " - WHERE template_id = {$style_row['template_id']}"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $data[] = array( - 'src' => $row['template_data'], - 'prefix' => 'template/' . $row['template_filename'] - ); - } - $db->sql_freeresult($result); - } - unset($template_cfg); - } - - // Export theme core code - if ($mode == 'theme' || $inc_theme) - { - $theme_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}'), array($mode, $style_row['theme_name'], $style_row['theme_copyright'], $config['version']), $this->theme_cfg); - - // Read old cfg file - $items = $cache->obtain_cfg_items($style_row); - $items = $items['theme']; - - if (!isset($items['parse_css_file'])) - { - $items['parse_css_file'] = 'off'; - } - - $theme_cfg = str_replace(array('{PARSE_CSS_FILE}'), array($items['parse_css_file']), $theme_cfg); - - $files[] = array( - 'src' => "styles/{$style_row['theme_path']}/theme/", - 'prefix-' => "styles/{$style_row['theme_path']}/", - 'prefix+' => false, - 'exclude' => ($style_row['theme_storedb']) ? 'stylesheet.css,theme.cfg' : 'theme.cfg' - ); - - $data[] = array( - 'src' => $theme_cfg, - 'prefix' => 'theme/theme.cfg' - ); - - if ($style_row['theme_storedb']) - { - $data[] = array( - 'src' => $style_row['theme_data'], - 'prefix' => 'theme/stylesheet.css' - ); - } - - unset($items, $theme_cfg); - } - - // Export imageset core code - if ($mode == 'imageset' || $inc_imageset) + // Check if style has a parent style in styles list + $has_parent = false; + if ($style['_inherit_name'] != '') { - $imageset_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}'), array($mode, $style_row['imageset_name'], $style_row['imageset_copyright'], $config['version']), $this->imageset_cfg); - - $imageset_main = array(); - - $sql = 'SELECT image_filename, image_name, image_height, image_width - FROM ' . STYLES_IMAGESET_DATA_TABLE . " - WHERE imageset_id = $style_id - AND image_lang = ''"; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $imageset_main[$row['image_name']] = $row['image_filename'] . ($row['image_height'] ? '*' . $row['image_height']: '') . ($row['image_width'] ? '*' . $row['image_width']: ''); - } - $db->sql_freeresult($result); - - foreach ($this->imageset_keys as $topic => $key_array) - { - foreach ($key_array as $key) - { - if (isset($imageset_main[$key])) - { - $imageset_cfg .= "\nimg_" . $key . ' = ' . str_replace("styles/{$style_row['imageset_path']}/imageset/", '{PATH}', $imageset_main[$key]); - } - } - } - - $files[] = array( - 'src' => "styles/{$style_row['imageset_path']}/imageset/", - 'prefix-' => "styles/{$style_row['imageset_path']}/", - 'prefix+' => false, - 'exclude' => 'imageset.cfg' - ); - - $data[] = array( - 'src' => trim($imageset_cfg), - 'prefix' => 'imageset/imageset.cfg' - ); - - end($data); - - $imageset_root = "{$phpbb_root_path}styles/{$style_row['imageset_path']}/imageset/"; - - if ($dh = @opendir($imageset_root)) + foreach ($styles as $parent_style) { - while (($fname = readdir($dh)) !== false) + if ($parent_style['style_name'] == $style['_inherit_name'] && empty($parent_style['_shown'])) { - if ($fname[0] != '.' && $fname != 'CVS' && is_dir("$imageset_root$fname")) - { - $files[key($files)]['exclude'] .= ',' . $fname . '/imageset.cfg'; - } - } - closedir($dh); - } - - $imageset_lang = array(); - - $sql = 'SELECT image_filename, image_name, image_height, image_width, image_lang - FROM ' . STYLES_IMAGESET_DATA_TABLE . " - WHERE imageset_id = $style_id - AND image_lang <> ''"; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $imageset_lang[$row['image_lang']][$row['image_name']] = $row['image_filename'] . ($row['image_height'] ? '*' . $row['image_height']: '') . ($row['image_width'] ? '*' . $row['image_width']: ''); - } - $db->sql_freeresult($result); - - foreach ($imageset_lang as $lang => $imageset_localized) - { - $imageset_cfg = str_replace(array('{MODE}', '{NAME}', '{COPYRIGHT}', '{VERSION}'), array($mode, $style_row['imageset_name'], $style_row['imageset_copyright'], $config['version']), $this->imageset_cfg); - - foreach ($this->imageset_keys as $topic => $key_array) - { - foreach ($key_array as $key) - { - if (isset($imageset_localized[$key])) - { - $imageset_cfg .= "\nimg_" . $key . ' = ' . str_replace("styles/{$style_row['imageset_path']}/imageset/", '{PATH}', $imageset_localized[$key]); - } - } + // Show parent style first + $has_parent = true; } - - $data[] = array( - 'src' => trim($imageset_cfg), - 'prefix' => 'imageset/' . $lang . '/imageset.cfg' - ); } - - unset($imageset_cfg); } - - switch ($format) + if (!$has_parent) { - case 'tar': - $ext = '.tar'; - break; - - case 'zip': - $ext = '.zip'; - break; - - case 'tar.gz': - $ext = '.tar.gz'; - break; - - case 'tar.bz2': - $ext = '.tar.bz2'; - break; - - default: - $error[] = $user->lang[$l_prefix . '_ERR_ARCHIVE']; + $this->list_style($style, 0); + $this->show_available_child_styles($styles, $style['style_name'], 1); } + } - if (!sizeof($error)) + // Show styles that do not have parent style in styles list + foreach ($styles as $style) + { + if (empty($style['_shown'])) { - include($phpbb_root_path . 'includes/functions_compress.' . $phpEx); - - if ($mode == 'style') - { - $path = preg_replace('#[^\w-]+#', '_', $style_row['style_name']); - } - else - { - $path = $style_row[$mode . '_path']; - } - - if ($format == 'zip') - { - $compress = new compress_zip('w', $phpbb_root_path . "store/$path$ext"); - } - else - { - $compress = new compress_tar('w', $phpbb_root_path . "store/$path$ext", $ext); - } - - if (sizeof($files)) - { - foreach ($files as $file_ary) - { - $compress->add_file($file_ary['src'], $file_ary['prefix-'], $file_ary['prefix+'], $file_ary['exclude']); - } - } - - if (sizeof($data)) - { - foreach ($data as $data_ary) - { - $compress->add_data($data_ary['src'], $data_ary['prefix']); - } - } - - $compress->close(); - - add_log('admin', 'LOG_' . $l_prefix . '_EXPORT', $style_row[$mode . '_name']); - - if (!$store) - { - $compress->download($path); - @unlink("{$phpbb_root_path}store/$path$ext"); - exit; - } - - trigger_error(sprintf($user->lang[$l_prefix . '_EXPORTED'], "store/$path$ext") . adm_back_link($this->u_action)); + $this->list_style($style, 0); } } - $sql = "SELECT {$mode}_id, {$mode}_name - FROM " . (($mode == 'style') ? STYLES_TABLE : $sql_from) . " - WHERE {$mode}_id = $style_id"; - $result = $db->sql_query($sql); - $style_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$style_row) + // Add button + if (isset($this->style_counters) && $this->style_counters['caninstall'] > 0) { - trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $this->page_title = $l_prefix . '_EXPORT'; - - $format_buttons = ''; - foreach ($methods as $method) - { - $format_buttons .= '<label><input type="radio"' . ((!$format_buttons) ? ' id="format"' : '') . ' class="radio" value="' . $method . '" name="format"' . (($method == $format) ? ' checked="checked"' : '') . ' /> ' . $method . '</label>'; + $this->template->assign_block_vars('extra_actions', array( + 'ACTION_NAME' => 'install', + 'L_ACTION' => $this->user->lang['INSTALL_STYLES'], + ) + ); } - - $template->assign_vars(array( - 'S_EXPORT' => true, - 'S_ERROR_MSG' => (sizeof($error)) ? true : false, - 'S_STYLE' => ($mode == 'style') ? true : false, - - 'L_TITLE' => $user->lang[$this->page_title], - 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'], - 'L_NAME' => $user->lang[$l_prefix . '_NAME'], - - 'U_ACTION' => $this->u_action . '&action=export&id=' . $style_id, - 'U_BACK' => $this->u_action, - - 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '', - 'NAME' => $style_row[$mode . '_name'], - 'FORMAT_BUTTONS' => $format_buttons) - ); } /** - * Display details + * Find styles available for installation + * + * @param bool $all if true, function will return all installable styles. if false, function will return only styles that can be installed + * @return array List of styles */ - function details($mode, $style_id) + protected function find_available($all) { - global $template, $db, $config, $user, $safe_mode, $cache, $phpbb_root_path; - - $update = (isset($_POST['update'])) ? true : false; - $l_type = strtoupper($mode); - - $error = array(); - $element_ary = array('template' => STYLES_TEMPLATE_TABLE, 'theme' => STYLES_THEME_TABLE, 'imageset' => STYLES_IMAGESET_TABLE); - - switch ($mode) - { - case 'style': - $sql_from = STYLES_TABLE; - break; - - case 'template': - $sql_from = STYLES_TEMPLATE_TABLE; - break; - - case 'theme': - $sql_from = STYLES_THEME_TABLE; - break; - - case 'imageset': - $sql_from = STYLES_IMAGESET_TABLE; - break; - } - - $sql = "SELECT * - FROM $sql_from - WHERE {$mode}_id = $style_id"; - $result = $db->sql_query($sql); - $style_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$style_row) - { - trigger_error($user->lang['NO_' . $l_type] . adm_back_link($this->u_action), E_USER_WARNING); + // Get list of installed styles + $installed = $this->get_styles(); + + $installed_dirs = array(); + $installed_names = array(); + foreach ($installed as $style) + { + $installed_dirs[] = $style['style_path']; + $installed_names[$style['style_name']] = array( + 'path' => $style['style_path'], + 'id' => $style['style_id'], + 'parent' => $style['style_parent_id'], + 'tree' => (strlen($style['style_parent_tree']) ? $style['style_parent_tree'] . '/' : '') . $style['style_path'], + ); } - $style_row['style_default'] = ($mode == 'style' && $config['default_style'] == $style_id) ? 1 : 0; + // Get list of directories + $dirs = $this->find_style_dirs(); - if ($update) + // Find styles that can be installed + $styles = array(); + foreach ($dirs as $dir) { - $name = utf8_normalize_nfc(request_var('name', '', true)); - $copyright = utf8_normalize_nfc(request_var('copyright', '', true)); - - $template_id = request_var('template_id', 0); - $theme_id = request_var('theme_id', 0); - $imageset_id = request_var('imageset_id', 0); - - $style_active = request_var('style_active', 0); - $style_default = request_var('style_default', 0); - $store_db = request_var('store_db', 0); - - // If the admin selected the style to be the default style, but forgot to activate it... we will do it for him - if ($style_default) - { - $style_active = 1; - } - - $sql = "SELECT {$mode}_id, {$mode}_name - FROM $sql_from - WHERE {$mode}_id <> $style_id - AND LOWER({$mode}_name) = '" . $db->sql_escape(strtolower($name)) . "'"; - $result = $db->sql_query($sql); - $conflict = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($mode == 'style' && (!$template_id || !$theme_id || !$imageset_id)) - { - $error[] = $user->lang['STYLE_ERR_NO_IDS']; - } - - if ($mode == 'style' && $style_row['style_active'] && !$style_active && $config['default_style'] == $style_id) - { - $error[] = $user->lang['DEACTIVATE_DEFAULT']; - } - - if (!$name || $conflict) - { - $error[] = $user->lang[$l_type . '_ERR_STYLE_NAME']; - } - - if ($mode === 'theme' || $mode === 'template') + if (in_array($dir, $installed_dirs)) { - // a rather elaborate check we have to do here once to avoid trouble later - $check = "{$phpbb_root_path}styles/" . $style_row["{$mode}_path"] . (($mode === 'theme') ? '/theme/stylesheet.css' : '/template'); - if (($style_row["{$mode}_storedb"] != $store_db) && !$store_db && ($safe_mode || !phpbb_is_writable($check))) - { - $error[] = $user->lang['EDIT_' . strtoupper($mode) . '_STORED_DB']; - $store_db = 1; - } - - // themes which have to be parsed have to go into db - if ($mode == 'theme') - { - $cfg = parse_cfg_file("{$phpbb_root_path}styles/" . $style_row["{$mode}_path"] . "/theme/theme.cfg"); - - if (isset($cfg['parse_css_file']) && $cfg['parse_css_file'] && !$store_db) - { - $error[] = $user->lang['EDIT_THEME_STORE_PARSED']; - $store_db = 1; - } - } + // Style is already installed + continue; } - - if (!sizeof($error)) + $cfg = $this->read_style_cfg($dir); + if ($cfg === false) { - // Check length settings - if (utf8_strlen($name) > 30) - { - $error[] = $user->lang[$l_type . '_ERR_NAME_LONG']; - } - - if (utf8_strlen($copyright) > 60) - { - $error[] = $user->lang[$l_type . '_ERR_COPY_LONG']; - } + // Invalid style.cfg + continue; } - } - if ($update && sizeof($error)) - { - $style_row = array_merge($style_row, array( - 'template_id' => $template_id, - 'theme_id' => $theme_id, - 'imageset_id' => $imageset_id, - 'style_active' => $style_active, - $mode . '_storedb' => $store_db, - $mode . '_name' => $name, - $mode . '_copyright' => $copyright) + // Style should be available for installation + $parent = $cfg['parent']; + $style = array( + 'style_id' => 0, + 'style_name' => $cfg['name'], + 'style_copyright' => $cfg['copyright'], + 'style_active' => 0, + 'style_path' => $dir, + 'bbcode_bitfield' => $cfg['template_bitfield'], + 'style_parent_id' => 0, + 'style_parent_tree' => '', + // Extra values for styles list + // All extra variable start with _ so they won't be confused with data that can be added to styles table + '_inherit_name' => $parent, + '_available' => true, + '_note' => '', ); - } - - // User has submitted form and no errors have occurred - if ($update && !sizeof($error)) - { - $sql_ary = array( - $mode . '_name' => $name, - $mode . '_copyright' => $copyright - ); - - switch ($mode) - { - case 'style': - - $sql_ary += array( - 'template_id' => (int) $template_id, - 'theme_id' => (int) $theme_id, - 'imageset_id' => (int) $imageset_id, - 'style_active' => (int) $style_active, - ); - break; - - case 'imageset': - break; - - case 'theme': - - if ($style_row['theme_storedb'] != $store_db) - { - $theme_data = ''; - - if (!$style_row['theme_storedb']) - { - $theme_data = $this->db_theme_data($style_row); - } - else if (!$store_db && !$safe_mode && phpbb_is_writable("{$phpbb_root_path}styles/{$style_row['theme_path']}/theme/stylesheet.css")) - { - $store_db = 1; - $theme_data = $style_row['theme_data']; - - if ($fp = @fopen("{$phpbb_root_path}styles/{$style_row['theme_path']}/theme/stylesheet.css", 'wb')) - { - $store_db = (@fwrite($fp, str_replace("styles/{$style_row['theme_path']}/theme/", './', $theme_data))) ? 0 : 1; - } - fclose($fp); - } - - $sql_ary += array( - 'theme_mtime' => ($store_db) ? filemtime("{$phpbb_root_path}styles/{$style_row['theme_path']}/theme/stylesheet.css") : 0, - 'theme_storedb' => $store_db, - 'theme_data' => ($store_db) ? $theme_data : '', - ); - } - break; - - case 'template': - if ($style_row['template_storedb'] != $store_db) - { - if ($super = $this->get_super($mode, $style_row['template_id'])) - { - $error[] = (sprintf($user->lang["{$l_type}_INHERITS"], $super['template_name'])); - $sql_ary = array(); - } - else - { - if (!$store_db && !$safe_mode && phpbb_is_writable("{$phpbb_root_path}styles/{$style_row['template_path']}/template")) - { - $err = $this->store_in_fs('template', $style_row['template_id']); - if ($err) - { - $error += $err; - } - } - else if ($store_db) - { - $this->store_in_db('template', $style_row['template_id']); - } - else - { - // We no longer store within the db, but are also not able to update the file structure - // Since the admin want to switch this, we adhere to his decision. But we also need to remove the cache - $sql = 'DELETE FROM ' . STYLES_TEMPLATE_DATA_TABLE . " - WHERE template_id = $style_id"; - $db->sql_query($sql); - } - - $sql_ary += array( - 'template_storedb' => $store_db, - ); - } - } - break; - } - - if (sizeof($sql_ary)) + // Check style inheritance + if ($parent != '') { - $sql = "UPDATE $sql_from - SET " . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE {$mode}_id = $style_id"; - $db->sql_query($sql); - - // Making this the default style? - if ($mode == 'style' && $style_default) + if (isset($installed_names[$parent])) { - set_config('default_style', $style_id); + // Parent style is installed + $row = $installed_names[$parent]; + $style['style_parent_id'] = $row['id']; + $style['style_parent_tree'] = $row['tree']; } - } - - $cache->destroy('sql', STYLES_TABLE); - - add_log('admin', 'LOG_' . $l_type . '_EDIT_DETAILS', $name); - if (sizeof($error)) - { - trigger_error(implode('<br />', $error) . adm_back_link($this->u_action), E_USER_WARNING); - } - else - { - trigger_error($user->lang[$l_type . '_DETAILS_UPDATED'] . adm_back_link($this->u_action)); - } - } - - if ($mode == 'style') - { - foreach ($element_ary as $element => $table) - { - $sql = "SELECT {$element}_id, {$element}_name - FROM $table - ORDER BY {$element}_id ASC"; - $result = $db->sql_query($sql); - - ${$element . '_options'} = ''; - while ($row = $db->sql_fetchrow($result)) + else { - $selected = ($row[$element . '_id'] == $style_row[$element . '_id']) ? ' selected="selected"' : ''; - ${$element . '_options'} .= '<option value="' . $row[$element . '_id'] . '"' . $selected . '>' . $row[$element . '_name'] . '</option>'; + // Parent style is not installed yet + $style['_available'] = false; + $style['_note'] = sprintf($this->user->lang['REQUIRES_STYLE'], htmlspecialchars($parent)); } - $db->sql_freeresult($result); } - } - if ($mode == 'template') - { - $super = array(); - if (isset($style_row[$mode . '_inherits_id']) && $style_row['template_inherits_id']) + if ($all || $style['_available']) { - $super = $this->get_super($mode, $style_row['template_id']); + $styles[] = $style; } } - $this->page_title = 'EDIT_DETAILS_' . $l_type; - - $template->assign_vars(array( - 'S_DETAILS' => true, - 'S_ERROR_MSG' => (sizeof($error)) ? true : false, - 'S_STYLE' => ($mode == 'style') ? true : false, - 'S_TEMPLATE' => ($mode == 'template') ? true : false, - 'S_THEME' => ($mode == 'theme') ? true : false, - 'S_IMAGESET' => ($mode == 'imageset') ? true : false, - 'S_STORE_DB' => (isset($style_row[$mode . '_storedb'])) ? $style_row[$mode . '_storedb'] : 0, - 'S_STORE_DB_DISABLED' => (isset($style_row[$mode . '_inherits_id'])) ? $style_row[$mode . '_inherits_id'] : 0, - 'S_STYLE_ACTIVE' => (isset($style_row['style_active'])) ? $style_row['style_active'] : 0, - 'S_STYLE_DEFAULT' => (isset($style_row['style_default'])) ? $style_row['style_default'] : 0, - 'S_SUPERTEMPLATE' => (isset($style_row[$mode . '_inherits_id']) && $style_row[$mode . '_inherits_id']) ? $super['template_name'] : 0, - - 'S_TEMPLATE_OPTIONS' => ($mode == 'style') ? $template_options : '', - 'S_THEME_OPTIONS' => ($mode == 'style') ? $theme_options : '', - 'S_IMAGESET_OPTIONS' => ($mode == 'style') ? $imageset_options : '', - - 'U_ACTION' => $this->u_action . '&action=details&id=' . $style_id, - 'U_BACK' => $this->u_action, - - 'L_TITLE' => $user->lang[$this->page_title], - 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'], - 'L_NAME' => $user->lang[$l_type . '_NAME'], - 'L_LOCATION' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION'] : '', - 'L_LOCATION_EXPLAIN' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION_EXPLAIN'] : '', - - 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '', - 'NAME' => $style_row[$mode . '_name'], - 'COPYRIGHT' => $style_row[$mode . '_copyright'], - ) - ); + return $styles; } /** - * Load css file contents + * Show styles list + * + * @param array $styles styles list + * @param int $parent parent style id + * @param int $level style inheritance level */ - function load_css_file($path, $filename) + protected function show_styles_list(&$styles, $parent, $level) { - global $phpbb_root_path; - - $file = "{$phpbb_root_path}styles/$path/theme/$filename"; - - if (file_exists($file) && ($content = file_get_contents($file))) - { - $content = trim($content); - } - else - { - $content = ''; - } - if (defined('DEBUG')) + foreach ($styles as &$style) { - $content = "/* BEGIN @include $filename */ \n $content \n /* END @include $filename */ \n"; + if (empty($style['_shown']) && $style['style_parent_id'] == $parent) + { + $this->list_style($style, $level); + $this->show_styles_list($styles, $style['style_id'], $level + 1); + } } - - return $content; } /** - * Returns a string containing the value that should be used for the theme_data column in the theme database table. - * Includes contents of files loaded via @import - * - * @param array $theme_row is an associative array containing the theme's current database entry - * @param mixed $stylesheet can either be the new content for the stylesheet or false to load from the standard file - * @param string $root_path should only be used in case you want to use a different root path than "{$phpbb_root_path}styles/{$theme_row['theme_path']}" + * Show available styles tree * - * @return string Stylesheet data for theme_data column in the theme table + * @param array $styles Styles list, passed as reference + * @param string $name Name of parent style + * @param int $level Styles tree level */ - function db_theme_data($theme_row, $stylesheet = false, $root_path = '') + protected function show_available_child_styles(&$styles, $name, $level) { - global $phpbb_root_path; - - if (!$root_path) - { - $root_path = $phpbb_root_path . 'styles/' . $theme_row['theme_path']; - } - - if (!$stylesheet) - { - $stylesheet = ''; - if (file_exists($root_path . '/theme/stylesheet.css')) - { - $stylesheet = file_get_contents($root_path . '/theme/stylesheet.css'); - } - } - - // Match CSS imports - $matches = array(); - preg_match_all('/@import url\((["\'])(.*)\1\);/i', $stylesheet, $matches); - - // remove commented stylesheets (very simple parser, allows only whitespace - // around an @import statement) - preg_match_all('#/\*\s*@import url\((["\'])(.*)\1\);\s\*/#i', $stylesheet, $commented); - $matches[2] = array_diff($matches[2], $commented[2]); - - if (sizeof($matches)) + foreach ($styles as &$style) { - foreach ($matches[0] as $idx => $match) + if (empty($style['_shown']) && $style['_inherit_name'] == $name) { - if (isset($matches[2][$idx])) - { - $stylesheet = str_replace($match, acp_styles::load_css_file($theme_row['theme_path'], $matches[2][$idx]), $stylesheet); - } + $this->list_style($style, $level); + $this->show_available_child_styles($styles, $style['style_name'], $level + 1); } } - - // adjust paths - return str_replace('./', 'styles/' . $theme_row['theme_path'] . '/theme/', $stylesheet); } /** - * Store template files into db + * Update styles tree + * + * @param array $styles Styles list, passed as reference + * @param array|false $style Current style, false if root + * @return bool True if something was updated, false if not */ - function store_templates($mode, $style_id, $template_path, $filelist) + protected function update_styles_tree(&$styles, $style = false) { - global $phpbb_root_path, $phpEx, $db; - - $template_path = $template_path . '/template/'; - $includes = array(); - foreach ($filelist as $pathfile => $file_ary) + $parent_id = ($style === false) ? 0 : $style['style_id']; + $parent_tree = ($style === false) ? '' : ($style['style_parent_tree'] == '' ? '' : $style['style_parent_tree']) . $style['style_path']; + $update = false; + $updated = false; + foreach ($styles as &$row) { - foreach ($file_ary as $file) + if ($row['style_parent_id'] == $parent_id) { - if (!($fp = @fopen("{$phpbb_root_path}styles/$template_path$pathfile$file", 'r'))) - { - trigger_error("Could not open {$phpbb_root_path}styles/$template_path$pathfile$file", E_USER_ERROR); - } - - $filesize = filesize("{$phpbb_root_path}styles/$template_path$pathfile$file"); - - if ($filesize) + if ($row['style_parent_tree'] != $parent_tree) { - $template_data = fread($fp, $filesize); - } - - fclose($fp); - - if (!$filesize) - { - // File is empty - continue; - } - - if (preg_match_all('#<!-- INCLUDE (.*?\.html) -->#is', $template_data, $matches)) - { - foreach ($matches[1] as $match) - { - $includes[trim($match)][] = $file; - } + $row['style_parent_tree'] = $parent_tree; + $update = true; } + $updated |= $this->update_styles_tree($styles, $row); } } - - foreach ($filelist as $pathfile => $file_ary) + if ($update) { - foreach ($file_ary as $file) - { - // Skip index. - if (strpos($file, 'index.') === 0) - { - continue; - } - - // We could do this using extended inserts ... but that could be one - // heck of a lot of data ... - $sql_ary = array( - 'template_id' => (int) $style_id, - 'template_filename' => "$pathfile$file", - 'template_included' => (isset($includes[$file])) ? implode(':', $includes[$file]) . ':' : '', - 'template_mtime' => (int) filemtime("{$phpbb_root_path}styles/$template_path$pathfile$file"), - 'template_data' => (string) file_get_contents("{$phpbb_root_path}styles/$template_path$pathfile$file"), - ); - - if ($mode == 'insert') - { - $sql = 'INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - } - else - { - $sql = 'UPDATE ' . STYLES_TEMPLATE_DATA_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE template_id = $style_id - AND template_filename = '" . $db->sql_escape("$pathfile$file") . "'"; - } - $db->sql_query($sql); - } + $sql = 'UPDATE ' . STYLES_TABLE . " + SET style_parent_tree = '" . $this->db->sql_escape($parent_tree) . "' + WHERE style_parent_id = {$parent_id}"; + $this->db->sql_query($sql); + $updated = true; } + return $updated; } /** - * Returns an array containing all template filenames for one template that are currently cached. - * - * @param string $template_path contains the name of the template's folder in /styles/ + * Find all possible parent styles for style * - * @return array of filenames that exist in /styles/$template_path/template/ (without extension!) + * @param array $styles list of styles + * @param int $id id of style + * @param int $parent current parent style id + * @param int $level current tree level + * @return array Style ids, names and levels */ - function template_cache_filelist($template_path) + protected function find_possible_parents($styles, $id = -1, $parent = 0, $level = 0) { - global $phpbb_root_path, $phpEx, $user; - - $cache_prefix = 'tpl_' . str_replace('_', '-', $template_path); - - if (!($dp = @opendir("{$phpbb_root_path}cache"))) - { - trigger_error($user->lang['TEMPLATE_ERR_CACHE_READ'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $file_ary = array(); - while ($file = readdir($dp)) - { - if ($file[0] == '.') - { - continue; - } - - if (is_file($phpbb_root_path . 'cache/' . $file) && (strpos($file, $cache_prefix) === 0)) - { - $file_ary[] = str_replace('.', '/', preg_replace('#^' . preg_quote($cache_prefix, '#') . '_(.*?)\.html\.' . $phpEx . '$#i', '\1', $file)); + $results = array(); + foreach ($styles as $style) + { + if ($style['style_id'] != $id && $style['style_parent_id'] == $parent) + { + $results[] = array( + 'style_id' => $style['style_id'], + 'style_name' => $style['style_name'], + 'style_path' => $style['style_path'], + 'style_parent_id' => $style['style_parent_id'], + 'style_parent_tree' => $style['style_parent_tree'], + 'level' => $level + ); + $results = array_merge($results, $this->find_possible_parents($styles, $id, $style['style_id'], $level + 1)); } } - closedir($dp); - - return $file_ary; + return $results; } /** - * Destroys cached versions of template files + * Show item in styles list * - * @param array $template_row contains the template's row in the STYLES_TEMPLATE_TABLE database table - * @param mixed $file_ary is optional and may contain an array of template file names which should be refreshed in the cache. - * The file names should be the original template file names and not the cache file names. + * @param array $style style row + * @param int $level style inheritance level */ - function clear_template_cache($template_row, $file_ary = false) + protected function list_style(&$style, $level) { - global $phpbb_root_path, $phpEx, $user; - - $cache_prefix = 'tpl_' . str_replace('_', '-', $template_row['template_path']); - - if (!$file_ary || !is_array($file_ary)) - { - $file_ary = $this->template_cache_filelist($template_row['template_path']); - $log_file_list = $user->lang['ALL_FILES']; - } - else + // Mark row as shown + if (!empty($style['_shown'])) { - $log_file_list = implode(', ', $file_ary); - } - - foreach ($file_ary as $file) - { - $file = str_replace('/', '.', $file); - - $file = "{$phpbb_root_path}cache/{$cache_prefix}_$file.html.$phpEx"; - if (file_exists($file) && is_file($file)) - { - @unlink($file); - } + return; } - unset($file_ary); - - add_log('admin', 'LOG_TEMPLATE_CACHE_CLEARED', $template_row['template_name'], $log_file_list); - } - - /** - * Install Style/Template/Theme/Imageset - */ - function install($mode) - { - global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template; - - $l_type = strtoupper($mode); - $error = $installcfg = $style_row = array(); - $root_path = $cfg_file = ''; - $element_ary = array('template' => STYLES_TEMPLATE_TABLE, 'theme' => STYLES_THEME_TABLE, 'imageset' => STYLES_IMAGESET_TABLE); - - $install_path = request_var('path', ''); - $update = (isset($_POST['update'])) ? true : false; + $style['_shown'] = true; + + // Generate template variables + $actions = array(); + $row = array( + // Style data + 'STYLE_ID' => $style['style_id'], + 'STYLE_NAME' => htmlspecialchars($style['style_name']), + 'STYLE_PATH' => htmlspecialchars($style['style_path']), + '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'] : '', + 'LEVEL' => $level, + 'PADDING' => (4 + 16 * $level), + 'SHOW_COPYRIGHT' => ($style['style_id']) ? false : true, + 'STYLE_PATH_FULL' => htmlspecialchars($this->styles_path_absolute . '/' . $style['style_path']) . '/', + + // Comment to show below style + 'COMMENT' => (isset($style['_note'])) ? $style['_note'] : '', + + // The following variables should be used by hooks to add custom HTML code + 'EXTRA' => '', + 'EXTRA_OPTIONS' => '' + ); - // Installing, obtain cfg file contents - if ($install_path) + // Status specific data + if ($style['style_id']) { - $root_path = $phpbb_root_path . 'styles/' . $install_path . '/'; - $cfg_file = ($mode == 'style') ? "$root_path$mode.cfg" : "$root_path$mode/$mode.cfg"; - - if (!file_exists($cfg_file)) - { - $error[] = $user->lang[$l_type . '_ERR_NOT_' . $l_type]; - } - else - { - $installcfg = parse_cfg_file($cfg_file); - } - } + // Style is installed - // Installing - if (sizeof($installcfg)) - { - $name = $installcfg['name']; - $copyright = $installcfg['copyright']; - $version = $installcfg['version']; - - $style_row = array( - $mode . '_id' => 0, - $mode . '_name' => '', - $mode . '_copyright' => '' + // Details + $actions[] = array( + 'U_ACTION' => $this->u_action . '&action=details&id=' . $style['style_id'], + 'L_ACTION' => $this->user->lang['DETAILS'] ); - switch ($mode) - { - case 'style': - - $style_row = array( - 'style_id' => 0, - 'style_name' => $installcfg['name'], - 'style_copyright' => $installcfg['copyright'] - ); - - $reqd_template = (isset($installcfg['required_template'])) ? $installcfg['required_template'] : false; - $reqd_theme = (isset($installcfg['required_theme'])) ? $installcfg['required_theme'] : false; - $reqd_imageset = (isset($installcfg['required_imageset'])) ? $installcfg['required_imageset'] : false; - - // Check to see if each element is already installed, if it is grab the id - foreach ($element_ary as $element => $table) - { - $style_row = array_merge($style_row, array( - $element . '_id' => 0, - $element . '_name' => '', - $element . '_copyright' => '') - ); - - $this->test_installed($element, $error, (${'reqd_' . $element}) ? $phpbb_root_path . 'styles/' . $reqd_template . '/' : $root_path, ${'reqd_' . $element}, $style_row[$element . '_id'], $style_row[$element . '_name'], $style_row[$element . '_copyright']); - - if (!$style_row[$element . '_name']) - { - $style_row[$element . '_name'] = $reqd_template; - } - - // Merge other information to installcfg... if present - $cfg_file = $phpbb_root_path . 'styles/' . $install_path . '/' . $element . '/' . $element . '.cfg'; + // Activate/Deactive + $action_name = ($style['style_active'] ? 'de' : '') . 'activate'; - if (file_exists($cfg_file)) - { - $cfg_contents = parse_cfg_file($cfg_file); - - // Merge only specific things. We may need them later. - foreach (array('inherit_from', 'parse_css_file') as $key) - { - if (!empty($cfg_contents[$key]) && !isset($installcfg[$key])) - { - $installcfg[$key] = $cfg_contents[$key]; - } - } - } - } - - break; + $actions[] = array( + 'U_ACTION' => $this->u_action . '&action=' . $action_name . '&hash=' . generate_link_hash($action_name) . '&id=' . $style['style_id'], + 'L_ACTION' => $this->user->lang['STYLE_' . ($style['style_active'] ? 'DE' : '') . 'ACTIVATE'] + ); - case 'template': - $this->test_installed('template', $error, $root_path, false, $style_row['template_id'], $style_row['template_name'], $style_row['template_copyright']); - break; +/* // Export + $actions[] = array( + 'U_ACTION' => $this->u_action . '&action=export&hash=' . generate_link_hash('export') . '&id=' . $style['style_id'], + 'L_ACTION' => $this->user->lang['EXPORT'] + ); */ - case 'theme': - $this->test_installed('theme', $error, $root_path, false, $style_row['theme_id'], $style_row['theme_name'], $style_row['theme_copyright']); - break; + // Uninstall + $actions[] = array( + 'U_ACTION' => $this->u_action . '&action=uninstall&hash=' . generate_link_hash('uninstall') . '&id=' . $style['style_id'], + 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL'] + ); - case 'imageset': - $this->test_installed('imageset', $error, $root_path, false, $style_row['imageset_id'], $style_row['imageset_name'], $style_row['imageset_copyright']); - break; - } + // Preview + $actions[] = array( + 'U_ACTION' => append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'style=' . $style['style_id']), + 'L_ACTION' => $this->user->lang['PREVIEW'] + ); } else { - trigger_error($user->lang['NO_' . $l_type] . adm_back_link($this->u_action), E_USER_WARNING); - } - - $style_row['store_db'] = request_var('store_db', 0); - $style_row['style_active'] = request_var('style_active', 1); - $style_row['style_default'] = request_var('style_default', 0); - - // User has submitted form and no errors have occurred - if ($update && !sizeof($error)) - { - if ($mode == 'style') + // Style is not installed + if (empty($style['_available'])) { - foreach ($element_ary as $element => $table) - { - ${$element . '_root_path'} = (${'reqd_' . $element}) ? $phpbb_root_path . 'styles/' . ${'reqd_' . $element} . '/' : false; - ${$element . '_path'} = (${'reqd_' . $element}) ? ${'reqd_' . $element} : false; - } - $this->install_style($error, 'install', $root_path, $style_row['style_id'], $style_row['style_name'], $install_path, $style_row['style_copyright'], $style_row['style_active'], $style_row['style_default'], $style_row, $template_root_path, $template_path, $theme_root_path, $theme_path, $imageset_root_path, $imageset_path); + $actions[] = array( + 'HTML' => $this->user->lang['CANNOT_BE_INSTALLED'] + ); } else { - $style_row['store_db'] = $this->install_element($mode, $error, 'install', $root_path, $style_row[$mode . '_id'], $style_row[$mode . '_name'], $install_path, $style_row[$mode . '_copyright'], $style_row['store_db']); + $actions[] = array( + 'U_ACTION' => $this->u_action . '&action=install&hash=' . generate_link_hash('install') . '&dir=' . urlencode($style['style_path']), + 'L_ACTION' => $this->user->lang['INSTALL_STYLE'] + ); } + } - if (!sizeof($error)) - { - $cache->destroy('sql', STYLES_TABLE); + // todo: add hook - $message = ($style_row['store_db']) ? '_ADDED_DB' : '_ADDED'; - trigger_error($user->lang[$l_type . $message] . adm_back_link($this->u_action)); - } + // Assign template variables + $this->template->assign_block_vars('styles_list', $row); + foreach($actions as $action) + { + $this->template->assign_block_vars('styles_list.actions', $action); } - $this->page_title = 'INSTALL_' . $l_type; - - $template->assign_vars(array( - 'S_DETAILS' => true, - 'S_INSTALL' => true, - 'S_ERROR_MSG' => (sizeof($error)) ? true : false, - 'S_LOCATION' => (isset($installcfg['inherit_from']) && $installcfg['inherit_from']) ? false : true, - 'S_STYLE' => ($mode == 'style') ? true : false, - 'S_TEMPLATE' => ($mode == 'template') ? true : false, - 'S_SUPERTEMPLATE' => (isset($installcfg['inherit_from'])) ? $installcfg['inherit_from'] : '', - 'S_THEME' => ($mode == 'theme') ? true : false, - - 'S_STORE_DB' => (isset($style_row[$mode . '_storedb'])) ? $style_row[$mode . '_storedb'] : 0, - 'S_STYLE_ACTIVE' => (isset($style_row['style_active'])) ? $style_row['style_active'] : 0, - 'S_STYLE_DEFAULT' => (isset($style_row['style_default'])) ? $style_row['style_default'] : 0, - - 'U_ACTION' => $this->u_action . "&action=install&path=" . urlencode($install_path), - 'U_BACK' => $this->u_action, - - 'L_TITLE' => $user->lang[$this->page_title], - 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'], - 'L_NAME' => $user->lang[$l_type . '_NAME'], - 'L_LOCATION' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION'] : '', - 'L_LOCATION_EXPLAIN' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION_EXPLAIN'] : '', - - 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '', - 'NAME' => $style_row[$mode . '_name'], - 'COPYRIGHT' => $style_row[$mode . '_copyright'], - 'TEMPLATE_NAME' => ($mode == 'style') ? $style_row['template_name'] : '', - 'THEME_NAME' => ($mode == 'style') ? $style_row['theme_name'] : '', - 'IMAGESET_NAME' => ($mode == 'style') ? $style_row['imageset_name'] : '') - ); + // Increase counters + $counter = ($style['style_id']) ? ($style['style_active'] ? 'active' : 'inactive') : (empty($style['_available']) ? 'cannotinstall' : 'caninstall'); + if (!isset($this->style_counters)) + { + $this->style_counters = array( + 'total' => 0, + 'active' => 0, + 'inactive' => 0, + 'caninstall' => 0, + 'cannotinstall' => 0 + ); + } + $this->style_counters[$counter]++; + $this->style_counters['total']++; } /** - * Add new style + * Show welcome message + * + * @param string $title main title + * @param string $description page description */ - function add($mode) + protected function welcome_message($title, $description) { - global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template; - - $l_type = strtoupper($mode); - $element_ary = array('template' => STYLES_TEMPLATE_TABLE, 'theme' => STYLES_THEME_TABLE, 'imageset' => STYLES_IMAGESET_TABLE); - $error = array(); - - $style_row = array( - $mode . '_name' => utf8_normalize_nfc(request_var('name', '', true)), - $mode . '_copyright' => utf8_normalize_nfc(request_var('copyright', '', true)), - 'template_id' => 0, - 'theme_id' => 0, - 'imageset_id' => 0, - 'store_db' => request_var('store_db', 0), - 'style_active' => request_var('style_active', 1), - 'style_default' => request_var('style_default', 0), + $this->template->assign_vars(array( + 'L_TITLE' => $this->user->lang[$title], + 'L_EXPLAIN' => (isset($this->user->lang[$description])) ? $this->user->lang[$description] : '' + ) ); + } - $basis = request_var('basis', 0); - $update = (isset($_POST['update'])) ? true : false; - - if ($basis) - { - switch ($mode) - { - case 'style': - $sql_select = 'template_id, theme_id, imageset_id'; - $sql_from = STYLES_TABLE; - break; - - case 'template': - $sql_select = 'template_id'; - $sql_from = STYLES_TEMPLATE_TABLE; - break; - - case 'theme': - $sql_select = 'theme_id'; - $sql_from = STYLES_THEME_TABLE; - break; - - case 'imageset': - $sql_select = 'imageset_id'; - $sql_from = STYLES_IMAGESET_TABLE; - break; - } - - $sql = "SELECT $sql_select - FROM $sql_from - WHERE {$mode}_id = $basis"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - $error[] = $user->lang['NO_' . $l_type]; - } - - if (!sizeof($error)) - { - $style_row['template_id'] = (isset($row['template_id'])) ? $row['template_id'] : $style_row['template_id']; - $style_row['theme_id'] = (isset($row['theme_id'])) ? $row['theme_id'] : $style_row['theme_id']; - $style_row['imageset_id'] = (isset($row['imageset_id'])) ? $row['imageset_id'] : $style_row['imageset_id']; - } - } - - if ($update) - { - $style_row['template_id'] = request_var('template_id', $style_row['template_id']); - $style_row['theme_id'] = request_var('theme_id', $style_row['theme_id']); - $style_row['imageset_id'] = request_var('imageset_id', $style_row['imageset_id']); - - if ($mode == 'style' && (!$style_row['template_id'] || !$style_row['theme_id'] || !$style_row['imageset_id'])) - { - $error[] = $user->lang['STYLE_ERR_NO_IDS']; - } - } - - // User has submitted form and no errors have occurred - if ($update && !sizeof($error)) - { - if ($mode == 'style') - { - $style_row['style_id'] = 0; - - $this->install_style($error, 'add', '', $style_row['style_id'], $style_row['style_name'], '', $style_row['style_copyright'], $style_row['style_active'], $style_row['style_default'], $style_row); - } - - if (!sizeof($error)) - { - $cache->destroy('sql', STYLES_TABLE); - - $message = ($style_row['store_db']) ? '_ADDED_DB' : '_ADDED'; - trigger_error($user->lang[$l_type . $message] . adm_back_link($this->u_action)); - } - } + /** + * Find all directories that have styles + * + * @return array Directory names + */ + protected function find_style_dirs() + { + $styles = array(); - if ($mode == 'style') + $dp = @opendir($this->styles_path); + if ($dp) { - foreach ($element_ary as $element => $table) + while (($file = readdir($dp)) !== false) { - $sql = "SELECT {$element}_id, {$element}_name - FROM $table - ORDER BY {$element}_id ASC"; - $result = $db->sql_query($sql); + $dir = $this->styles_path . $file; + if ($file[0] == '.' || !is_dir($dir)) + { + continue; + } - ${$element . '_options'} = ''; - while ($row = $db->sql_fetchrow($result)) + if (file_exists("{$dir}/style.cfg")) { - $selected = ($row[$element . '_id'] == $style_row[$element . '_id']) ? ' selected="selected"' : ''; - ${$element . '_options'} .= '<option value="' . $row[$element . '_id'] . '"' . $selected . '>' . $row[$element . '_name'] . '</option>'; + $styles[] = $file; } - $db->sql_freeresult($result); } + closedir($dp); } - $this->page_title = 'ADD_' . $l_type; - - $template->assign_vars(array( - 'S_DETAILS' => true, - 'S_ADD' => true, - 'S_ERROR_MSG' => (sizeof($error)) ? true : false, - 'S_STYLE' => ($mode == 'style') ? true : false, - 'S_TEMPLATE' => ($mode == 'template') ? true : false, - 'S_THEME' => ($mode == 'theme') ? true : false, - 'S_BASIS' => ($basis) ? true : false, - - 'S_STORE_DB' => (isset($style_row['storedb'])) ? $style_row['storedb'] : 0, - 'S_STYLE_ACTIVE' => (isset($style_row['style_active'])) ? $style_row['style_active'] : 0, - 'S_STYLE_DEFAULT' => (isset($style_row['style_default'])) ? $style_row['style_default'] : 0, - 'S_TEMPLATE_OPTIONS' => ($mode == 'style') ? $template_options : '', - 'S_THEME_OPTIONS' => ($mode == 'style') ? $theme_options : '', - 'S_IMAGESET_OPTIONS' => ($mode == 'style') ? $imageset_options : '', - - 'U_ACTION' => $this->u_action . '&action=add&basis=' . $basis, - 'U_BACK' => $this->u_action, - - 'L_TITLE' => $user->lang[$this->page_title], - 'L_EXPLAIN' => $user->lang[$this->page_title . '_EXPLAIN'], - 'L_NAME' => $user->lang[$l_type . '_NAME'], - 'L_LOCATION' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION'] : '', - 'L_LOCATION_EXPLAIN' => ($mode == 'template' || $mode == 'theme') ? $user->lang[$l_type . '_LOCATION_EXPLAIN'] : '', - - 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '', - 'NAME' => $style_row[$mode . '_name'], - 'COPYRIGHT' => $style_row[$mode . '_copyright']) - ); - + return $styles; } /** - - $reqd_template = (isset($installcfg['required_template'])) ? $installcfg['required_template'] : false; - $reqd_theme = (isset($installcfg['required_theme'])) ? $installcfg['required_theme'] : false; - $reqd_imageset = (isset($installcfg['required_imageset'])) ? $installcfg['required_imageset'] : false; - - // Check to see if each element is already installed, if it is grab the id - foreach ($element_ary as $element => $table) - { - $style_row = array_merge($style_row, array( - $element . '_id' => 0, - $element . '_name' => '', - $element . '_copyright' => '') - ); - - $this->test_installed($element, $error, $root_path, ${'reqd_' . $element}, $style_row[$element . '_id'], $style_row[$element . '_name'], $style_row[$element . '_copyright']); - * Is this element installed? If not, grab its cfg details + * Sort styles */ - function test_installed($element, &$error, $root_path, $reqd_name, &$id, &$name, &$copyright) + public function sort_styles($style1, $style2) { - global $db, $user; - - switch ($element) + if ($style1['style_active'] != $style2['style_active']) { - case 'template': - $sql_from = STYLES_TEMPLATE_TABLE; - break; - - case 'theme': - $sql_from = STYLES_THEME_TABLE; - break; - - case 'imageset': - $sql_from = STYLES_IMAGESET_TABLE; - break; + return ($style1['style_active']) ? -1 : 1; } - - $l_element = strtoupper($element); - - $chk_name = ($reqd_name !== false) ? $reqd_name : $name; - - $sql = "SELECT {$element}_id, {$element}_name - FROM $sql_from - WHERE {$element}_name = '" . $db->sql_escape($chk_name) . "'"; - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) + if (isset($style1['_available']) && $style1['_available'] != $style2['_available']) { - $name = $row[$element . '_name']; - $id = $row[$element . '_id']; - } - else - { - if (!($cfg = @file("$root_path$element/$element.cfg"))) - { - $error[] = sprintf($user->lang['REQUIRES_' . $l_element], $reqd_name); - return false; - } - - $cfg = parse_cfg_file("$root_path$element/$element.cfg", $cfg); - - $name = $cfg['name']; - $copyright = $cfg['copyright']; - $id = 0; - - unset($cfg); + return ($style1['_available']) ? -1 : 1; } - $db->sql_freeresult($result); + return strcasecmp(isset($style1['style_name']) ? $style1['style_name'] : $style1['name'], isset($style2['style_name']) ? $style2['style_name'] : $style2['name']); } /** - * Install/Add style + * Read style configuration file + * + * @param string $dir style directory + * @return array|bool Style data, false on error */ - function install_style(&$error, $action, $root_path, &$id, $name, $path, $copyright, $active, $default, &$style_row, $template_root_path = false, $template_path = false, $theme_root_path = false, $theme_path = false, $imageset_root_path = false, $imageset_path = false) + protected function read_style_cfg($dir) { - global $config, $db, $user; - - $element_ary = array('template', 'theme', 'imageset'); - - if (!$name) - { - $error[] = $user->lang['STYLE_ERR_STYLE_NAME']; - } - - // Check length settings - if (utf8_strlen($name) > 30) - { - $error[] = $user->lang['STYLE_ERR_NAME_LONG']; - } - - if (utf8_strlen($copyright) > 60) - { - $error[] = $user->lang['STYLE_ERR_COPY_LONG']; - } - - // Check if the name already exist - $sql = 'SELECT style_id - FROM ' . STYLES_TABLE . " - WHERE style_name = '" . $db->sql_escape($name) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $error[] = $user->lang['STYLE_ERR_NAME_EXIST']; - } - - if (sizeof($error)) - { - return false; - } + static $required = array('name', 'phpbb_version', 'copyright'); + $cfg = parse_cfg_file($this->styles_path . $dir . '/style.cfg'); - foreach ($element_ary as $element) + // Check if it is a valid file + foreach ($required as $key) { - // Zero id value ... need to install element ... run usual checks - // and do the install if necessary - if (!$style_row[$element . '_id']) + if (!isset($cfg[$key])) { - $this->install_element($element, $error, $action, (${$element . '_root_path'}) ? ${$element . '_root_path'} : $root_path, $style_row[$element . '_id'], $style_row[$element . '_name'], (${$element . '_path'}) ? ${$element . '_path'} : $path, $style_row[$element . '_copyright']); + return false; } } - if (!$style_row['template_id'] || !$style_row['theme_id'] || !$style_row['imageset_id']) + // Check data + if (!isset($cfg['parent']) || !is_string($cfg['parent']) || $cfg['parent'] == $cfg['name']) { - $error[] = $user->lang['STYLE_ERR_NO_IDS']; + $cfg['parent'] = ''; } - - if (sizeof($error)) + if (!isset($cfg['template_bitfield'])) { - return false; + $cfg['template_bitfield'] = $this->default_bitfield(); } - $db->sql_transaction('begin'); - - $sql_ary = array( - 'style_name' => $name, - 'style_copyright' => $copyright, - 'style_active' => (int) $active, - 'template_id' => (int) $style_row['template_id'], - 'theme_id' => (int) $style_row['theme_id'], - 'imageset_id' => (int) $style_row['imageset_id'], - ); - - $sql = 'INSERT INTO ' . STYLES_TABLE . ' - ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - - $id = $db->sql_nextid(); - - if ($default) - { - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_style = $id - WHERE user_style = " . $config['default_style']; - $db->sql_query($sql); - - set_config('default_style', $id); - } - - $db->sql_transaction('commit'); - - add_log('admin', 'LOG_STYLE_ADD', $name); + return $cfg; } /** - * Install/add an element, doing various checks as we go + * Install style + * + * @param array $style style data + * @return int Style id */ - function install_element($mode, &$error, $action, $root_path, &$id, $name, $path, $copyright, $store_db = 0) + protected function install_style($style) { - global $phpbb_root_path, $db, $user; - - // we parse the cfg here (again) - $cfg_data = parse_cfg_file("$root_path$mode/$mode.cfg"); - - switch ($mode) - { - case 'template': - $sql_from = STYLES_TEMPLATE_TABLE; - break; - - case 'theme': - $sql_from = STYLES_THEME_TABLE; - break; - - case 'imageset': - $sql_from = STYLES_IMAGESET_TABLE; - break; - } - - $l_type = strtoupper($mode); - - if (!$name) - { - $error[] = $user->lang[$l_type . '_ERR_STYLE_NAME']; - } - - // Check length settings - if (utf8_strlen($name) > 30) - { - $error[] = $user->lang[$l_type . '_ERR_NAME_LONG']; - } - - if (utf8_strlen($copyright) > 60) + // Generate row + $sql_ary = array(); + foreach ($style as $key => $value) { - $error[] = $user->lang[$l_type . '_ERR_COPY_LONG']; - } - - // Check if the name already exist - $sql = "SELECT {$mode}_id - FROM $sql_from - WHERE {$mode}_name = '" . $db->sql_escape($name) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - // If it exist, we just use the style on installation - if ($action == 'install') + if ($key != 'style_id' && substr($key, 0, 1) != '_') { - $id = $row[$mode . '_id']; - return false; + $sql_ary[$key] = $value; } - - $error[] = $user->lang[$l_type . '_ERR_NAME_EXIST']; - } - - if (isset($cfg_data['inherit_from']) && $cfg_data['inherit_from']) - { - if ($mode === 'template') - { - $select_bf = ', bbcode_bitfield'; - } - else - { - $select_bf = ''; - } - - $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path, {$mode}_storedb $select_bf - FROM $sql_from - WHERE {$mode}_name = '" . $db->sql_escape($cfg_data['inherit_from']) . "' - AND {$mode}_inherits_id = 0"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - if (!$row) - { - $error[] = sprintf($user->lang[$l_type . '_ERR_REQUIRED_OR_INCOMPLETE'], $cfg_data['inherit_from']); - } - else - { - $inherit_id = $row["{$mode}_id"]; - $inherit_path = $row["{$mode}_path"]; - $inherit_bf = ($mode === 'template') ? $row["bbcode_bitfield"] : false; - $cfg_data['store_db'] = $row["{$mode}_storedb"]; - $store_db = $row["{$mode}_storedb"]; - } - } - else - { - $inherit_id = 0; - $inherit_path = ''; - $inherit_bf = false; - } - - if (sizeof($error)) - { - return false; - } - - $sql_ary = array( - $mode . '_name' => $name, - $mode . '_copyright' => $copyright, - $mode . '_path' => $path, - ); - - switch ($mode) - { - case 'template': - // We check if the template author defined a different bitfield - if (!empty($cfg_data['template_bitfield'])) - { - $sql_ary['bbcode_bitfield'] = $cfg_data['template_bitfield']; - } - else if ($inherit_bf) - { - $sql_ary['bbcode_bitfield'] = $inherit_bf; - } - else - { - $sql_ary['bbcode_bitfield'] = TEMPLATE_BITFIELD; - } - - // We set a pre-defined bitfield here which we may use further in 3.2 - $sql_ary += array( - 'template_storedb' => $store_db, - ); - if (isset($cfg_data['inherit_from']) && $cfg_data['inherit_from']) - { - $sql_ary += array( - 'template_inherits_id' => $inherit_id, - 'template_inherit_path' => $inherit_path, - ); - } - break; - - case 'theme': - // We are only interested in the theme configuration for now - - if (isset($cfg_data['parse_css_file']) && $cfg_data['parse_css_file']) - { - $store_db = 1; - } - - $sql_ary += array( - 'theme_storedb' => $store_db, - 'theme_data' => ($store_db) ? $this->db_theme_data($sql_ary, false, $root_path) : '', - 'theme_mtime' => (int) filemtime("{$phpbb_root_path}styles/$path/theme/stylesheet.css") - ); - break; - - // all the heavy lifting is done later - case 'imageset': - break; - } - - $db->sql_transaction('begin'); - - $sql = "INSERT INTO $sql_from - " . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - - $id = $db->sql_nextid(); - - if ($mode == 'template' && $store_db) - { - $filelist = filelist("{$root_path}template", '', 'html'); - $this->store_templates('insert', $id, $path, $filelist); } - else if ($mode == 'imageset') - { - $cfg_data = parse_cfg_file("$root_path$mode/imageset.cfg"); - $imageset_definitions = array(); - foreach ($this->imageset_keys as $topic => $key_array) - { - $imageset_definitions = array_merge($imageset_definitions, $key_array); - } + // Add to database + $this->db->sql_transaction('begin'); - foreach ($cfg_data as $key => $value) - { - if (strpos($value, '*') !== false) - { - if (substr($value, -1, 1) === '*') - { - list($image_filename, $image_height) = explode('*', $value); - $image_width = 0; - } - else - { - list($image_filename, $image_height, $image_width) = explode('*', $value); - } - } - else - { - $image_filename = $value; - $image_height = $image_width = 0; - } - - if (strpos($key, 'img_') === 0 && $image_filename) - { - $key = substr($key, 4); - if (in_array($key, $imageset_definitions)) - { - $sql_ary = array( - 'image_name' => $key, - 'image_filename' => str_replace('{PATH}', "styles/$path/imageset/", trim($image_filename)), - 'image_height' => (int) $image_height, - 'image_width' => (int) $image_width, - 'imageset_id' => (int) $id, - 'image_lang' => '', - ); - $db->sql_query('INSERT INTO ' . STYLES_IMAGESET_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - } - } - } - unset($cfg_data); + $sql = 'INSERT INTO ' . STYLES_TABLE . ' + ' . $this->db->sql_build_array('INSERT', $sql_ary); + $this->db->sql_query($sql); - $sql = 'SELECT lang_dir - FROM ' . LANG_TABLE; - $result = $db->sql_query($sql); + $id = $this->db->sql_nextid(); - while ($row = $db->sql_fetchrow($result)) - { - if (@file_exists("$root_path$mode/{$row['lang_dir']}/imageset.cfg")) - { - $cfg_data_imageset_data = parse_cfg_file("$root_path$mode/{$row['lang_dir']}/imageset.cfg"); - foreach ($cfg_data_imageset_data as $image_name => $value) - { - if (strpos($value, '*') !== false) - { - if (substr($value, -1, 1) === '*') - { - list($image_filename, $image_height) = explode('*', $value); - $image_width = 0; - } - else - { - list($image_filename, $image_height, $image_width) = explode('*', $value); - } - } - else - { - $image_filename = $value; - $image_height = $image_width = 0; - } + $this->db->sql_transaction('commit'); - if (strpos($image_name, 'img_') === 0 && $image_filename) - { - $image_name = substr($image_name, 4); - if (in_array($image_name, $imageset_definitions)) - { - $sql_ary = array( - 'image_name' => $image_name, - 'image_filename' => $image_filename, - 'image_height' => (int) $image_height, - 'image_width' => (int) $image_width, - 'imageset_id' => (int) $id, - 'image_lang' => $row['lang_dir'], - ); - $db->sql_query('INSERT INTO ' . STYLES_IMAGESET_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - } - } - } - unset($cfg_data_imageset_data); - } - } - $db->sql_freeresult($result); - } + add_log('admin', 'LOG_STYLE_ADD', $sql_ary['style_name']); - $db->sql_transaction('commit'); - - $log = ($store_db) ? 'LOG_' . $l_type . '_ADD_DB' : 'LOG_' . $l_type . '_ADD_FS'; - add_log('admin', $log, $name); - - // Return store_db in case it had to be altered - return $store_db; + return $id; } /** - * Checks downwards dependencies + * Lists all styles * - * @access public - * @param string $mode The element type to check - only template is supported - * @param int $id The template id - * @returns false if no component inherits, array with name, path and id for each subtemplate otherwise + * @return array Rows with styles data */ - function check_inheritance($mode, $id) + protected function get_styles() { - global $db; - - $l_type = strtoupper($mode); - - switch ($mode) - { - case 'template': - $sql_from = STYLES_TEMPLATE_TABLE; - break; + $sql = 'SELECT * + FROM ' . STYLES_TABLE; + $result = $this->db->sql_query($sql); - case 'theme': - $sql_from = STYLES_THEME_TABLE; - break; + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); - case 'imageset': - $sql_from = STYLES_IMAGESET_TABLE; - break; - } + return $rows; + } - $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path - FROM $sql_from - WHERE {$mode}_inherits_id = " . (int) $id; - $result = $db->sql_query($sql); + /** + * Count users for each style + * + * @return array Styles in following format: [style_id] = number of users + */ + protected function get_users() + { + $sql = 'SELECT user_style, COUNT(user_style) AS style_count + FROM ' . USERS_TABLE . ' + GROUP BY user_style'; + $result = $this->db->sql_query($sql); - $names = array(); - while ($row = $db->sql_fetchrow($result)) + $style_count = array(); + while ($row = $this->db->sql_fetchrow($result)) { - - $names[$row["{$mode}_id"]] = array( - "{$mode}_id" => $row["{$mode}_id"], - "{$mode}_name" => $row["{$mode}_name"], - "{$mode}_path" => $row["{$mode}_path"], - ); + $style_count[$row['user_style']] = $row['style_count']; } - $db->sql_freeresult($result); + $this->db->sql_freeresult($result); - if (sizeof($names)) - { - return $names; - } - else - { - return false; - } + return $style_count; } /** - * Checks upwards dependencies + * Uninstall style * - * @access public - * @param string $mode The element type to check - only template is supported - * @param int $id The template id - * @returns false if the component does not inherit, array with name, path and id otherwise + * @param array $style Style data + * @return bool|string True on success, error message on error */ - function get_super($mode, $id) + protected function uninstall_style($style) { - global $db; - - $l_type = strtoupper($mode); - - switch ($mode) - { - case 'template': - $sql_from = STYLES_TEMPLATE_TABLE; - break; + $id = $style['style_id']; + $path = $style['style_path']; - case 'theme': - $sql_from = STYLES_THEME_TABLE; - break; - - case 'imageset': - $sql_from = STYLES_IMAGESET_TABLE; - break; - } + // Check if style has child styles + $sql = 'SELECT style_id + FROM ' . STYLES_TABLE . ' + WHERE style_parent_id = ' . (int) $id . " OR style_parent_tree = '" . $this->db->sql_escape($path) . "'"; + $result = $this->db->sql_query($sql); - $sql = "SELECT {$mode}_inherits_id - FROM $sql_from - WHERE {$mode}_id = " . (int) $id; - $result = $db->sql_query_limit($sql, 1); + $conflict = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); - if ($row = $db->sql_fetchrow($result)) - { - $db->sql_freeresult($result); - } - else + if ($conflict !== false) { - return false; + return sprintf($this->user->lang['STYLE_UNINSTALL_DEPENDENT'], $style['style_name']); } - $super_id = $row["{$mode}_inherits_id"]; - - $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path - FROM $sql_from - WHERE {$mode}_id = " . (int) $super_id; - - $result = $db->sql_query_limit($sql, 1); - if ($row = $db->sql_fetchrow($result)) - { - $db->sql_freeresult($result); - return $row; - } + // Change default style for users + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_style = 0 + WHERE user_style = ' . $id; + $this->db->sql_query($sql); - return false; + // Uninstall style + $sql = 'DELETE FROM ' . STYLES_TABLE . ' + WHERE style_id = ' . $id; + $this->db->sql_query($sql); + return true; } /** - * Moves a template set and its subtemplates to the database + * Delete all files in style directory * - * @access public - * @param string $mode The component to move - only template is supported - * @param int $id The template id + * @param string $path Style directory + * @param string $dir Directory to remove inside style's directory + * @return bool True on success, false on error */ - function store_in_db($mode, $id) + protected function delete_style_files($path, $dir = '') { - global $db, $user; + $dirname = $this->styles_path . $path . $dir; + $result = true; - $error = array(); - $l_type = strtoupper($mode); - if ($super = $this->get_super($mode, $id)) - { - $error[] = (sprintf($user->lang["{$l_type}_INHERITS"], $super['template_name'])); - return $error; - } + $dp = @opendir($dirname); - $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path - FROM " . STYLES_TEMPLATE_TABLE . ' - WHERE template_id = ' . (int) $id; - - $result = $db->sql_query_limit($sql, 1); - if ($row = $db->sql_fetchrow($result)) + if ($dp) { - $db->sql_freeresult($result); - $subs = $this->check_inheritance($mode, $id); - - $this->_store_in_db($mode, $id, $row["{$mode}_path"]); - if ($subs && sizeof($subs)) + while (($file = readdir($dp)) !== false) { - foreach ($subs as $sub_id => $sub) + if ($file == '.' || $file == '..') + { + continue; + } + $filename = $dirname . '/' . $file; + if (is_dir($filename)) + { + if (!$this->delete_style_files($path, $dir . '/' . $file)) + { + $result = false; + } + } + else { - if ($err = $this->_store_in_db($mode, $sub["{$mode}_id"], $sub["{$mode}_path"])) + if (!@unlink($filename)) { - $error[] = $err; + $result = false; } } } + closedir($dp); } - if (sizeof($error)) + if (!@rmdir($dirname)) { - return $error; + return false; } - return false; - } - - /** - * Moves a template set to the database - * - * @access private - * @param string $mode The component to move - only template is supported - * @param int $id The template id - * @param string $path TThe path to the template files - */ - function _store_in_db($mode, $id, $path) - { - global $phpbb_root_path, $db; - - $filelist = filelist("{$phpbb_root_path}styles/{$path}/template", '', 'html'); - $this->store_templates('insert', $id, $path, $filelist); - - // Okay, we do the query here -shouldn't be triggered often. - $sql = 'UPDATE ' . STYLES_TEMPLATE_TABLE . ' - SET template_storedb = 1 - WHERE template_id = ' . $id; - $db->sql_query($sql); + return $result; } /** - * Moves a template set and its subtemplates to the filesystem + * Get list of items from posted data * - * @access public - * @param string $mode The component to move - only template is supported - * @param int $id The template id + * @param string $name Variable name + * @param string|int $default Default value for array + * @param bool $error If true, error will be triggered if list is empty + * @return array Items */ - function store_in_fs($mode, $id) + protected function request_vars($name, $default, $error = false) { - global $db, $user; + $item = $this->request->variable($name, $default); + $items = $this->request->variable($name . 's', array($default)); - $error = array(); - $l_type = strtoupper($mode); - if ($super = $this->get_super($mode, $id)) + if (count($items) == 1 && $items[0] == $default) { - $error[] = (sprintf($user->lang["{$l_type}_INHERITS"], $super['template_name'])); - return($error); + $items = array(); } - $sql = "SELECT {$mode}_id, {$mode}_name, {$mode}_path - FROM " . STYLES_TEMPLATE_TABLE . ' - WHERE template_id = ' . (int) $id; - - $result = $db->sql_query_limit($sql, 1); - if ($row = $db->sql_fetchrow($result)) + if ($item != $default && !count($items)) { - $db->sql_freeresult($result); - if (!sizeof($error)) - { - $subs = $this->check_inheritance($mode, $id); - - $this->_store_in_fs($mode, $id, $row["{$mode}_path"]); + $items[] = $item; + } - if ($subs && sizeof($subs)) - { - foreach ($subs as $sub_id => $sub) - { - $this->_store_in_fs($mode, $sub["{$mode}_id"], $sub["{$mode}_path"]); - } - } - } - if (sizeof($error)) - { - $this->store_in_db($id, $mode); - return $error; - } + if ($error && !count($items)) + { + trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); } - return false; + + return $items; } /** - * Moves a template set to the filesystem + * Generates default bitfield + * + * This bitfield decides which bbcodes are defined in a template. * - * @access private - * @param string $mode The component to move - only template is supported - * @param int $id The template id - * @param string $path The path to the template + * @return string Bitfield */ - function _store_in_fs($mode, $id, $path) + protected function default_bitfield() { - global $phpbb_root_path, $db, $user, $safe_mode; - - $store_db = 0; - $error = array(); - if (!$safe_mode && phpbb_is_writable("{$phpbb_root_path}styles/{$path}/template")) + static $value; + if (isset($value)) { - $sql = 'SELECT * - FROM ' . STYLES_TEMPLATE_DATA_TABLE . " - WHERE template_id = $id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!($fp = @fopen("{$phpbb_root_path}styles/{$path}/template/" . $row['template_filename'], 'wb'))) - { - $store_db = 1; - $error[] = $user->lang['EDIT_TEMPLATE_STORED_DB']; - break; - } - - fwrite($fp, $row['template_data']); - fclose($fp); - } - $db->sql_freeresult($result); - - if (!$store_db) - { - $sql = 'DELETE FROM ' . STYLES_TEMPLATE_DATA_TABLE . " - WHERE template_id = $id"; - $db->sql_query($sql); - } + return $value; } - if (sizeof($error)) - { - return $error; - } - $sql = 'UPDATE ' . STYLES_TEMPLATE_TABLE . ' - SET template_storedb = 0 - WHERE template_id = ' . $id; - $db->sql_query($sql); - return false; + // Hardcoded template bitfield to add for new templates + $bitfield = new bitfield(); + $bitfield->set(0); + $bitfield->set(1); + $bitfield->set(2); + $bitfield->set(3); + $bitfield->set(4); + $bitfield->set(8); + $bitfield->set(9); + $bitfield->set(11); + $bitfield->set(12); + $value = $bitfield->get_base64(); + return $value; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_update.php b/phpBB/includes/acp/acp_update.php index 87d5c51b56..0167a06dbb 100644 --- a/phpBB/includes/acp/acp_update.php +++ b/phpBB/includes/acp/acp_update.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,72 +19,48 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_update { var $u_action; function main($id, $mode) { - global $config, $db, $user, $auth, $template, $cache; - global $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $config, $user, $template, $request; + global $phpbb_root_path, $phpEx, $phpbb_container; $user->add_lang('install'); $this->tpl_name = 'acp_update'; $this->page_title = 'ACP_VERSION_CHECK'; - // Get current and latest version - $info = htmlspecialchars(obtain_latest_version_info(request_var('versioncheck_force', false))); - - if (empty($info)) + $version_helper = $phpbb_container->get('version_helper'); + try { - trigger_error('VERSIONCHECK_FAIL', E_USER_WARNING); + $recheck = $request->variable('versioncheck_force', false); + $updates_available = $version_helper->get_suggested_updates($recheck); } + catch (\RuntimeException $e) + { + $template->assign_var('S_VERSIONCHECK_FAIL', true); - $info = explode("\n", $info); - $latest_version = trim($info[0]); - - $announcement_url = trim($info[1]); - $announcement_url = (strpos($announcement_url, '&') === false) ? str_replace('&', '&', $announcement_url) : $announcement_url; - $update_link = append_sid($phpbb_root_path . 'install/index.' . $phpEx, 'mode=update'); + $updates_available = array(); + } - // next feature release - $next_feature_version = $next_feature_announcement_url = false; - if (isset($info[2]) && trim($info[2]) !== '') + foreach ($updates_available as $branch => $version_data) { - $next_feature_version = trim($info[2]); - $next_feature_announcement_url = trim($info[3]); + $template->assign_block_vars('updates_available', $version_data); } - // Determine automatic update... - $sql = 'SELECT config_value - FROM ' . CONFIG_TABLE . " - WHERE config_name = 'version_update_from'"; - $result = $db->sql_query($sql); - $version_update_from = (string) $db->sql_fetchfield('config_value'); - $db->sql_freeresult($result); - - $current_version = (!empty($version_update_from)) ? $version_update_from : $config['version']; + $update_link = append_sid($phpbb_root_path . 'install/index.' . $phpEx, 'mode=update'); $template->assign_vars(array( - 'S_UP_TO_DATE' => phpbb_version_compare($latest_version, $config['version'], '<='), - 'S_UP_TO_DATE_AUTO' => phpbb_version_compare($latest_version, $current_version, '<='), - 'S_VERSION_CHECK' => true, - 'U_ACTION' => $this->u_action, - 'U_VERSIONCHECK_FORCE' => append_sid($this->u_action . '&versioncheck_force=1'), + 'S_UP_TO_DATE' => empty($updates_available), + 'U_ACTION' => $this->u_action, + 'U_VERSIONCHECK_FORCE' => append_sid($this->u_action . '&versioncheck_force=1'), - 'LATEST_VERSION' => $latest_version, - 'CURRENT_VERSION' => $config['version'], - 'AUTO_VERSION' => $version_update_from, - 'NEXT_FEATURE_VERSION' => $next_feature_version, + 'CURRENT_VERSION' => $config['version'], - 'UPDATE_INSTRUCTIONS' => sprintf($user->lang['UPDATE_INSTRUCTIONS'], $announcement_url, $update_link), - 'UPGRADE_INSTRUCTIONS' => $next_feature_version ? $user->lang('UPGRADE_INSTRUCTIONS', $next_feature_version, $next_feature_announcement_url) : false, + 'UPDATE_INSTRUCTIONS' => sprintf($user->lang['UPDATE_INSTRUCTIONS'], $update_link), )); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index b82be8887c..8c17fb6311 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,9 +19,6 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package acp -*/ class acp_users { var $u_action; @@ -33,10 +33,11 @@ class acp_users { global $config, $db, $user, $auth, $template, $cache; global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads; + global $phpbb_dispatcher, $request; + global $phpbb_container; $user->add_lang(array('posting', 'ucp', 'acp/users')); $this->tpl_name = 'acp_users'; - $this->page_title = 'ACP_USER_' . strtoupper($mode); $error = array(); $username = utf8_normalize_nfc(request_var('username', '', true)); @@ -56,7 +57,7 @@ class acp_users $this->page_title = 'WHOIS'; $this->tpl_name = 'simple_body'; - $user_ip = request_var('user_ip', ''); + $user_ip = phpbb_ip_normalise(request_var('user_ip', '')); $domain = gethostbyaddr($user_ip); $ipwhois = user_ipwhois($user_ip); @@ -120,7 +121,7 @@ class acp_users // Build modes dropdown list $sql = 'SELECT module_mode, module_auth FROM ' . MODULES_TABLE . " - WHERE module_basename = 'users' + WHERE module_basename = 'acp_users' AND module_enabled = 1 AND module_class = 'acp' ORDER BY left_id, module_mode"; @@ -129,7 +130,7 @@ class acp_users $dropdown_modes = array(); while ($row = $db->sql_fetchrow($result)) { - if (!$this->p_master->module_auth($row['module_auth'])) + if (!$this->p_master->module_auth_self($row['module_auth'])) { continue; } @@ -158,6 +159,8 @@ class acp_users trigger_error($user->lang['NOT_MANAGE_FOUNDER'] . adm_back_link($this->u_action), E_USER_WARNING); } + $this->page_title = $user_row['username'] . ' :: ' . $user->lang('ACP_USER_' . strtoupper($mode)); + switch ($mode) { case 'overview': @@ -170,6 +173,21 @@ class acp_users $delete_type = request_var('delete_type', ''); $ip = request_var('ip', 'ip'); + /** + * Run code at beginning of ACP users overview + * + * @event core.acp_users_overview_before + * @var array user_row Current user data + * @var string mode Active module + * @var string action Module that should be run + * @var bool submit Do we display the form only + * or did the user press submit + * @var array error Array holding error messages + * @since 3.1.3-RC1 + */ + $vars = array('user_row', 'mode', 'action', 'submit', 'error'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_overview_before', compact($vars))); + if ($submit) { if ($delete) @@ -351,7 +369,7 @@ class acp_users $messenger->template($email_template, $user_row['user_lang']); - $messenger->to($user_row['user_email'], $user_row['username']); + $messenger->set_addresses($user_row); $messenger->anti_abuse_headers($config, $user); @@ -400,13 +418,16 @@ class acp_users { if ($config['require_activation'] == USER_ACTIVATION_ADMIN) { + $phpbb_notifications = $phpbb_container->get('notification_manager'); + $phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_row['user_id']); + include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); $messenger = new messenger(false); $messenger->template('admin_welcome_activated', $user_row['user_lang']); - $messenger->to($user_row['user_email'], $user_row['username']); + $messenger->set_addresses($user_row); $messenger->anti_abuse_headers($config, $user); @@ -459,23 +480,9 @@ class acp_users trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } - $sql_ary = array( - 'user_avatar' => '', - 'user_avatar_type' => 0, - 'user_avatar_width' => 0, - 'user_avatar_height' => 0, - ); - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - // Delete old avatar if present - if ($user_row['user_avatar'] && $user_row['user_avatar_type'] != AVATAR_GALLERY) - { - avatar_delete('user', $user_row); - } + $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $phpbb_avatar_manager->clean_row($user_row, 'user'), USERS_TABLE, 'user_'); add_log('admin', 'LOG_USER_DEL_AVATAR', $user_row['username']); add_log('user', $user_id, 'LOG_USER_DEL_AVATAR_USER'); @@ -626,29 +633,32 @@ class acp_users $topic_id_ary = $move_topic_ary = $move_post_ary = $new_topic_id_ary = array(); $forum_id_ary = array($new_forum_id); - $sql = 'SELECT topic_id, COUNT(post_id) AS total_posts + $sql = 'SELECT topic_id, post_visibility, COUNT(post_id) AS total_posts FROM ' . POSTS_TABLE . " WHERE poster_id = $user_id AND forum_id <> $new_forum_id - GROUP BY topic_id"; + GROUP BY topic_id, post_visibility"; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - $topic_id_ary[$row['topic_id']] = $row['total_posts']; + $topic_id_ary[$row['topic_id']][$row['post_visibility']] = $row['total_posts']; } $db->sql_freeresult($result); if (sizeof($topic_id_ary)) { - $sql = 'SELECT topic_id, forum_id, topic_title, topic_replies, topic_replies_real, topic_attachment + $sql = 'SELECT topic_id, forum_id, topic_title, topic_posts_approved, topic_posts_unapproved, topic_posts_softdeleted, topic_attachment FROM ' . TOPICS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', array_keys($topic_id_ary)); $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - if (max($row['topic_replies'], $row['topic_replies_real']) + 1 == $topic_id_ary[$row['topic_id']]) + if ($topic_id_ary[$row['topic_id']][ITEM_APPROVED] == $row['topic_posts_approved'] + && $topic_id_ary[$row['topic_id']][ITEM_UNAPPROVED] == $row['topic_posts_unapproved'] + && $topic_id_ary[$row['topic_id']][ITEM_REAPPROVE] == $row['topic_posts_unapproved'] + && $topic_id_ary[$row['topic_id']][ITEM_DELETED] == $row['topic_posts_softdeleted']) { $move_topic_ary[] = $row['topic_id']; } @@ -681,7 +691,7 @@ class acp_users 'topic_time' => time(), 'forum_id' => $new_forum_id, 'icon_id' => 0, - 'topic_approved' => 1, + 'topic_visibility' => ITEM_APPROVED, 'topic_title' => $post_ary['title'], 'topic_first_poster_name' => $user_row['username'], 'topic_type' => POST_NORMAL, @@ -726,7 +736,6 @@ class acp_users sync('forum', 'forum_id', $forum_id_ary, false, true); } - add_log('admin', 'LOG_USER_MOVE_POSTS', $user_row['username'], $forum_info['forum_name']); add_log('user', $user_id, 'LOG_USER_MOVE_POSTS_USER', $forum_info['forum_name']); @@ -755,6 +764,19 @@ class acp_users } break; + + default: + /** + * Run custom quicktool code + * + * @event core.acp_users_overview_run_quicktool + * @var array user_row Current user data + * @var string action Quick tool that should be run + * @since 3.1.0-a1 + */ + $vars = array('action', 'user_row'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_overview_run_quicktool', compact($vars))); + break; } // Handle registration info updates @@ -762,9 +784,8 @@ class acp_users 'username' => utf8_normalize_nfc(request_var('user', $user_row['username'], true)), 'user_founder' => request_var('user_founder', ($user_row['user_type'] == USER_FOUNDER) ? 1 : 0), 'email' => strtolower(request_var('user_email', $user_row['user_email'])), - 'email_confirm' => strtolower(request_var('email_confirm', '')), - 'new_password' => request_var('new_password', '', true), - 'password_confirm' => request_var('password_confirm', '', true), + 'new_password' => $request->variable('new_password', '', true), + 'password_confirm' => $request->variable('password_confirm', '', true), ); // Validation data - we do not check the password complexity setting here @@ -792,9 +813,8 @@ class acp_users $check_ary += array( 'email' => array( array('string', false, 6, 60), - array('email', $user_row['user_email']) + array('user_email', $user_row['user_email']), ), - 'email_confirm' => array('string', true, 6, 60) ); } @@ -805,19 +825,17 @@ class acp_users $error[] = 'NEW_PASSWORD_ERROR'; } - if ($data['email'] != $user_row['user_email'] && $data['email_confirm'] != $data['email']) - { - $error[] = 'NEW_EMAIL_ERROR'; - } - if (!check_form_key($form_name)) { $error[] = 'FORM_INVALID'; } + // Instantiate passwords manager + $passwords_manager = $phpbb_container->get('passwords.manager'); + // Which updates do we need to do? $update_username = ($user_row['username'] != $data['username']) ? $data['username'] : false; - $update_password = ($data['new_password'] && !phpbb_check_hash($data['new_password'], $user_row['user_password'])) ? true : false; + $update_password = $data['new_password'] && !$passwords_manager->check($data['new_password'], $user_row['user_password']); $update_email = ($data['email'] != $user_row['user_email']) ? $data['email'] : false; if (!sizeof($error)) @@ -868,6 +886,18 @@ class acp_users } } + /** + * Modify user data before we update it + * + * @event core.acp_users_overview_modify_data + * @var array user_row Current user data + * @var array data Submitted user data + * @var array sql_ary User data we udpate + * @since 3.1.0-a1 + */ + $vars = array('user_row', 'data', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_overview_modify_data', compact($vars))); + if ($update_username !== false) { $sql_ary['username'] = $update_username; @@ -889,9 +919,8 @@ class acp_users if ($update_password) { $sql_ary += array( - 'user_password' => phpbb_hash($data['new_password']), + 'user_password' => $passwords_manager->hash($data['new_password']), 'user_passchg' => time(), - 'user_pass_convert' => 0, ); $user->reset_login_keys($user_id); @@ -920,7 +949,7 @@ class acp_users } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); } if ($user_id == $user->data['user_id']) @@ -958,12 +987,6 @@ class acp_users } } - $s_action_options = '<option class="sep" value="">' . $user->lang['SELECT_OPTION'] . '</option>'; - foreach ($quick_tool_ary as $value => $lang) - { - $s_action_options .= '<option value="' . $value . '">' . $user->lang['USER_ADMIN_' . $lang] . '</option>'; - } - if ($config['load_onlinetrack']) { $sql = 'SELECT MAX(session_time) AS session_time, MIN(session_viewonline) AS session_viewonline @@ -978,7 +1001,24 @@ class acp_users unset($row); } - $last_visit = (!empty($user_row['session_time'])) ? $user_row['session_time'] : $user_row['user_lastvisit']; + /** + * Add additional quick tool options and overwrite user data + * + * @event core.acp_users_display_overview + * @var array user_row Array with user data + * @var array quick_tool_ary Ouick tool options + * @since 3.1.0-a1 + */ + $vars = array('user_row', 'quick_tool_ary'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_display_overview', compact($vars))); + + $s_action_options = '<option class="sep" value="">' . $user->lang['SELECT_OPTION'] . '</option>'; + foreach ($quick_tool_ary as $value => $lang) + { + $s_action_options .= '<option value="' . $value . '">' . $user->lang['USER_ADMIN_' . $lang] . '</option>'; + } + + $last_active = (!empty($user_row['session_time'])) ? $user_row['session_time'] : $user_row['user_lastvisit']; $inactive_reason = ''; if ($user_row['user_type'] == USER_INACTIVE) @@ -1009,7 +1049,7 @@ class acp_users $sql = 'SELECT COUNT(post_id) as posts_in_queue FROM ' . POSTS_TABLE . ' WHERE poster_id = ' . $user_id . ' - AND post_approved = 0'; + AND ' . $db->sql_in_set('post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)); $result = $db->sql_query($sql); $user_row['posts_in_queue'] = (int) $db->sql_fetchfield('posts_in_queue'); $db->sql_freeresult($result); @@ -1022,8 +1062,8 @@ class acp_users $db->sql_freeresult($result); $template->assign_vars(array( - 'L_NAME_CHARS_EXPLAIN' => sprintf($user->lang[$config['allow_name_chars'] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), - 'L_CHANGE_PASSWORD_EXPLAIN' => sprintf($user->lang[$config['pass_complex'] . '_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), + 'L_NAME_CHARS_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), + 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars']), $user->lang('CHARACTERS', (int) $config['max_pass_chars'])), 'L_POSTS_IN_QUEUE' => $user->lang('NUM_POSTS_IN_QUEUE', $user_row['posts_in_queue']), 'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false, @@ -1045,7 +1085,7 @@ class acp_users 'USER' => $user_row['username'], 'USER_REGISTERED' => $user->format_date($user_row['user_regdate']), 'REGISTERED_IP' => ($ip == 'hostname') ? gethostbyaddr($user_row['user_ip']) : $user_row['user_ip'], - 'USER_LASTACTIVE' => ($last_visit) ? $user->format_date($last_visit) : ' - ', + 'USER_LASTACTIVE' => ($last_active) ? $user->format_date($last_active) : ' - ', 'USER_EMAIL' => $user_row['user_email'], 'USER_WARNINGS' => $user_row['user_warnings'], 'USER_POSTS' => $user_row['user_posts'], @@ -1065,6 +1105,7 @@ class acp_users $deleteall = (isset($_POST['delall'])) ? true : false; $marked = request_var('mark', array(0)); $message = utf8_normalize_nfc(request_var('message', '', true)); + $pagination = $phpbb_container->get('pagination'); // Sort keys $sort_days = request_var('st', 0); @@ -1134,10 +1175,11 @@ class acp_users $log_count = 0; $start = view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort); + $base_url = $this->u_action . "&u=$user_id&$u_sort_param"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); + $template->assign_vars(array( 'S_FEEDBACK' => true, - 'S_ON_PAGE' => on_page($log_count, $config['topics_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&u=$user_id&$u_sort_param", $log_count, $config['topics_per_page'], $start, true), 'S_LIMIT_DAYS' => $s_limit_days, 'S_SORT_KEY' => $s_sort_key, @@ -1210,17 +1252,13 @@ class acp_users WHERE user_id = $user_id"; $db->sql_query($sql); - switch ($log_warnings) + if ($log_warnings) { - case 2: - add_log('admin', 'LOG_WARNINGS_DELETED', $user_row['username'], $num_warnings); - break; - case 1: - add_log('admin', 'LOG_WARNING_DELETED', $user_row['username']); - break; - default: - add_log('admin', 'LOG_WARNINGS_DELETED_ALL', $user_row['username']); - break; + add_log('admin', 'LOG_WARNINGS_DELETED', $user_row['username'], $num_warnings); + } + else + { + add_log('admin', 'LOG_WARNINGS_DELETED_ALL', $user_row['username']); } } } @@ -1290,7 +1328,6 @@ class acp_users } } - $template->assign_block_vars('warn', array( 'ID' => $row['warning_id'], 'USERNAME' => ($row['log_operation']) ? get_username_string('full', $row['mod_user_id'], $row['mod_username'], $row['mod_user_colour']) : '-', @@ -1309,9 +1346,8 @@ class acp_users case 'profile': include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); - $cp = new custom_profile(); + $cp = $phpbb_container->get('profilefields.manager'); $cp_data = $cp_error = array(); @@ -1325,15 +1361,7 @@ class acp_users $user_row['iso_lang_id'] = $row['lang_id']; $data = array( - 'icq' => request_var('icq', $user_row['user_icq']), - 'aim' => request_var('aim', $user_row['user_aim']), - 'msn' => request_var('msn', $user_row['user_msnm']), - 'yim' => request_var('yim', $user_row['user_yim']), 'jabber' => utf8_normalize_nfc(request_var('jabber', $user_row['user_jabber'], true)), - 'website' => request_var('website', $user_row['user_website']), - 'location' => utf8_normalize_nfc(request_var('location', $user_row['user_from'], true)), - 'occupation' => utf8_normalize_nfc(request_var('occupation', $user_row['user_occ'], true)), - 'interests' => utf8_normalize_nfc(request_var('interests', $user_row['user_interests'], true)), 'bday_day' => 0, 'bday_month' => 0, 'bday_year' => 0, @@ -1349,25 +1377,25 @@ class acp_users $data['bday_year'] = request_var('bday_year', $data['bday_year']); $data['user_birthday'] = sprintf('%2d-%2d-%4d', $data['bday_day'], $data['bday_month'], $data['bday_year']); + /** + * Modify user data on editing profile in ACP + * + * @event core.acp_users_modify_profile + * @var array data Array with user profile data + * @var bool submit Flag indicating if submit button has been pressed + * @var int user_id The user id + * @var array user_row Array with the full user data + * @since 3.1.4-RC1 + */ + $vars = array('data', 'submit', 'user_id', 'user_row'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_modify_profile', compact($vars))); if ($submit) { $error = validate_data($data, array( - 'icq' => array( - array('string', true, 3, 15), - array('match', true, '#^[0-9]+$#i')), - 'aim' => array('string', true, 3, 255), - 'msn' => array('string', true, 5, 255), 'jabber' => array( array('string', true, 5, 255), array('jabber')), - 'yim' => array('string', true, 5, 255), - 'website' => array( - array('string', true, 12, 255), - array('match', true, '#^http[s]?://(.*?\.)*?[a-z0-9\-]+\.[a-z]{2,4}#i')), - 'location' => array('string', true, 2, 100), - 'occupation' => array('string', true, 2, 500), - 'interests' => array('string', true, 2, 500), 'bday_day' => array('num', true, 1, 31), 'bday_month' => array('num', true, 1, 12), 'bday_year' => array('num', true, 1901, gmdate('Y', time())), @@ -1386,21 +1414,39 @@ class acp_users $error[] = 'FORM_INVALID'; } + /** + * Validate profile data in ACP before submitting to the database + * + * @event core.acp_users_profile_validate + * @var bool submit Flag indicating if submit button has been pressed + * @var array data Array with user profile data + * @var array error Array with the form errors + * @since 3.1.4-RC1 + */ + $vars = array('submit', 'data', 'error'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_profile_validate', compact($vars))); + if (!sizeof($error)) { $sql_ary = array( - 'user_icq' => $data['icq'], - 'user_aim' => $data['aim'], - 'user_msnm' => $data['msn'], - 'user_yim' => $data['yim'], 'user_jabber' => $data['jabber'], - 'user_website' => $data['website'], - 'user_from' => $data['location'], - 'user_occ' => $data['occupation'], - 'user_interests'=> $data['interests'], 'user_birthday' => $data['user_birthday'], ); + /** + * Modify profile data in ACP before submitting to the database + * + * @event core.acp_users_profile_modify_sql_ary + * @var array cp_data Array with the user custom profile fields data + * @var array data Array with user profile data + * @var int user_id The user id + * @var array user_row Array with the full user data + * @var array sql_ary Array with sql data + * @since 3.1.4-RC1 + */ + $vars = array('cp_data', 'data', 'user_id', 'user_row', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_profile_modify_sql_ary', compact($vars))); + $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " WHERE user_id = $user_id"; @@ -1413,7 +1459,7 @@ class acp_users } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); } $s_birthday_day_options = '<option value="0"' . ((!$data['bday_day']) ? ' selected="selected"' : '') . '>--</option>'; @@ -1441,16 +1487,7 @@ class acp_users unset($now); $template->assign_vars(array( - 'ICQ' => $data['icq'], - 'YIM' => $data['yim'], - 'AIM' => $data['aim'], - 'MSN' => $data['msn'], 'JABBER' => $data['jabber'], - 'WEBSITE' => $data['website'], - 'LOCATION' => $data['location'], - 'OCCUPATION' => $data['occupation'], - 'INTERESTS' => $data['interests'], - 'S_BIRTHDAY_DAY_OPTIONS' => $s_birthday_day_options, 'S_BIRTHDAY_MONTH_OPTIONS' => $s_birthday_month_options, 'S_BIRTHDAY_YEAR_OPTIONS' => $s_birthday_year_options, @@ -1472,15 +1509,13 @@ class acp_users $data = array( 'dateformat' => utf8_normalize_nfc(request_var('dateformat', $user_row['user_dateformat'], true)), 'lang' => basename(request_var('lang', $user_row['user_lang'])), - 'tz' => request_var('tz', (float) $user_row['user_timezone']), + 'tz' => request_var('tz', $user_row['user_timezone']), 'style' => request_var('style', $user_row['user_style']), - 'dst' => request_var('dst', $user_row['user_dst']), 'viewemail' => request_var('viewemail', $user_row['user_allow_viewemail']), 'massemail' => request_var('massemail', $user_row['user_allow_massemail']), 'hideonline' => request_var('hideonline', !$user_row['user_allow_viewonline']), 'notifymethod' => request_var('notifymethod', $user_row['user_notify_type']), 'notifypm' => request_var('notifypm', $user_row['user_notify_pm']), - 'popuppm' => request_var('popuppm', $this->optionget($user_row, 'popuppm')), 'allowpm' => request_var('allowpm', $user_row['user_allow_pm']), 'topic_sk' => request_var('topic_sk', ($user_row['user_topic_sortby_type']) ? $user_row['user_topic_sortby_type'] : 't'), @@ -1504,12 +1539,23 @@ class acp_users 'notify' => request_var('notify', $user_row['user_notify']), ); + /** + * Modify users preferences data + * + * @event core.acp_users_prefs_modify_data + * @var array data Array with users preferences data + * @var array user_row Array with user data + * @since 3.1.0-b3 + */ + $vars = array('data', 'user_row'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_data', compact($vars))); + if ($submit) { $error = validate_data($data, array( 'dateformat' => array('string', false, 1, 30), 'lang' => array('match', false, '#^[a-z_\-]{2,}$#i'), - 'tz' => array('num', false, -14, 14), + 'tz' => array('timezone'), 'topic_sk' => array('string', false, 1, 1), 'topic_sd' => array('string', false, 1, 1), @@ -1524,7 +1570,6 @@ class acp_users if (!sizeof($error)) { - $this->optionset($user_row, 'popuppm', $data['popuppm']); $this->optionset($user_row, 'viewimg', $data['view_images']); $this->optionset($user_row, 'viewflash', $data['view_flash']); $this->optionset($user_row, 'viewsmilies', $data['view_smilies']); @@ -1545,7 +1590,6 @@ class acp_users 'user_notify_type' => $data['notifymethod'], 'user_notify_pm' => $data['notifypm'], - 'user_dst' => $data['dst'], 'user_dateformat' => $data['dateformat'], 'user_lang' => $data['lang'], 'user_timezone' => $data['tz'], @@ -1562,41 +1606,57 @@ class acp_users 'user_notify' => $data['notify'], ); - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - // Check if user has an active session - if ($user_row['session_id']) + /** + * Modify SQL query before users preferences are updated + * + * @event core.acp_users_prefs_modify_sql + * @var array data Array with users preferences data + * @var array user_row Array with user data + * @var array sql_ary SQL array with users preferences data to update + * @var array error Array with errors data + * @since 3.1.0-b3 + */ + $vars = array('data', 'user_row', 'sql_ary', 'error'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_sql', compact($vars))); + + if (!sizeof($error)) { - // We'll update the session if user_allow_viewonline has changed and the user is a bot - // Or if it's a regular user and the admin set it to hide the session - if ($user_row['user_allow_viewonline'] != $sql_ary['user_allow_viewonline'] && $user_row['user_type'] == USER_IGNORE - || $user_row['user_allow_viewonline'] && !$sql_ary['user_allow_viewonline']) + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " + WHERE user_id = $user_id"; + $db->sql_query($sql); + + // Check if user has an active session + if ($user_row['session_id']) { - // We also need to check if the user has the permission to cloak. - $user_auth = new auth(); - $user_auth->acl($user_row); + // We'll update the session if user_allow_viewonline has changed and the user is a bot + // Or if it's a regular user and the admin set it to hide the session + if ($user_row['user_allow_viewonline'] != $sql_ary['user_allow_viewonline'] && $user_row['user_type'] == USER_IGNORE + || $user_row['user_allow_viewonline'] && !$sql_ary['user_allow_viewonline']) + { + // We also need to check if the user has the permission to cloak. + $user_auth = new \phpbb\auth\auth(); + $user_auth->acl($user_row); - $session_sql_ary = array( - 'session_viewonline' => ($user_auth->acl_get('u_hideonline')) ? $sql_ary['user_allow_viewonline'] : true, - ); + $session_sql_ary = array( + 'session_viewonline' => ($user_auth->acl_get('u_hideonline')) ? $sql_ary['user_allow_viewonline'] : true, + ); - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $session_sql_ary) . " - WHERE session_user_id = $user_id"; - $db->sql_query($sql); + $sql = 'UPDATE ' . SESSIONS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $session_sql_ary) . " + WHERE session_user_id = $user_id"; + $db->sql_query($sql); - unset($user_auth); + unset($user_auth); + } } - } - trigger_error($user->lang['USER_PREFS_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['USER_PREFS_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); + } } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); } $dateformat_options = ''; @@ -1655,7 +1715,8 @@ class acp_users ${'s_sort_' . $sort_option . '_dir'} .= '</select>'; } - $template->assign_vars(array( + phpbb_timezone_select($template, $user, $data['tz'], true); + $user_prefs_data = array( 'S_PREFS' => true, 'S_JABBER_DISABLED' => ($config['jab_enable'] && $user_row['user_jabber'] && @extension_loaded('xml')) ? false : true, @@ -1667,8 +1728,6 @@ class acp_users 'NOTIFY_IM' => ($data['notifymethod'] == NOTIFY_IM) ? true : false, 'NOTIFY_BOTH' => ($data['notifymethod'] == NOTIFY_BOTH) ? true : false, 'NOTIFY_PM' => $data['notifypm'], - 'POPUP_PM' => $data['popuppm'], - 'DST' => $data['dst'], 'BBCODE' => $data['bbcode'], 'SMILIES' => $data['smilies'], 'ATTACH_SIG' => $data['sig'], @@ -1695,75 +1754,136 @@ class acp_users 'S_LANG_OPTIONS' => language_select($data['lang']), 'S_STYLE_OPTIONS' => style_select($data['style']), - 'S_TZ_OPTIONS' => tz_select($data['tz'], true), - ) ); + /** + * Modify users preferences data before assigning it to the template + * + * @event core.acp_users_prefs_modify_template_data + * @var array data Array with users preferences data + * @var array user_row Array with user data + * @var array user_prefs_data Array with users preferences data to be assigned to the template + * @since 3.1.0-b3 + */ + $vars = array('data', 'user_row', 'user_prefs_data'); + extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_template_data', compact($vars))); + + $template->assign_vars($user_prefs_data); + break; case 'avatar': include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false; + $avatars_enabled = false; - if ($submit) + if ($config['allow_avatar']) { + $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); + $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers(); - if (!check_form_key($form_name)) + // This is normalised data, without the user_ prefix + $avatar_data = \phpbb\avatar\manager::clean_row($user_row, 'user'); + + if ($submit) { + if (check_form_key($form_name)) + { + $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', '')); + + if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) + { + $driver = $phpbb_avatar_manager->get_driver($driver_name); + $result = $driver->process_form($request, $template, $user, $avatar_data, $error); + + if ($result && empty($error)) + { + // Success! Lets save the result in the database + $result = array( + 'user_avatar_type' => $driver_name, + 'user_avatar' => $result['avatar'], + 'user_avatar_width' => $result['avatar_width'], + 'user_avatar_height' => $result['avatar_height'], + ); + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $result) . ' + WHERE user_id = ' . (int) $user_id; + + $db->sql_query($sql); + trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); + } + } + } + else + { trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); + } } - if (avatar_process_user($error, $user_row, $can_upload)) + // Handle deletion of avatars + if ($request->is_set_post('avatar_delete')) { - trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_row['user_id'])); + if (!confirm_box(true)) + { + confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( + 'avatar_delete' => true)) + ); + } + else + { + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, USERS_TABLE, 'user_'); + + trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); + } } - // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); - } + $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user_row['user_avatar_type'])); - if (!$config['allow_avatar'] && $user_row['user_avatar_type']) - { - $error[] = $user->lang['USER_AVATAR_NOT_ALLOWED']; - } - else if ((($user_row['user_avatar_type'] == AVATAR_UPLOAD) && !$config['allow_avatar_upload']) || - (($user_row['user_avatar_type'] == AVATAR_REMOTE) && !$config['allow_avatar_remote']) || - (($user_row['user_avatar_type'] == AVATAR_GALLERY) && !$config['allow_avatar_local'])) - { - $error[] = $user->lang['USER_AVATAR_TYPE_NOT_ALLOWED']; - } + foreach ($avatar_drivers as $current_driver) + { + $driver = $phpbb_avatar_manager->get_driver($current_driver); - // Generate users avatar - $avatar_img = ($user_row['user_avatar']) ? get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height'], 'USER_AVATAR', true) : '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />'; + $avatars_enabled = true; + $config_name = $phpbb_avatar_manager->get_driver_config_name($driver); + $template->set_filenames(array( + 'avatar' => "acp_avatar_options_{$config_name}.html", + )); - $display_gallery = (isset($_POST['display_gallery'])) ? true : false; - $avatar_select = basename(request_var('avatar_select', '')); - $category = basename(request_var('category', '')); + if ($driver->prepare_form($request, $template, $user, $avatar_data, $error)) + { + $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); + $driver_upper = strtoupper($driver_name); - if ($config['allow_avatar_local'] && $display_gallery) - { - avatar_gallery($category, $avatar_select, 4); + $template->assign_block_vars('avatar_drivers', array( + 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), + 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), + + 'DRIVER' => $driver_name, + 'SELECTED' => $current_driver == $selected_driver, + 'OUTPUT' => $template->assign_display('avatar'), + )); + } + } } + // Replace "error" strings with their real, localised form + $error = $phpbb_avatar_manager->localize_errors($user, $error); + + $avatar = phpbb_get_user_avatar($user_row, 'USER_AVATAR', true); + $template->assign_vars(array( - 'S_AVATAR' => true, - 'S_CAN_UPLOAD' => $can_upload, - 'S_UPLOAD_FILE' => ($config['allow_avatar'] && $can_upload && $config['allow_avatar_upload']) ? true : false, - 'S_REMOTE_UPLOAD' => ($config['allow_avatar'] && $can_upload && $config['allow_avatar_remote_upload']) ? true : false, - 'S_ALLOW_REMOTE' => ($config['allow_avatar'] && $config['allow_avatar_remote']) ? true : false, - 'S_DISPLAY_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && !$display_gallery) ? true : false, - 'S_IN_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && $display_gallery) ? true : false, - - 'AVATAR_IMAGE' => $avatar_img, - 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'], - 'USER_AVATAR_WIDTH' => $user_row['user_avatar_width'], - 'USER_AVATAR_HEIGHT' => $user_row['user_avatar_height'], - - 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], round($config['avatar_filesize'] / 1024))) - ); + 'S_AVATAR' => true, + 'ERROR' => (!empty($error)) ? implode('<br />', $error) : '', + 'AVATAR' => (empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar), + + 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"', + + 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], $config['avatar_filesize'] / 1024), + + 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled), + )); break; @@ -1865,7 +1985,7 @@ class acp_users } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); } $signature_preview = ''; @@ -1895,7 +2015,7 @@ class acp_users 'FLASH_STATUS' => ($config['allow_sig_flash']) ? $user->lang['FLASH_IS_ON'] : $user->lang['FLASH_IS_OFF'], 'URL_STATUS' => ($config['allow_sig_links']) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'], - 'L_SIGNATURE_EXPLAIN' => sprintf($user->lang['SIGNATURE_EXPLAIN'], $config['max_sig_chars']), + 'L_SIGNATURE_EXPLAIN' => $user->lang('SIGNATURE_EXPLAIN', (int) $config['max_sig_chars']), 'S_BBCODE_ALLOWED' => $config['allow_sig_bbcode'], 'S_SMILIES_ALLOWED' => $config['allow_sig_smilies'], @@ -1914,6 +2034,7 @@ class acp_users $start = request_var('start', 0); $deletemark = (isset($_POST['delmarked'])) ? true : false; $marked = request_var('mark', array(0)); + $pagination = $phpbb_container->get('pagination'); // Sort keys $sort_key = request_var('sk', 'a'); @@ -1956,7 +2077,7 @@ class acp_users $message = (sizeof($log_attachments) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED']; - add_log('admin', 'LOG_ATTACHMENTS_DELETED', implode(', ', $log_attachments)); + add_log('admin', 'LOG_ATTACHMENTS_DELETED', implode($user->lang['COMMA_SEPARATOR'], $log_attachments)); trigger_error($message . adm_back_link($this->u_action . '&u=' . $user_id)); } else @@ -2049,14 +2170,14 @@ class acp_users } $db->sql_freeresult($result); + $base_url = $this->u_action . "&u=$user_id&sk=$sort_key&sd=$sort_dir"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $num_attachments, $config['topics_per_page'], $start); + $template->assign_vars(array( 'S_ATTACHMENTS' => true, - 'S_ON_PAGE' => on_page($num_attachments, $config['topics_per_page'], $start), 'S_SORT_KEY' => $s_sort_key, 'S_SORT_DIR' => $s_sort_dir, - - 'PAGINATION' => generate_pagination($this->u_action . "&u=$user_id&sk=$sort_key&sd=$sort_dir", $num_attachments, $config['topics_per_page'], $start, true)) - ); + )); break; @@ -2190,7 +2311,6 @@ class acp_users $error = array(); } - $sql = 'SELECT ug.*, g.* FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . " ug WHERE ug.user_id = $user_id @@ -2294,7 +2414,7 @@ class acp_users // Select auth options $sql = 'SELECT auth_option, is_local, is_global FROM ' . ACL_OPTIONS_TABLE . ' - WHERE auth_option ' . $db->sql_like_expression($db->any_char . '_') . ' + WHERE auth_option ' . $db->sql_like_expression($db->get_any_char() . '_') . ' AND is_global = 1 ORDER BY auth_option'; $result = $db->sql_query($sql); @@ -2314,7 +2434,7 @@ class acp_users { $sql = 'SELECT auth_option, is_local, is_global FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option " . $db->sql_like_expression($db->any_char . '_') . " + WHERE auth_option " . $db->sql_like_expression($db->get_any_char() . '_') . " AND is_local = 1 ORDER BY is_global DESC, auth_option"; $result = $db->sql_query($sql); @@ -2411,5 +2531,3 @@ class acp_users return phpbb_optionget($user->keyoptions[$key], $var); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_words.php b/phpBB/includes/acp/acp_words.php index 88c5bbe592..272d38bcc8 100644 --- a/phpBB/includes/acp/acp_words.php +++ b/phpBB/includes/acp/acp_words.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,7 +21,6 @@ if (!defined('IN_PHPBB')) /** * @todo [words] check regular expressions for special char replacements (stored specialchared in db) -* @package acp */ class acp_words { @@ -102,7 +104,7 @@ class acp_words 'word' => $word, 'replacement' => $replacement ); - + if ($word_id) { $db->sql_query('UPDATE ' . WORDS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE word_id = ' . $word_id); @@ -163,7 +165,6 @@ class acp_words break; } - $template->assign_vars(array( 'U_ACTION' => $this->u_action, 'S_HIDDEN_FIELDS' => $s_hidden_fields) @@ -186,5 +187,3 @@ class acp_words $db->sql_freeresult($result); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/auth.php b/phpBB/includes/acp/auth.php index 10d7973da6..905e981cdc 100644 --- a/phpBB/includes/acp/auth.php +++ b/phpBB/includes/acp/auth.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,9 +21,8 @@ if (!defined('IN_PHPBB')) /** * ACP Permission/Auth class -* @package phpBB3 */ -class auth_admin extends auth +class auth_admin extends \phpbb\auth\auth { /** * Init auth settings @@ -131,7 +133,7 @@ class auth_admin extends auth { if ($user->data['user_id'] != $userdata['user_id']) { - $auth2 = new auth(); + $auth2 = new \phpbb\auth\auth(); $auth2->acl($userdata); } else @@ -140,7 +142,6 @@ class auth_admin extends auth $auth2 = &$auth; } - $hold_ary[$userdata['user_id']] = array(); foreach ($forum_ids as $f_id) { @@ -182,7 +183,10 @@ class auth_admin extends auth } // Defining the user-function here to save some memory - $return_acl_fill = create_function('$value', 'return ' . $acl_fill . ';'); + $return_acl_fill = function () use ($acl_fill) + { + return $acl_fill; + }; // Actually fill the gaps if (sizeof($hold_ary)) @@ -262,7 +266,8 @@ class auth_admin extends auth */ function display_mask($mode, $permission_type, &$hold_ary, $user_mode = 'user', $local = false, $group_display = true) { - global $template, $user, $db, $phpbb_root_path, $phpEx; + global $template, $user, $db, $phpbb_root_path, $phpEx, $phpbb_container; + $phpbb_permissions = $phpbb_container->get('acl.permissions'); // Define names for template loops, might be able to be set $tpl_pmask = 'p_mask'; @@ -270,7 +275,7 @@ class auth_admin extends auth $tpl_category = 'category'; $tpl_mask = 'mask'; - $l_acl_type = (isset($user->lang['ACL_TYPE_' . (($local) ? 'LOCAL' : 'GLOBAL') . '_' . strtoupper($permission_type)])) ? $user->lang['ACL_TYPE_' . (($local) ? 'LOCAL' : 'GLOBAL') . '_' . strtoupper($permission_type)] : 'ACL_TYPE_' . (($local) ? 'LOCAL' : 'GLOBAL') . '_' . strtoupper($permission_type); + $l_acl_type = $phpbb_permissions->get_type_lang($permission_type, (($local) ? 'local' : 'global')); // Allow trace for viewing permissions and in user mode $show_trace = ($mode == 'view' && $user_mode == 'user') ? true : false; @@ -506,7 +511,7 @@ class auth_admin extends auth 'FORUM_ID' => $forum_id) ); - $this->assign_cat_array($ug_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, $show_trace, ($mode == 'view')); + $this->assign_cat_array($ug_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, ($mode == 'view'), $show_trace); unset($content_array[$ug_id]); } @@ -530,8 +535,8 @@ class auth_admin extends auth 'NAME' => $ug_name, 'CATEGORIES' => implode('</th><th>', $categories), - 'USER_GROUPS_DEFAULT' => ($user_mode == 'user' && isset($user_groups_default[$ug_id]) && sizeof($user_groups_default[$ug_id])) ? implode(', ', $user_groups_default[$ug_id]) : '', - 'USER_GROUPS_CUSTOM' => ($user_mode == 'user' && isset($user_groups_custom[$ug_id]) && sizeof($user_groups_custom[$ug_id])) ? implode(', ', $user_groups_custom[$ug_id]) : '', + 'USER_GROUPS_DEFAULT' => ($user_mode == 'user' && isset($user_groups_default[$ug_id]) && sizeof($user_groups_default[$ug_id])) ? implode($user->lang['COMMA_SEPARATOR'], $user_groups_default[$ug_id]) : '', + 'USER_GROUPS_CUSTOM' => ($user_mode == 'user' && isset($user_groups_custom[$ug_id]) && sizeof($user_groups_custom[$ug_id])) ? implode($user->lang['COMMA_SEPARATOR'], $user_groups_custom[$ug_id]) : '', 'L_ACL_TYPE' => $l_acl_type, 'S_LOCAL' => ($local) ? true : false, @@ -593,7 +598,7 @@ class auth_admin extends auth 'FORUM_ID' => $forum_id) ); - $this->assign_cat_array($forum_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, $show_trace, ($mode == 'view')); + $this->assign_cat_array($forum_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, ($mode == 'view'), $show_trace); } unset($hold_ary[$ug_id], $ug_names_ary[$ug_id]); @@ -649,9 +654,9 @@ class auth_admin extends auth { $template->assign_block_vars('role_mask.users', array( 'USER_ID' => $row['user_id'], - 'USERNAME' => $row['username'], - 'U_PROFILE' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=viewprofile&u={$row['user_id']}")) - ); + 'USERNAME' => get_username_string('username', $row['user_id'], $row['username']), + 'U_PROFILE' => get_username_string('profile', $row['user_id'], $row['username']), + )); } $db->sql_freeresult($result); } @@ -833,7 +838,7 @@ class auth_admin extends auth } // Remove current auth options... - $auth_option_ids = array((int)$any_option_id); + $auth_option_ids = array((int) $any_option_id); foreach ($auth as $auth_option => $auth_setting) { $auth_option_ids[] = (int) $this->acl_options['id'][$auth_option]; @@ -1022,7 +1027,7 @@ class auth_admin extends auth // Get permission type $sql = 'SELECT auth_option, auth_option_id FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option " . $db->sql_like_expression($permission_type . $db->any_char); + WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char()); $result = $db->sql_query($sql); $auth_id_ary = array(); @@ -1099,9 +1104,11 @@ class auth_admin extends auth * Assign category to template * used by display_mask() */ - function assign_cat_array(&$category_array, $tpl_cat, $tpl_mask, $ug_id, $forum_id, $show_trace = false, $s_view) + function assign_cat_array(&$category_array, $tpl_cat, $tpl_mask, $ug_id, $forum_id, $s_view, $show_trace = false) { - global $template, $user, $phpbb_admin_path, $phpEx; + global $template, $user, $phpbb_admin_path, $phpEx, $phpbb_container; + + $phpbb_permissions = $phpbb_container->get('acl.permissions'); @reset($category_array); while (list($cat, $cat_array) = each($category_array)) @@ -1111,8 +1118,8 @@ class auth_admin extends auth 'S_NEVER' => ($cat_array['S_NEVER'] && !$cat_array['S_YES'] && !$cat_array['S_NO']) ? true : false, 'S_NO' => ($cat_array['S_NO'] && !$cat_array['S_NEVER'] && !$cat_array['S_YES']) ? true : false, - 'CAT_NAME' => $user->lang['permission_cat'][$cat]) - ); + 'CAT_NAME' => $phpbb_permissions->get_category_lang($cat), + )); /* Sort permissions by name (more naturaly and user friendly than sorting by a primary key) * Commented out due to it's memory consumption and time needed @@ -1146,8 +1153,8 @@ class auth_admin extends auth 'U_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission") : '', 'UA_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '', - 'PERMISSION' => $user->lang['acl_' . $permission]['lang']) - ); + 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission), + )); } else { @@ -1164,8 +1171,8 @@ class auth_admin extends auth 'U_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission") : '', 'UA_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '', - 'PERMISSION' => $user->lang['acl_' . $permission]['lang']) - ); + 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission), + )); } } } @@ -1177,7 +1184,9 @@ class auth_admin extends auth */ function build_permission_array(&$permission_row, &$content_array, &$categories, $key_sort_array) { - global $user; + global $user, $phpbb_container; + + $phpbb_permissions = $phpbb_container->get('acl.permissions'); foreach ($key_sort_array as $forum_id) { @@ -1192,20 +1201,12 @@ class auth_admin extends auth @reset($permissions); while (list($permission, $auth_setting) = each($permissions)) { - if (!isset($user->lang['acl_' . $permission])) - { - $user->lang['acl_' . $permission] = array( - 'cat' => 'misc', - 'lang' => '{ acl_' . $permission . ' }' - ); - } - - $cat = $user->lang['acl_' . $permission]['cat']; + $cat = $phpbb_permissions->get_permission_category($permission); // Build our categories array if (!isset($categories[$cat])) { - $categories[$cat] = $user->lang['permission_cat'][$cat]; + $categories[$cat] = $phpbb_permissions->get_category_lang($cat); } // Build our content array @@ -1281,5 +1282,3 @@ class auth_admin extends auth return true; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_attachments.php b/phpBB/includes/acp/info/acp_attachments.php index b77785801f..ff6e342f77 100644 --- a/phpBB/includes/acp/info/acp_attachments.php +++ b/phpBB/includes/acp/info/acp_attachments.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_attachments_info { function module() @@ -23,7 +23,8 @@ class acp_attachments_info 'attach' => array('title' => 'ACP_ATTACHMENT_SETTINGS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_BOARD_CONFIGURATION', 'ACP_ATTACHMENTS')), 'extensions' => array('title' => 'ACP_MANAGE_EXTENSIONS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')), 'ext_groups' => array('title' => 'ACP_EXTENSION_GROUPS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')), - 'orphan' => array('title' => 'ACP_ORPHAN_ATTACHMENTS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')) + 'orphan' => array('title' => 'ACP_ORPHAN_ATTACHMENTS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')), + 'manage' => array('title' => 'ACP_MANAGE_ATTACHMENTS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')), ), ); } @@ -36,5 +37,3 @@ class acp_attachments_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_ban.php b/phpBB/includes/acp/info/acp_ban.php index df51011ec6..4959f4da41 100644 --- a/phpBB/includes/acp/info/acp_ban.php +++ b/phpBB/includes/acp/info/acp_ban.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_ban_info { function module() @@ -35,5 +35,3 @@ class acp_ban_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_bbcodes.php b/phpBB/includes/acp/info/acp_bbcodes.php index c0206432d6..2bca319cc3 100644 --- a/phpBB/includes/acp/info/acp_bbcodes.php +++ b/phpBB/includes/acp/info/acp_bbcodes.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_bbcodes_info { function module() @@ -33,5 +33,3 @@ class acp_bbcodes_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_board.php b/phpBB/includes/acp/info/acp_board.php index 3e18f55940..6838b4f8ba 100644 --- a/phpBB/includes/acp/info/acp_board.php +++ b/phpBB/includes/acp/info/acp_board.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_board_info { function module() @@ -48,5 +48,3 @@ class acp_board_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_bots.php b/phpBB/includes/acp/info/acp_bots.php index 45087f9225..9aa24927af 100644 --- a/phpBB/includes/acp/info/acp_bots.php +++ b/phpBB/includes/acp/info/acp_bots.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_bots_info { function module() @@ -33,6 +33,3 @@ class acp_bots_info { } } - - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_captcha.php b/phpBB/includes/acp/info/acp_captcha.php index b2541c252c..99dc5ce0e5 100644 --- a/phpBB/includes/acp/info/acp_captcha.php +++ b/phpBB/includes/acp/info/acp_captcha.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_captcha_info { function module() @@ -34,5 +34,3 @@ class acp_captcha_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_contact.php b/phpBB/includes/acp/info/acp_contact.php new file mode 100644 index 0000000000..548eb52816 --- /dev/null +++ b/phpBB/includes/acp/info/acp_contact.php @@ -0,0 +1,30 @@ +<?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. +* +*/ + +/** +* @package module_install +*/ +class acp_contact_info +{ + public function module() + { + return array( + 'filename' => 'acp_contact', + 'title' => 'ACP_CONTACT', + 'version' => '1.0.0', + 'modes' => array( + 'contact' => array('title' => 'ACP_CONTACT_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')), + ), + ); + } +} diff --git a/phpBB/includes/acp/info/acp_database.php b/phpBB/includes/acp/info/acp_database.php index 85c3c8b21c..5cf9da24fb 100644 --- a/phpBB/includes/acp/info/acp_database.php +++ b/phpBB/includes/acp/info/acp_database.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_database_info { function module() @@ -34,5 +34,3 @@ class acp_database_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_disallow.php b/phpBB/includes/acp/info/acp_disallow.php index 41315eb716..ebd44b515c 100644 --- a/phpBB/includes/acp/info/acp_disallow.php +++ b/phpBB/includes/acp/info/acp_disallow.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_disallow_info { function module() @@ -33,6 +33,3 @@ class acp_disallow_info { } } - - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_email.php b/phpBB/includes/acp/info/acp_email.php index 4ad7bca58b..2f77fc617c 100644 --- a/phpBB/includes/acp/info/acp_email.php +++ b/phpBB/includes/acp/info/acp_email.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_email_info { function module() @@ -33,6 +33,3 @@ class acp_email_info { } } - - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_extensions.php b/phpBB/includes/acp/info/acp_extensions.php new file mode 100644 index 0000000000..d4cf1b0ed5 --- /dev/null +++ b/phpBB/includes/acp/info/acp_extensions.php @@ -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. +* +*/ + +class acp_extensions_info +{ + function module() + { + return array( + 'filename' => 'acp_extensions', + 'title' => 'ACP_EXTENSION_MANAGEMENT', + 'version' => '1.0.0', + 'modes' => array( + 'main' => array('title' => 'ACP_EXTENSIONS', 'auth' => 'acl_a_extensions', 'cat' => array('ACP_EXTENSION_MANAGEMENT')), + ), + ); + } + + function install() + { + } + + function uninstall() + { + } +} diff --git a/phpBB/includes/acp/info/acp_forums.php b/phpBB/includes/acp/info/acp_forums.php index 8d82eaf42d..647090c8c3 100644 --- a/phpBB/includes/acp/info/acp_forums.php +++ b/phpBB/includes/acp/info/acp_forums.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_forums_info { function module() @@ -33,5 +33,3 @@ class acp_forums_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_groups.php b/phpBB/includes/acp/info/acp_groups.php index 3910c24e6b..6c5ad70d97 100644 --- a/phpBB/includes/acp/info/acp_groups.php +++ b/phpBB/includes/acp/info/acp_groups.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_groups_info { function module() @@ -21,6 +21,7 @@ class acp_groups_info 'version' => '1.0.0', 'modes' => array( 'manage' => array('title' => 'ACP_GROUPS_MANAGE', 'auth' => 'acl_a_group', 'cat' => array('ACP_GROUPS')), + 'position' => array('title' => 'ACP_GROUPS_POSITION', 'auth' => 'acl_a_group', 'cat' => array('ACP_GROUPS')), ), ); } @@ -33,5 +34,3 @@ class acp_groups_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_icons.php b/phpBB/includes/acp/info/acp_icons.php index 16bf753940..001d6cb402 100644 --- a/phpBB/includes/acp/info/acp_icons.php +++ b/phpBB/includes/acp/info/acp_icons.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_icons_info { function module() @@ -34,5 +34,3 @@ class acp_icons_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_inactive.php b/phpBB/includes/acp/info/acp_inactive.php index e17fbda9dd..442eb13c30 100644 --- a/phpBB/includes/acp/info/acp_inactive.php +++ b/phpBB/includes/acp/info/acp_inactive.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_inactive_info { function module() @@ -33,5 +33,3 @@ class acp_inactive_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_jabber.php b/phpBB/includes/acp/info/acp_jabber.php index 7bcf7744e1..c1dfb2aca7 100644 --- a/phpBB/includes/acp/info/acp_jabber.php +++ b/phpBB/includes/acp/info/acp_jabber.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_jabber_info { function module() @@ -33,4 +33,3 @@ class acp_jabber_info { } } -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_language.php b/phpBB/includes/acp/info/acp_language.php index f7606631fe..b9efbbbd9a 100644 --- a/phpBB/includes/acp/info/acp_language.php +++ b/phpBB/includes/acp/info/acp_language.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_language_info { function module() @@ -20,7 +20,7 @@ class acp_language_info 'title' => 'ACP_LANGUAGE', 'version' => '1.0.0', 'modes' => array( - 'lang_packs' => array('title' => 'ACP_LANGUAGE_PACKS', 'auth' => 'acl_a_language', 'cat' => array('ACP_GENERAL_TASKS')), + 'lang_packs' => array('title' => 'ACP_LANGUAGE_PACKS', 'auth' => 'acl_a_language', 'cat' => array('ACP_LANGUAGE')), ), ); } @@ -33,5 +33,3 @@ class acp_language_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_logs.php b/phpBB/includes/acp/info/acp_logs.php index f119e10b83..e9e6034cd4 100644 --- a/phpBB/includes/acp/info/acp_logs.php +++ b/phpBB/includes/acp/info/acp_logs.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_logs_info { function module() @@ -36,5 +36,3 @@ class acp_logs_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_main.php b/phpBB/includes/acp/info/acp_main.php index 5574cc40d1..51259e3bd9 100644 --- a/phpBB/includes/acp/info/acp_main.php +++ b/phpBB/includes/acp/info/acp_main.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_main_info { function module() @@ -33,5 +33,3 @@ class acp_main_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_modules.php b/phpBB/includes/acp/info/acp_modules.php index 886f17d628..a47cd4ad83 100644 --- a/phpBB/includes/acp/info/acp_modules.php +++ b/phpBB/includes/acp/info/acp_modules.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_modules_info { function module() @@ -35,5 +35,3 @@ class acp_modules_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_permission_roles.php b/phpBB/includes/acp/info/acp_permission_roles.php index 3ab2fecd53..e8aa13375d 100644 --- a/phpBB/includes/acp/info/acp_permission_roles.php +++ b/phpBB/includes/acp/info/acp_permission_roles.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_permission_roles_info { function module() @@ -36,5 +36,3 @@ class acp_permission_roles_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_permissions.php b/phpBB/includes/acp/info/acp_permissions.php index 6f341742f3..3ec592a300 100644 --- a/phpBB/includes/acp/info/acp_permissions.php +++ b/phpBB/includes/acp/info/acp_permissions.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_permissions_info { function module() @@ -50,5 +50,3 @@ class acp_permissions_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_php_info.php b/phpBB/includes/acp/info/acp_php_info.php index 7d716b0f83..af978e0daa 100644 --- a/phpBB/includes/acp/info/acp_php_info.php +++ b/phpBB/includes/acp/info/acp_php_info.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_php_info_info { function module() @@ -33,5 +33,3 @@ class acp_php_info_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_profile.php b/phpBB/includes/acp/info/acp_profile.php index 8590226038..307e711eee 100644 --- a/phpBB/includes/acp/info/acp_profile.php +++ b/phpBB/includes/acp/info/acp_profile.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_profile_info { function module() @@ -33,5 +33,3 @@ class acp_profile_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_prune.php b/phpBB/includes/acp/info/acp_prune.php index 46565c4f16..58cb1ba9ab 100644 --- a/phpBB/includes/acp/info/acp_prune.php +++ b/phpBB/includes/acp/info/acp_prune.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_prune_info { function module() @@ -21,7 +21,7 @@ class acp_prune_info 'version' => '1.0.0', 'modes' => array( 'forums' => array('title' => 'ACP_PRUNE_FORUMS', 'auth' => 'acl_a_prune', 'cat' => array('ACP_MANAGE_FORUMS')), - 'users' => array('title' => 'ACP_PRUNE_USERS', 'auth' => 'acl_a_userdel', 'cat' => array('ACP_USER_SECURITY')), + 'users' => array('title' => 'ACP_PRUNE_USERS', 'auth' => 'acl_a_userdel', 'cat' => array('ACP_CAT_USERS')), ), ); } @@ -34,5 +34,3 @@ class acp_prune_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_ranks.php b/phpBB/includes/acp/info/acp_ranks.php index 06b9c6d284..3cc9b4a428 100644 --- a/phpBB/includes/acp/info/acp_ranks.php +++ b/phpBB/includes/acp/info/acp_ranks.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_ranks_info { function module() @@ -33,5 +33,3 @@ class acp_ranks_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_reasons.php b/phpBB/includes/acp/info/acp_reasons.php index 65d805ee18..c48fd1aacd 100644 --- a/phpBB/includes/acp/info/acp_reasons.php +++ b/phpBB/includes/acp/info/acp_reasons.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_reasons_info { function module() @@ -33,5 +33,3 @@ class acp_reasons_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_search.php b/phpBB/includes/acp/info/acp_search.php index 4afd6c6994..5d681a7174 100644 --- a/phpBB/includes/acp/info/acp_search.php +++ b/phpBB/includes/acp/info/acp_search.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_search_info { function module() @@ -34,5 +34,3 @@ class acp_search_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_send_statistics.php b/phpBB/includes/acp/info/acp_send_statistics.php index de5dcdb8ad..a4f2ddc420 100644 --- a/phpBB/includes/acp/info/acp_send_statistics.php +++ b/phpBB/includes/acp/info/acp_send_statistics.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_send_statistics_info { function module() @@ -33,5 +33,3 @@ class acp_send_statistics_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_styles.php b/phpBB/includes/acp/info/acp_styles.php index db67167e39..c0ab005502 100644 --- a/phpBB/includes/acp/info/acp_styles.php +++ b/phpBB/includes/acp/info/acp_styles.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_styles_info { function module() @@ -18,12 +18,10 @@ class acp_styles_info return array( 'filename' => 'acp_styles', 'title' => 'ACP_CAT_STYLES', - 'version' => '1.0.0', + 'version' => '2.0.0', 'modes' => array( 'style' => array('title' => 'ACP_STYLES', 'auth' => 'acl_a_styles', 'cat' => array('ACP_STYLE_MANAGEMENT')), - 'template' => array('title' => 'ACP_TEMPLATES', 'auth' => 'acl_a_styles', 'cat' => array('ACP_STYLE_COMPONENTS')), - 'theme' => array('title' => 'ACP_THEMES', 'auth' => 'acl_a_styles', 'cat' => array('ACP_STYLE_COMPONENTS')), - 'imageset' => array('title' => 'ACP_IMAGESETS', 'auth' => 'acl_a_styles', 'cat' => array('ACP_STYLE_COMPONENTS')), + 'install' => array('title' => 'ACP_STYLES_INSTALL', 'auth' => 'acl_a_styles', 'cat' => array('ACP_STYLE_MANAGEMENT')), ), ); } @@ -36,5 +34,3 @@ class acp_styles_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_update.php b/phpBB/includes/acp/info/acp_update.php index 886cdc94d5..ca00f6d305 100644 --- a/phpBB/includes/acp/info/acp_update.php +++ b/phpBB/includes/acp/info/acp_update.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_update_info { function module() @@ -33,5 +33,3 @@ class acp_update_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_users.php b/phpBB/includes/acp/info/acp_users.php index 10081ac870..ab69523cde 100644 --- a/phpBB/includes/acp/info/acp_users.php +++ b/phpBB/includes/acp/info/acp_users.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_users_info { function module() @@ -43,5 +43,3 @@ class acp_users_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_words.php b/phpBB/includes/acp/info/acp_words.php index a2417f8a7f..3c8c79f25f 100644 --- a/phpBB/includes/acp/info/acp_words.php +++ b/phpBB/includes/acp/info/acp_words.php @@ -1,16 +1,16 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class acp_words_info { function module() @@ -33,5 +33,3 @@ class acp_words_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/auth.php b/phpBB/includes/auth.php deleted file mode 100644 index 0585921426..0000000000 --- a/phpBB/includes/auth.php +++ /dev/null @@ -1,1064 +0,0 @@ -<?php -/** -* -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Permission/Auth class -* @package phpBB3 -*/ -class auth -{ - var $acl = array(); - var $cache = array(); - var $acl_options = array(); - var $acl_forum_ids = false; - - /** - * Init permissions - */ - function acl(&$userdata) - { - global $db, $cache; - - $this->acl = $this->cache = $this->acl_options = array(); - $this->acl_forum_ids = false; - - if (($this->acl_options = $cache->get('_acl_options')) === false) - { - $sql = 'SELECT auth_option_id, auth_option, is_global, is_local - FROM ' . ACL_OPTIONS_TABLE . ' - ORDER BY auth_option_id'; - $result = $db->sql_query($sql); - - $global = $local = 0; - $this->acl_options = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['is_global']) - { - $this->acl_options['global'][$row['auth_option']] = $global++; - } - - if ($row['is_local']) - { - $this->acl_options['local'][$row['auth_option']] = $local++; - } - - $this->acl_options['id'][$row['auth_option']] = (int) $row['auth_option_id']; - $this->acl_options['option'][(int) $row['auth_option_id']] = $row['auth_option']; - } - $db->sql_freeresult($result); - - $cache->put('_acl_options', $this->acl_options); - } - - if (!trim($userdata['user_permissions'])) - { - $this->acl_cache($userdata); - } - - // Fill ACL array - $this->_fill_acl($userdata['user_permissions']); - - // Verify bitstring length with options provided... - $renew = false; - $global_length = sizeof($this->acl_options['global']); - $local_length = sizeof($this->acl_options['local']); - - // Specify comparing length (bitstring is padded to 31 bits) - $global_length = ($global_length % 31) ? ($global_length - ($global_length % 31) + 31) : $global_length; - $local_length = ($local_length % 31) ? ($local_length - ($local_length % 31) + 31) : $local_length; - - // You thought we are finished now? Noooo... now compare them. - foreach ($this->acl as $forum_id => $bitstring) - { - if (($forum_id && strlen($bitstring) != $local_length) || (!$forum_id && strlen($bitstring) != $global_length)) - { - $renew = true; - break; - } - } - - // If a bitstring within the list does not match the options, we have a user with incorrect permissions set and need to renew them - if ($renew) - { - $this->acl_cache($userdata); - $this->_fill_acl($userdata['user_permissions']); - } - - return; - } - - /** - * Fill ACL array with relevant bitstrings from user_permissions column - * @access private - */ - function _fill_acl($user_permissions) - { - $seq_cache = array(); - $this->acl = array(); - $user_permissions = explode("\n", $user_permissions); - - foreach ($user_permissions as $f => $seq) - { - if ($seq) - { - $i = 0; - - if (!isset($this->acl[$f])) - { - $this->acl[$f] = ''; - } - - while ($subseq = substr($seq, $i, 6)) - { - if (isset($seq_cache[$subseq])) - { - $converted = $seq_cache[$subseq]; - } - else - { - $converted = $seq_cache[$subseq] = str_pad(base_convert($subseq, 36, 2), 31, 0, STR_PAD_LEFT); - } - - // We put the original bitstring into the acl array - $this->acl[$f] .= $converted; - $i += 6; - } - } - } - } - - /** - * Look up an option - * if the option is prefixed with !, then the result becomes negated - * - * If a forum id is specified the local option will be combined with a global option if one exist. - * If a forum id is not specified, only the global option will be checked. - */ - function acl_get($opt, $f = 0) - { - $negate = false; - - if (strpos($opt, '!') === 0) - { - $negate = true; - $opt = substr($opt, 1); - } - - if (!isset($this->cache[$f][$opt])) - { - // We combine the global/local option with an OR because some options are global and local. - // If the user has the global permission the local one is true too and vice versa - $this->cache[$f][$opt] = false; - - // Is this option a global permission setting? - if (isset($this->acl_options['global'][$opt])) - { - if (isset($this->acl[0])) - { - $this->cache[$f][$opt] = $this->acl[0][$this->acl_options['global'][$opt]]; - } - } - - // Is this option a local permission setting? - // But if we check for a global option only, we won't combine the options... - if ($f != 0 && isset($this->acl_options['local'][$opt])) - { - if (isset($this->acl[$f]) && isset($this->acl[$f][$this->acl_options['local'][$opt]])) - { - $this->cache[$f][$opt] |= $this->acl[$f][$this->acl_options['local'][$opt]]; - } - } - } - - // Founder always has all global options set to true... - return ($negate) ? !$this->cache[$f][$opt] : $this->cache[$f][$opt]; - } - - /** - * Get forums with the specified permission setting - * if the option is prefixed with !, then the result becomes nagated - * - * @param bool $clean set to true if only values needs to be returned which are set/unset - */ - function acl_getf($opt, $clean = false) - { - $acl_f = array(); - $negate = false; - - if (strpos($opt, '!') === 0) - { - $negate = true; - $opt = substr($opt, 1); - } - - // If we retrieve a list of forums not having permissions in, we need to get every forum_id - if ($negate) - { - if ($this->acl_forum_ids === false) - { - global $db; - - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE; - - if (sizeof($this->acl)) - { - $sql .= ' WHERE ' . $db->sql_in_set('forum_id', array_keys($this->acl), true); - } - $result = $db->sql_query($sql); - - $this->acl_forum_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $this->acl_forum_ids[] = $row['forum_id']; - } - $db->sql_freeresult($result); - } - } - - if (isset($this->acl_options['local'][$opt])) - { - foreach ($this->acl as $f => $bitstring) - { - // Skip global settings - if (!$f) - { - continue; - } - - $allowed = (!isset($this->cache[$f][$opt])) ? $this->acl_get($opt, $f) : $this->cache[$f][$opt]; - - if (!$clean) - { - $acl_f[$f][$opt] = ($negate) ? !$allowed : $allowed; - } - else - { - if (($negate && !$allowed) || (!$negate && $allowed)) - { - $acl_f[$f][$opt] = 1; - } - } - } - } - - // If we get forum_ids not having this permission, we need to fill the remaining parts - if ($negate && sizeof($this->acl_forum_ids)) - { - foreach ($this->acl_forum_ids as $f) - { - $acl_f[$f][$opt] = 1; - } - } - - return $acl_f; - } - - /** - * Get local permission state for any forum. - * - * Returns true if user has the permission in one or more forums, false if in no forum. - * If global option is checked it returns the global state (same as acl_get($opt)) - * Local option has precedence... - */ - function acl_getf_global($opt) - { - if (is_array($opt)) - { - // evaluates to true as soon as acl_getf_global is true for one option - foreach ($opt as $check_option) - { - if ($this->acl_getf_global($check_option)) - { - return true; - } - } - - return false; - } - - if (isset($this->acl_options['local'][$opt])) - { - foreach ($this->acl as $f => $bitstring) - { - // Skip global settings - if (!$f) - { - continue; - } - - // as soon as the user has any permission we're done so return true - if ((!isset($this->cache[$f][$opt])) ? $this->acl_get($opt, $f) : $this->cache[$f][$opt]) - { - return true; - } - } - } - else if (isset($this->acl_options['global'][$opt])) - { - return $this->acl_get($opt); - } - - return false; - } - - /** - * Get permission settings (more than one) - */ - function acl_gets() - { - $args = func_get_args(); - $f = array_pop($args); - - if (!is_numeric($f)) - { - $args[] = $f; - $f = 0; - } - - // alternate syntax: acl_gets(array('m_', 'a_'), $forum_id) - if (is_array($args[0])) - { - $args = $args[0]; - } - - $acl = 0; - foreach ($args as $opt) - { - $acl |= $this->acl_get($opt, $f); - } - - return $acl; - } - - /** - * Get permission listing based on user_id/options/forum_ids - * - * Be careful when using this function with permissions a_, m_, u_ and f_ ! - * It may not work correctly. When a user group grants an a_* permission, - * e.g. a_foo, but the user's a_foo permission is set to "Never", then - * the user does not in fact have the a_ permission. - * But the user will still be listed as having the a_ permission. - * - * For more information see: http://tracker.phpbb.com/browse/PHPBB3-10252 - */ - function acl_get_list($user_id = false, $opts = false, $forum_id = false) - { - if ($user_id !== false && !is_array($user_id) && $opts === false && $forum_id === false) - { - $hold_ary = array($user_id => $this->acl_raw_data_single_user($user_id)); - } - else - { - $hold_ary = $this->acl_raw_data($user_id, $opts, $forum_id); - } - - $auth_ary = array(); - foreach ($hold_ary as $user_id => $forum_ary) - { - foreach ($forum_ary as $forum_id => $auth_option_ary) - { - foreach ($auth_option_ary as $auth_option => $auth_setting) - { - if ($auth_setting) - { - $auth_ary[$forum_id][$auth_option][] = $user_id; - } - } - } - } - - return $auth_ary; - } - - /** - * Cache data to user_permissions row - */ - function acl_cache(&$userdata) - { - global $db; - - // Empty user_permissions - $userdata['user_permissions'] = ''; - - $hold_ary = $this->acl_raw_data_single_user($userdata['user_id']); - - // Key 0 in $hold_ary are global options, all others are forum_ids - - // If this user is founder we're going to force fill the admin options ... - if ($userdata['user_type'] == USER_FOUNDER) - { - foreach ($this->acl_options['global'] as $opt => $id) - { - if (strpos($opt, 'a_') === 0) - { - $hold_ary[0][$this->acl_options['id'][$opt]] = ACL_YES; - } - } - } - - $hold_str = $this->build_bitstring($hold_ary); - - if ($hold_str) - { - $userdata['user_permissions'] = $hold_str; - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_permissions = '" . $db->sql_escape($userdata['user_permissions']) . "', - user_perm_from = 0 - WHERE user_id = " . $userdata['user_id']; - $db->sql_query($sql); - } - - return; - } - - /** - * Build bitstring from permission set - */ - function build_bitstring(&$hold_ary) - { - $hold_str = ''; - - if (sizeof($hold_ary)) - { - ksort($hold_ary); - - $last_f = 0; - - foreach ($hold_ary as $f => $auth_ary) - { - $ary_key = (!$f) ? 'global' : 'local'; - - $bitstring = array(); - foreach ($this->acl_options[$ary_key] as $opt => $id) - { - if (isset($auth_ary[$this->acl_options['id'][$opt]])) - { - $bitstring[$id] = $auth_ary[$this->acl_options['id'][$opt]]; - - $option_key = substr($opt, 0, strpos($opt, '_') + 1); - - // If one option is allowed, the global permission for this option has to be allowed too - // example: if the user has the a_ permission this means he has one or more a_* permissions - if ($auth_ary[$this->acl_options['id'][$opt]] == ACL_YES && (!isset($bitstring[$this->acl_options[$ary_key][$option_key]]) || $bitstring[$this->acl_options[$ary_key][$option_key]] == ACL_NEVER)) - { - $bitstring[$this->acl_options[$ary_key][$option_key]] = ACL_YES; - } - } - else - { - $bitstring[$id] = ACL_NEVER; - } - } - - // Now this bitstring defines the permission setting for the current forum $f (or global setting) - $bitstring = implode('', $bitstring); - - // The line number indicates the id, therefore we have to add empty lines for those ids not present - $hold_str .= str_repeat("\n", $f - $last_f); - - // Convert bitstring for storage - we do not use binary/bytes because PHP's string functions are not fully binary safe - for ($i = 0, $bit_length = strlen($bitstring); $i < $bit_length; $i += 31) - { - $hold_str .= str_pad(base_convert(str_pad(substr($bitstring, $i, 31), 31, 0, STR_PAD_RIGHT), 2, 36), 6, 0, STR_PAD_LEFT); - } - - $last_f = $f; - } - unset($bitstring); - - $hold_str = rtrim($hold_str); - } - - return $hold_str; - } - - /** - * Clear one or all users cached permission settings - */ - function acl_clear_prefetch($user_id = false) - { - global $db, $cache; - - // Rebuild options cache - $cache->destroy('_role_cache'); - - $sql = 'SELECT * - FROM ' . ACL_ROLES_DATA_TABLE . ' - ORDER BY role_id ASC'; - $result = $db->sql_query($sql); - - $this->role_cache = array(); - while ($row = $db->sql_fetchrow($result)) - { - $this->role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting']; - } - $db->sql_freeresult($result); - - foreach ($this->role_cache as $role_id => $role_options) - { - $this->role_cache[$role_id] = serialize($role_options); - } - - $cache->put('_role_cache', $this->role_cache); - - // Now empty user permissions - $where_sql = ''; - - if ($user_id !== false) - { - $user_id = (!is_array($user_id)) ? $user_id = array((int) $user_id) : array_map('intval', $user_id); - $where_sql = ' WHERE ' . $db->sql_in_set('user_id', $user_id); - } - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_permissions = '', - user_perm_from = 0 - $where_sql"; - $db->sql_query($sql); - - return; - } - - /** - * Get assigned roles - */ - function acl_role_data($user_type, $role_type, $ug_id = false, $forum_id = false) - { - global $db; - - $roles = array(); - - $sql_id = ($user_type == 'user') ? 'user_id' : 'group_id'; - - $sql_ug = ($ug_id !== false) ? ((!is_array($ug_id)) ? "AND a.$sql_id = $ug_id" : 'AND ' . $db->sql_in_set("a.$sql_id", $ug_id)) : ''; - $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? "AND a.forum_id = $forum_id" : 'AND ' . $db->sql_in_set('a.forum_id', $forum_id)) : ''; - - // Grab assigned roles... - $sql = 'SELECT a.auth_role_id, a.' . $sql_id . ', a.forum_id - FROM ' . (($user_type == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE) . ' a, ' . ACL_ROLES_TABLE . " r - WHERE a.auth_role_id = r.role_id - AND r.role_type = '" . $db->sql_escape($role_type) . "' - $sql_ug - $sql_forum - ORDER BY r.role_order ASC"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $roles[$row[$sql_id]][$row['forum_id']] = $row['auth_role_id']; - } - $db->sql_freeresult($result); - - return $roles; - } - - /** - * Get raw acl data based on user/option/forum - */ - function acl_raw_data($user_id = false, $opts = false, $forum_id = false) - { - global $db; - - $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? 'user_id = ' . (int) $user_id : $db->sql_in_set('user_id', array_map('intval', $user_id))) : ''; - $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : ''; - - $sql_opts = $sql_opts_select = $sql_opts_from = ''; - $hold_ary = array(); - - if ($opts !== false) - { - $sql_opts_select = ', ao.auth_option'; - $sql_opts_from = ', ' . ACL_OPTIONS_TABLE . ' ao'; - $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts); - } - - $sql_ary = array(); - - // Grab non-role settings - user-specific - $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . ' - FROM ' . ACL_USERS_TABLE . ' a' . $sql_opts_from . ' - WHERE a.auth_role_id = 0 ' . - (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') . - (($sql_user) ? 'AND a.' . $sql_user : '') . " - $sql_forum - $sql_opts"; - - // Now the role settings - user-specific - $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . ' - FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . ' - WHERE a.auth_role_id = r.role_id ' . - (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') . - (($sql_user) ? 'AND a.' . $sql_user : '') . " - $sql_forum - $sql_opts"; - - foreach ($sql_ary as $sql) - { - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']]; - $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting']; - } - $db->sql_freeresult($result); - } - - $sql_ary = array(); - - // Now grab group settings - non-role specific... - $sql_ary[] = 'SELECT ug.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . ' - FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g' . $sql_opts_from . ' - WHERE a.auth_role_id = 0 ' . - (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') . ' - AND a.group_id = ug.group_id - AND g.group_id = ug.group_id - AND ug.user_pending = 0 - AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) - ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . " - $sql_forum - $sql_opts"; - - // Now grab group settings - role specific... - $sql_ary[] = 'SELECT ug.user_id, a.forum_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . ' - FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . ' - WHERE a.auth_role_id = r.role_id ' . - (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') . ' - AND a.group_id = ug.group_id - AND g.group_id = ug.group_id - AND ug.user_pending = 0 - AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) - ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . " - $sql_forum - $sql_opts"; - - foreach ($sql_ary as $sql) - { - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']]; - - if (!isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) || (isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) && $hold_ary[$row['user_id']][$row['forum_id']][$option] != ACL_NEVER)) - { - $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting']; - - // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again) - if ($row['auth_setting'] == ACL_NEVER) - { - $flag = substr($option, 0, strpos($option, '_') + 1); - - if (isset($hold_ary[$row['user_id']][$row['forum_id']][$flag]) && $hold_ary[$row['user_id']][$row['forum_id']][$flag] == ACL_YES) - { - unset($hold_ary[$row['user_id']][$row['forum_id']][$flag]); - -/* if (in_array(ACL_YES, $hold_ary[$row['user_id']][$row['forum_id']])) - { - $hold_ary[$row['user_id']][$row['forum_id']][$flag] = ACL_YES; - } -*/ - } - } - } - } - $db->sql_freeresult($result); - } - - return $hold_ary; - } - - /** - * Get raw user based permission settings - */ - function acl_user_raw_data($user_id = false, $opts = false, $forum_id = false) - { - global $db; - - $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? 'user_id = ' . (int) $user_id : $db->sql_in_set('user_id', array_map('intval', $user_id))) : ''; - $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : ''; - - $sql_opts = ''; - $hold_ary = $sql_ary = array(); - - if ($opts !== false) - { - $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts); - } - - // Grab user settings - non-role specific... - $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option - FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao - WHERE a.auth_role_id = 0 - AND a.auth_option_id = ao.auth_option_id ' . - (($sql_user) ? 'AND a.' . $sql_user : '') . " - $sql_forum - $sql_opts - ORDER BY a.forum_id, ao.auth_option"; - - // Now the role settings - user-specific - $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id, ao.auth_option - FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao - WHERE a.auth_role_id = r.role_id - AND r.auth_option_id = ao.auth_option_id ' . - (($sql_user) ? 'AND a.' . $sql_user : '') . " - $sql_forum - $sql_opts - ORDER BY a.forum_id, ao.auth_option"; - - foreach ($sql_ary as $sql) - { - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting']; - } - $db->sql_freeresult($result); - } - - return $hold_ary; - } - - /** - * Get raw group based permission settings - */ - function acl_group_raw_data($group_id = false, $opts = false, $forum_id = false) - { - global $db; - - $sql_group = ($group_id !== false) ? ((!is_array($group_id)) ? 'group_id = ' . (int) $group_id : $db->sql_in_set('group_id', array_map('intval', $group_id))) : ''; - $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : ''; - - $sql_opts = ''; - $hold_ary = $sql_ary = array(); - - if ($opts !== false) - { - $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts); - } - - // Grab group settings - non-role specific... - $sql_ary[] = 'SELECT a.group_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option - FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao - WHERE a.auth_role_id = 0 - AND a.auth_option_id = ao.auth_option_id ' . - (($sql_group) ? 'AND a.' . $sql_group : '') . " - $sql_forum - $sql_opts - ORDER BY a.forum_id, ao.auth_option"; - - // Now grab group settings - role specific... - $sql_ary[] = 'SELECT a.group_id, a.forum_id, r.auth_setting, r.auth_option_id, ao.auth_option - FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao - WHERE a.auth_role_id = r.role_id - AND r.auth_option_id = ao.auth_option_id ' . - (($sql_group) ? 'AND a.' . $sql_group : '') . " - $sql_forum - $sql_opts - ORDER BY a.forum_id, ao.auth_option"; - - foreach ($sql_ary as $sql) - { - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $hold_ary[$row['group_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting']; - } - $db->sql_freeresult($result); - } - - return $hold_ary; - } - - /** - * Get raw acl data based on user for caching user_permissions - * This function returns the same data as acl_raw_data(), but without the user id as the first key within the array. - */ - function acl_raw_data_single_user($user_id) - { - global $db, $cache; - - // Check if the role-cache is there - if (($this->role_cache = $cache->get('_role_cache')) === false) - { - $this->role_cache = array(); - - // We pre-fetch roles - $sql = 'SELECT * - FROM ' . ACL_ROLES_DATA_TABLE . ' - ORDER BY role_id ASC'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $this->role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting']; - } - $db->sql_freeresult($result); - - foreach ($this->role_cache as $role_id => $role_options) - { - $this->role_cache[$role_id] = serialize($role_options); - } - - $cache->put('_role_cache', $this->role_cache); - } - - $hold_ary = array(); - - // Grab user-specific permission settings - $sql = 'SELECT forum_id, auth_option_id, auth_role_id, auth_setting - FROM ' . ACL_USERS_TABLE . ' - WHERE user_id = ' . $user_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - // If a role is assigned, assign all options included within this role. Else, only set this one option. - if ($row['auth_role_id']) - { - $hold_ary[$row['forum_id']] = (empty($hold_ary[$row['forum_id']])) ? unserialize($this->role_cache[$row['auth_role_id']]) : $hold_ary[$row['forum_id']] + unserialize($this->role_cache[$row['auth_role_id']]); - } - else - { - $hold_ary[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting']; - } - } - $db->sql_freeresult($result); - - // Now grab group-specific permission settings - $sql = 'SELECT a.forum_id, a.auth_option_id, a.auth_role_id, a.auth_setting - FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g - WHERE a.group_id = ug.group_id - AND g.group_id = ug.group_id - AND ug.user_pending = 0 - AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) - AND ug.user_id = ' . $user_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$row['auth_role_id']) - { - $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $row['auth_option_id'], $row['auth_setting']); - } - else if (!empty($this->role_cache[$row['auth_role_id']])) - { - foreach (unserialize($this->role_cache[$row['auth_role_id']]) as $option_id => $setting) - { - $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $option_id, $setting); - } - } - } - $db->sql_freeresult($result); - - return $hold_ary; - } - - /** - * Private function snippet for setting a specific piece of the hold_ary - */ - function _set_group_hold_ary(&$hold_ary, $option_id, $setting) - { - if (!isset($hold_ary[$option_id]) || (isset($hold_ary[$option_id]) && $hold_ary[$option_id] != ACL_NEVER)) - { - $hold_ary[$option_id] = $setting; - - // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again) - if ($setting == ACL_NEVER) - { - $flag = substr($this->acl_options['option'][$option_id], 0, strpos($this->acl_options['option'][$option_id], '_') + 1); - $flag = (int) $this->acl_options['id'][$flag]; - - if (isset($hold_ary[$flag]) && $hold_ary[$flag] == ACL_YES) - { - unset($hold_ary[$flag]); - -/* This is uncommented, because i suspect this being slightly wrong due to mixed permission classes being possible - if (in_array(ACL_YES, $hold_ary)) - { - $hold_ary[$flag] = ACL_YES; - }*/ - } - } - } - } - - /** - * Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him. - */ - function login($username, $password, $autologin = false, $viewonline = 1, $admin = 0) - { - global $config, $db, $user, $phpbb_root_path, $phpEx; - - $method = trim(basename($config['auth_method'])); - include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); - - $method = 'login_' . $method; - if (function_exists($method)) - { - $login = $method($username, $password, $user->ip, $user->browser, $user->forwarded_for); - - // If the auth module wants us to create an empty profile do so and then treat the status as LOGIN_SUCCESS - if ($login['status'] == LOGIN_SUCCESS_CREATE_PROFILE) - { - // we are going to use the user_add function so include functions_user.php if it wasn't defined yet - if (!function_exists('user_add')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - user_add($login['user_row'], (isset($login['cp_data'])) ? $login['cp_data'] : false); - - $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'AUTH_NO_PROFILE_CREATED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $login = array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - - // If login succeeded, we will log the user in... else we pass the login array through... - if ($login['status'] == LOGIN_SUCCESS) - { - $old_session_id = $user->session_id; - - if ($admin) - { - global $SID, $_SID; - - $cookie_expire = time() - 31536000; - $user->set_cookie('u', '', $cookie_expire); - $user->set_cookie('sid', '', $cookie_expire); - unset($cookie_expire); - - $SID = '?sid='; - $user->session_id = $_SID = ''; - } - - $result = $user->session_create($login['user_row']['user_id'], $admin, $autologin, $viewonline); - - // Successful session creation - if ($result === true) - { - // If admin re-authentication we remove the old session entry because a new one has been created... - if ($admin) - { - // the login array is used because the user ids do not differ for re-authentication - $sql = 'DELETE FROM ' . SESSIONS_TABLE . " - WHERE session_id = '" . $db->sql_escape($old_session_id) . "' - AND session_user_id = {$login['user_row']['user_id']}"; - $db->sql_query($sql); - } - - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $login['user_row'], - ); - } - - return array( - 'status' => LOGIN_BREAK, - 'error_msg' => $result, - 'user_row' => $login['user_row'], - ); - } - - return $login; - } - - trigger_error('Authentication method not found', E_USER_ERROR); - } - - /** - * Fill auth_option statement for later querying based on the supplied options - */ - function build_auth_option_statement($key, $auth_options, &$sql_opts) - { - global $db; - - if (!is_array($auth_options)) - { - if (strpos($auth_options, '%') !== false) - { - $sql_opts = "AND $key " . $db->sql_like_expression(str_replace('%', $db->any_char, $auth_options)); - } - else - { - $sql_opts = "AND $key = '" . $db->sql_escape($auth_options) . "'"; - } - } - else - { - $is_like_expression = false; - - foreach ($auth_options as $option) - { - if (strpos($option, '%') !== false) - { - $is_like_expression = true; - } - } - - if (!$is_like_expression) - { - $sql_opts = 'AND ' . $db->sql_in_set($key, $auth_options); - } - else - { - $sql = array(); - - foreach ($auth_options as $option) - { - if (strpos($option, '%') !== false) - { - $sql[] = $key . ' ' . $db->sql_like_expression(str_replace('%', $db->any_char, $option)); - } - else - { - $sql[] = $key . " = '" . $db->sql_escape($option) . "'"; - } - } - - $sql_opts = 'AND (' . implode(' OR ', $sql) . ')'; - } - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/auth/auth_apache.php b/phpBB/includes/auth/auth_apache.php deleted file mode 100644 index 391e7abb0e..0000000000 --- a/phpBB/includes/auth/auth_apache.php +++ /dev/null @@ -1,249 +0,0 @@ -<?php -/** -* Apache auth plug-in for phpBB3 -* -* Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him. -* -* @package login -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Checks whether the user is identified to apache -* Only allow changing authentication to apache if the user is identified -* Called in acp_board while setting authentication plugins -* -* @return boolean|string false if the user is identified and else an error message -*/ -function init_apache() -{ - global $user; - - if (!isset($_SERVER['PHP_AUTH_USER']) || $user->data['username'] !== $_SERVER['PHP_AUTH_USER']) - { - return $user->lang['APACHE_SETUP_BEFORE_USE']; - } - return false; -} - -/** -* Login function -*/ -function login_apache(&$username, &$password) -{ - global $db; - - // do not allow empty password - if (!$password) - { - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'NO_PASSWORD_SUPPLIED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!isset($_SERVER['PHP_AUTH_USER'])) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $php_auth_user = $_SERVER['PHP_AUTH_USER']; - $php_auth_pw = $_SERVER['PHP_AUTH_PW']; - - if (!empty($php_auth_user) && !empty($php_auth_pw)) - { - if ($php_auth_user !== $username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type - FROM ' . USERS_TABLE . " - WHERE username = '" . $db->sql_escape($php_auth_user) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - // User inactive... - if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) - { - return array( - 'status' => LOGIN_ERROR_ACTIVE, - 'error_msg' => 'ACTIVE_ERROR', - 'user_row' => $row, - ); - } - - // Successful login... - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - - // this is the user's first login so create an empty profile - return array( - 'status' => LOGIN_SUCCESS_CREATE_PROFILE, - 'error_msg' => false, - 'user_row' => user_row_apache($php_auth_user, $php_auth_pw), - ); - } - - // Not logged into apache - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE', - 'user_row' => array('user_id' => ANONYMOUS), - ); -} - -/** -* Autologin function -* -* @return array containing the user row or empty if no auto login should take place -*/ -function autologin_apache() -{ - global $db; - - if (!isset($_SERVER['PHP_AUTH_USER'])) - { - return array(); - } - - $php_auth_user = $_SERVER['PHP_AUTH_USER']; - $php_auth_pw = $_SERVER['PHP_AUTH_PW']; - - if (!empty($php_auth_user) && !empty($php_auth_pw)) - { - set_var($php_auth_user, $php_auth_user, 'string', true); - set_var($php_auth_pw, $php_auth_pw, 'string', true); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE username = '" . $db->sql_escape($php_auth_user) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) ? array() : $row; - } - - if (!function_exists('user_add')) - { - global $phpbb_root_path, $phpEx; - - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - - // create the user if he does not exist yet - user_add(user_row_apache($php_auth_user, $php_auth_pw)); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($php_auth_user)) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - return $row; - } - } - - return array(); -} - -/** -* This function generates an array which can be passed to the user_add function in order to create a user -*/ -function user_row_apache($username, $password) -{ - global $db, $config, $user; - // first retrieve default group id - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $db->sql_escape('REGISTERED') . "' - AND group_type = " . GROUP_SPECIAL; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_GROUP'); - } - - // generate user account data - return array( - 'username' => $username, - 'user_password' => phpbb_hash($password), - 'user_email' => '', - 'group_id' => (int) $row['group_id'], - 'user_type' => USER_NORMAL, - 'user_ip' => $user->ip, - 'user_new' => ($config['new_member_post_limit']) ? 1 : 0, - ); -} - -/** -* The session validation function checks whether the user is still logged in -* -* @return boolean true if the given user is authenticated or false if the session should be closed -*/ -function validate_session_apache(&$user) -{ - // Check if PHP_AUTH_USER is set and handle this case - if (isset($_SERVER['PHP_AUTH_USER'])) - { - $php_auth_user = ''; - set_var($php_auth_user, $_SERVER['PHP_AUTH_USER'], 'string', true); - - return ($php_auth_user === $user['username']) ? true : false; - } - - // PHP_AUTH_USER is not set. A valid session is now determined by the user type (anonymous/bot or not) - if ($user['user_type'] == USER_IGNORE) - { - return true; - } - - return false; -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php deleted file mode 100644 index 1c6cdf7832..0000000000 --- a/phpBB/includes/auth/auth_db.php +++ /dev/null @@ -1,276 +0,0 @@ -<?php -/** -* Database auth plug-in for phpBB3 -* -* Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him. -* -* This is for authentication via the integrated user table -* -* @package login -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Login function -* -* @param string $username -* @param string $password -* @param string $ip IP address the login is taking place from. Used to -* limit the number of login attempts per IP address. -* @param string $browser The user agent used to login -* @param string $forwarded_for X_FORWARDED_FOR header sent with login request -* @return array A associative array of the format -* array( -* 'status' => status constant -* 'error_msg' => string -* 'user_row' => array -* ) -*/ -function login_db($username, $password, $ip = '', $browser = '', $forwarded_for = '') -{ - global $db, $config; - - // do not allow empty password - if (!$password) - { - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'NO_PASSWORD_SUPPLIED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $username_clean = utf8_clean_string($username); - - $sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape($username_clean) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (($ip && !$config['ip_login_limit_use_forwarded']) || - ($forwarded_for && $config['ip_login_limit_use_forwarded'])) - { - $sql = 'SELECT COUNT(*) AS attempts - FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE attempt_time > ' . (time() - (int) $config['ip_login_limit_time']); - if ($config['ip_login_limit_use_forwarded']) - { - $sql .= " AND attempt_forwarded_for = '" . $db->sql_escape($forwarded_for) . "'"; - } - else - { - $sql .= " AND attempt_ip = '" . $db->sql_escape($ip) . "' "; - } - - $result = $db->sql_query($sql); - $attempts = (int) $db->sql_fetchfield('attempts'); - $db->sql_freeresult($result); - - $attempt_data = array( - 'attempt_ip' => $ip, - 'attempt_browser' => trim(substr($browser, 0, 149)), - 'attempt_forwarded_for' => $forwarded_for, - 'attempt_time' => time(), - 'user_id' => ($row) ? (int) $row['user_id'] : 0, - 'username' => $username, - 'username_clean' => $username_clean, - ); - $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $db->sql_build_array('INSERT', $attempt_data); - $result = $db->sql_query($sql); - } - else - { - $attempts = 0; - } - - if (!$row) - { - if ($config['ip_login_limit_max'] && $attempts >= $config['ip_login_limit_max']) - { - return array( - 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $show_captcha = ($config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']) || - ($config['ip_login_limit_max'] && $attempts >= $config['ip_login_limit_max']); - - // If there are too much login attempts, we need to check for an confirm image - // Every auth module is able to define what to do by itself... - if ($show_captcha) - { - // Visual Confirmation handling - if (!class_exists('phpbb_captcha_factory')) - { - global $phpbb_root_path, $phpEx; - include ($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - } - - $captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); - $captcha->init(CONFIRM_LOGIN); - $vc_response = $captcha->validate($row); - if ($vc_response) - { - return array( - 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', - 'user_row' => $row, - ); - } - else - { - $captcha->reset(); - } - - } - - // If the password convert flag is set we need to convert it - if ($row['user_pass_convert']) - { - // in phpBB2 passwords were used exactly as they were sent, with addslashes applied - $password_old_format = isset($_REQUEST['password']) ? (string) $_REQUEST['password'] : ''; - $password_old_format = (!STRIP) ? addslashes($password_old_format) : $password_old_format; - $password_new_format = ''; - - set_var($password_new_format, stripslashes($password_old_format), 'string', true); - - if ($password == $password_new_format) - { - if (!function_exists('utf8_to_cp1252')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx); - } - - // cp1252 is phpBB2's default encoding, characters outside ASCII range might work when converted into that encoding - // plain md5 support left in for conversions from other systems. - if ((strlen($row['user_password']) == 34 && (phpbb_check_hash(md5($password_old_format), $row['user_password']) || phpbb_check_hash(md5(utf8_to_cp1252($password_old_format)), $row['user_password']))) - || (strlen($row['user_password']) == 32 && (md5($password_old_format) == $row['user_password'] || md5(utf8_to_cp1252($password_old_format)) == $row['user_password']))) - { - $hash = phpbb_hash($password_new_format); - - // Update the password in the users table to the new format and remove user_pass_convert flag - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_password = \'' . $db->sql_escape($hash) . '\', - user_pass_convert = 0 - WHERE user_id = ' . $row['user_id']; - $db->sql_query($sql); - - $row['user_pass_convert'] = 0; - $row['user_password'] = $hash; - } - else - { - // Although we weren't able to convert this password we have to - // increase login attempt count to make sure this cannot be exploited - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_login_attempts = user_login_attempts + 1 - WHERE user_id = ' . (int) $row['user_id'] . ' - AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX; - $db->sql_query($sql); - - return array( - 'status' => LOGIN_ERROR_PASSWORD_CONVERT, - 'error_msg' => 'LOGIN_ERROR_PASSWORD_CONVERT', - 'user_row' => $row, - ); - } - } - } - - // Check password ... - if (!$row['user_pass_convert'] && phpbb_check_hash($password, $row['user_password'])) - { - // Check for old password hash... - if (strlen($row['user_password']) == 32) - { - $hash = phpbb_hash($password); - - // Update the password in the users table to the new format - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_password = '" . $db->sql_escape($hash) . "', - user_pass_convert = 0 - WHERE user_id = {$row['user_id']}"; - $db->sql_query($sql); - - $row['user_password'] = $hash; - } - - $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE user_id = ' . $row['user_id']; - $db->sql_query($sql); - - if ($row['user_login_attempts'] != 0) - { - // Successful, reset login attempts (the user passed all stages) - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_login_attempts = 0 - WHERE user_id = ' . $row['user_id']; - $db->sql_query($sql); - } - - // User inactive... - if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) - { - return array( - 'status' => LOGIN_ERROR_ACTIVE, - 'error_msg' => 'ACTIVE_ERROR', - 'user_row' => $row, - ); - } - - // Successful login... set user_login_attempts to zero... - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - - // Password incorrect - increase login attempts - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_login_attempts = user_login_attempts + 1 - WHERE user_id = ' . (int) $row['user_id'] . ' - AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX; - $db->sql_query($sql); - - // Give status about wrong password... - return array( - 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD, - 'error_msg' => ($show_captcha) ? 'LOGIN_ERROR_ATTEMPTS' : 'LOGIN_ERROR_PASSWORD', - 'user_row' => $row, - ); -} - -?> diff --git a/phpBB/includes/auth/auth_ldap.php b/phpBB/includes/auth/auth_ldap.php deleted file mode 100644 index 63796a474b..0000000000 --- a/phpBB/includes/auth/auth_ldap.php +++ /dev/null @@ -1,353 +0,0 @@ -<?php -/** -* -* LDAP auth plug-in for phpBB3 -* -* Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him. -* -* @package login -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Connect to ldap server -* Only allow changing authentication to ldap if we can connect to the ldap server -* Called in acp_board while setting authentication plugins -*/ -function init_ldap() -{ - global $config, $user; - - if (!@extension_loaded('ldap')) - { - return $user->lang['LDAP_NO_LDAP_EXTENSION']; - } - - $config['ldap_port'] = (int) $config['ldap_port']; - if ($config['ldap_port']) - { - $ldap = @ldap_connect($config['ldap_server'], $config['ldap_port']); - } - else - { - $ldap = @ldap_connect($config['ldap_server']); - } - - if (!$ldap) - { - return $user->lang['LDAP_NO_SERVER_CONNECTION']; - } - - @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); - @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); - - if ($config['ldap_user'] || $config['ldap_password']) - { - if (!@ldap_bind($ldap, htmlspecialchars_decode($config['ldap_user']), htmlspecialchars_decode($config['ldap_password']))) - { - return $user->lang['LDAP_INCORRECT_USER_PASSWORD']; - } - } - - // ldap_connect only checks whether the specified server is valid, so the connection might still fail - $search = @ldap_search( - $ldap, - htmlspecialchars_decode($config['ldap_base_dn']), - ldap_user_filter($user->data['username']), - (empty($config['ldap_email'])) ? - array(htmlspecialchars_decode($config['ldap_uid'])) : - array(htmlspecialchars_decode($config['ldap_uid']), htmlspecialchars_decode($config['ldap_email'])), - 0, - 1 - ); - - if ($search === false) - { - return $user->lang['LDAP_SEARCH_FAILED']; - } - - $result = @ldap_get_entries($ldap, $search); - - @ldap_close($ldap); - - - if (!is_array($result) || sizeof($result) < 2) - { - return sprintf($user->lang['LDAP_NO_IDENTITY'], $user->data['username']); - } - - if (!empty($config['ldap_email']) && !isset($result[0][htmlspecialchars_decode($config['ldap_email'])])) - { - return $user->lang['LDAP_NO_EMAIL']; - } - - return false; -} - -/** -* Login function -*/ -function login_ldap(&$username, &$password) -{ - global $db, $config, $user; - - // do not allow empty password - if (!$password) - { - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'NO_PASSWORD_SUPPLIED', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!$username) - { - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - if (!@extension_loaded('ldap')) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LDAP_NO_LDAP_EXTENSION', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - $config['ldap_port'] = (int) $config['ldap_port']; - if ($config['ldap_port']) - { - $ldap = @ldap_connect($config['ldap_server'], $config['ldap_port']); - } - else - { - $ldap = @ldap_connect($config['ldap_server']); - } - - if (!$ldap) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LDAP_NO_SERVER_CONNECTION', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - - @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); - @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); - - if ($config['ldap_user'] || $config['ldap_password']) - { - if (!@ldap_bind($ldap, htmlspecialchars_decode($config['ldap_user']), htmlspecialchars_decode($config['ldap_password']))) - { - return array( - 'status' => LOGIN_ERROR_EXTERNAL_AUTH, - 'error_msg' => 'LDAP_NO_SERVER_CONNECTION', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - } - - $search = @ldap_search( - $ldap, - htmlspecialchars_decode($config['ldap_base_dn']), - ldap_user_filter($username), - (empty($config['ldap_email'])) ? - array(htmlspecialchars_decode($config['ldap_uid'])) : - array(htmlspecialchars_decode($config['ldap_uid']), htmlspecialchars_decode($config['ldap_email'])), - 0, - 1 - ); - - $ldap_result = @ldap_get_entries($ldap, $search); - - if (is_array($ldap_result) && sizeof($ldap_result) > 1) - { - if (@ldap_bind($ldap, $ldap_result[0]['dn'], htmlspecialchars_decode($password))) - { - @ldap_close($ldap); - - $sql ='SELECT user_id, username, user_password, user_passchg, user_email, user_type - FROM ' . USERS_TABLE . " - WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - unset($ldap_result); - - // User inactive... - if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) - { - return array( - 'status' => LOGIN_ERROR_ACTIVE, - 'error_msg' => 'ACTIVE_ERROR', - 'user_row' => $row, - ); - } - - // Successful login... set user_login_attempts to zero... - return array( - 'status' => LOGIN_SUCCESS, - 'error_msg' => false, - 'user_row' => $row, - ); - } - else - { - // retrieve default group id - $sql = 'SELECT group_id - FROM ' . GROUPS_TABLE . " - WHERE group_name = '" . $db->sql_escape('REGISTERED') . "' - AND group_type = " . GROUP_SPECIAL; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row) - { - trigger_error('NO_GROUP'); - } - - // generate user account data - $ldap_user_row = array( - 'username' => $username, - 'user_password' => phpbb_hash($password), - 'user_email' => (!empty($config['ldap_email'])) ? utf8_htmlspecialchars($ldap_result[0][htmlspecialchars_decode($config['ldap_email'])][0]) : '', - 'group_id' => (int) $row['group_id'], - 'user_type' => USER_NORMAL, - 'user_ip' => $user->ip, - 'user_new' => ($config['new_member_post_limit']) ? 1 : 0, - ); - - unset($ldap_result); - - // this is the user's first login so create an empty profile - return array( - 'status' => LOGIN_SUCCESS_CREATE_PROFILE, - 'error_msg' => false, - 'user_row' => $ldap_user_row, - ); - } - } - else - { - unset($ldap_result); - @ldap_close($ldap); - - // Give status about wrong password... - return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'LOGIN_ERROR_PASSWORD', - 'user_row' => array('user_id' => ANONYMOUS), - ); - } - } - - @ldap_close($ldap); - - return array( - 'status' => LOGIN_ERROR_USERNAME, - 'error_msg' => 'LOGIN_ERROR_USERNAME', - 'user_row' => array('user_id' => ANONYMOUS), - ); -} - -/** -* Generates a filter string for ldap_search to find a user -* -* @param $username string Username identifying the searched user -* -* @return string A filter string for ldap_search -*/ -function ldap_user_filter($username) -{ - global $config; - - $filter = '(' . $config['ldap_uid'] . '=' . phpbb_ldap_escape(htmlspecialchars_decode($username)) . ')'; - if ($config['ldap_user_filter']) - { - $_filter = ($config['ldap_user_filter'][0] == '(' && substr($config['ldap_user_filter'], -1) == ')') ? $config['ldap_user_filter'] : "({$config['ldap_user_filter']})"; - $filter = "(&{$filter}{$_filter})"; - } - return $filter; -} - -/** -* Escapes an LDAP AttributeValue -*/ -function phpbb_ldap_escape($string) -{ - return str_replace(array('*', '\\', '(', ')'), array('\\*', '\\\\', '\\(', '\\)'), $string); -} - -/** -* This function is used to output any required fields in the authentication -* admin panel. It also defines any required configuration table fields. -*/ -function acp_ldap(&$new) -{ - global $user; - - $tpl = ' - - <dl> - <dt><label for="ldap_server">' . $user->lang['LDAP_SERVER'] . ':</label><br /><span>' . $user->lang['LDAP_SERVER_EXPLAIN'] . '</span></dt> - <dd><input type="text" id="ldap_server" size="40" name="config[ldap_server]" value="' . $new['ldap_server'] . '" /></dd> - </dl> - <dl> - <dt><label for="ldap_port">' . $user->lang['LDAP_PORT'] . ':</label><br /><span>' . $user->lang['LDAP_PORT_EXPLAIN'] . '</span></dt> - <dd><input type="text" id="ldap_port" size="40" name="config[ldap_port]" value="' . $new['ldap_port'] . '" /></dd> - </dl> - <dl> - <dt><label for="ldap_dn">' . $user->lang['LDAP_DN'] . ':</label><br /><span>' . $user->lang['LDAP_DN_EXPLAIN'] . '</span></dt> - <dd><input type="text" id="ldap_dn" size="40" name="config[ldap_base_dn]" value="' . $new['ldap_base_dn'] . '" /></dd> - </dl> - <dl> - <dt><label for="ldap_uid">' . $user->lang['LDAP_UID'] . ':</label><br /><span>' . $user->lang['LDAP_UID_EXPLAIN'] . '</span></dt> - <dd><input type="text" id="ldap_uid" size="40" name="config[ldap_uid]" value="' . $new['ldap_uid'] . '" /></dd> - </dl> - <dl> - <dt><label for="ldap_user_filter">' . $user->lang['LDAP_USER_FILTER'] . ':</label><br /><span>' . $user->lang['LDAP_USER_FILTER_EXPLAIN'] . '</span></dt> - <dd><input type="text" id="ldap_user_filter" size="40" name="config[ldap_user_filter]" value="' . $new['ldap_user_filter'] . '" /></dd> - </dl> - <dl> - <dt><label for="ldap_email">' . $user->lang['LDAP_EMAIL'] . ':</label><br /><span>' . $user->lang['LDAP_EMAIL_EXPLAIN'] . '</span></dt> - <dd><input type="text" id="ldap_email" size="40" name="config[ldap_email]" value="' . $new['ldap_email'] . '" /></dd> - </dl> - <dl> - <dt><label for="ldap_user">' . $user->lang['LDAP_USER'] . ':</label><br /><span>' . $user->lang['LDAP_USER_EXPLAIN'] . '</span></dt> - <dd><input type="text" id="ldap_user" size="40" name="config[ldap_user]" value="' . $new['ldap_user'] . '" /></dd> - </dl> - <dl> - <dt><label for="ldap_password">' . $user->lang['LDAP_PASSWORD'] . ':</label><br /><span>' . $user->lang['LDAP_PASSWORD_EXPLAIN'] . '</span></dt> - <dd><input type="password" id="ldap_password" size="40" name="config[ldap_password]" value="' . $new['ldap_password'] . '" autocomplete="off" /></dd> - </dl> - '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => array('ldap_server', 'ldap_port', 'ldap_base_dn', 'ldap_uid', 'ldap_user_filter', 'ldap_email', 'ldap_user', 'ldap_password') - ); -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/auth/index.htm b/phpBB/includes/auth/index.htm deleted file mode 100644 index ee1f723a7d..0000000000 --- a/phpBB/includes/auth/index.htm +++ /dev/null @@ -1,10 +0,0 @@ -<html> -<head> -<title></title> -<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> -</head> - -<body bgcolor="#FFFFFF" text="#000000"> - -</body> -</html> diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php index 3c25fd6587..5f6dcde448 100644 --- a/phpBB/includes/bbcode.php +++ b/phpBB/includes/bbcode.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,7 +21,6 @@ if (!defined('IN_PHPBB')) /** * BBCode class -* @package phpBB3 */ class bbcode { @@ -30,7 +32,6 @@ class bbcode var $bbcodes = array(); var $template_bitfield; - var $template_filename = ''; /** * Constructor @@ -128,33 +129,16 @@ class bbcode */ function bbcode_cache_init() { - global $phpbb_root_path, $template, $user; + global $phpbb_root_path, $phpEx, $config, $user, $phpbb_dispatcher, $phpbb_extension_manager, $phpbb_path_helper; if (empty($this->template_filename)) { - $this->template_bitfield = new bitfield($user->theme['bbcode_bitfield']); - $this->template_filename = $phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template/bbcode.html'; - - if (empty($user->theme['template_inherits_id']) && !empty($template->orig_tpl_inherits_id)) - { - $user->theme['template_inherits_id'] = $template->orig_tpl_inherits_id; - } + $this->template_bitfield = new bitfield($user->style['bbcode_bitfield']); - if (!@file_exists($this->template_filename)) - { - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id']) - { - $this->template_filename = $phpbb_root_path . 'styles/' . $user->theme['template_inherit_path'] . '/template/bbcode.html'; - if (!@file_exists($this->template_filename)) - { - trigger_error('The file ' . $this->template_filename . ' is missing.', E_USER_ERROR); - } - } - else - { - trigger_error('The file ' . $this->template_filename . ' is missing.', E_USER_ERROR); - } - } + $template = new phpbb\template\twig\twig($phpbb_path_helper, $config, $user, new phpbb\template\context(), $phpbb_extension_manager); + $template->set_style(); + $template->set_filenames(array('bbcode.html' => 'bbcode.html')); + $this->template_filename = $template->get_source_file_for_handle('bbcode.html'); } $bbcode_ids = $rowset = $sql = array(); @@ -404,6 +388,26 @@ class bbcode break; } } + + $bbcode_cache = $this->bbcode_cache; + $bbcode_bitfield = $this->bbcode_bitfield; + $bbcode_uid = $this->bbcode_uid; + + /** + * Use this event to modify the bbcode_cache + * + * @event core.bbcode_cache_init_end + * @var array bbcode_cache The array of cached search and replace patterns of bbcodes + * @var string bbcode_bitfield The bbcode bitfield + * @var string bbcode_uid The bbcode uid + * @since 3.1.3-RC1 + */ + $vars = array('bbcode_cache', 'bbcode_bitfield', 'bbcode_uid'); + extract($phpbb_dispatcher->trigger_event('core.bbcode_cache_init_end', compact($vars))); + + $this->bbcode_cache = $bbcode_cache; + $this->bbcode_bitfield = $bbcode_bitfield; + $this->bbcode_uid = $bbcode_uid; } /** @@ -423,7 +427,7 @@ class bbcode 'i_close' => '</span>', 'u_open' => '<span style="text-decoration: underline">', 'u_close' => '</span>', - 'img' => '<img src="$1" alt="' . $user->lang['IMAGE'] . '" />', + 'img' => '<img src="$1" class="postimage" alt="' . $user->lang['IMAGE'] . '" />', 'size' => '<span style="font-size: $1%; line-height: normal">$2</span>', 'color' => '<span style="color: $1">$2</span>', 'email' => '<a href="mailto:$1">$2</a>' @@ -610,5 +614,3 @@ class bbcode return $code; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/cache.php b/phpBB/includes/cache.php deleted file mode 100644 index 612adcca4f..0000000000 --- a/phpBB/includes/cache.php +++ /dev/null @@ -1,437 +0,0 @@ -<?php -/** -* -* @package acm -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Class for grabbing/handling cached entries, extends acm_file or acm_db depending on the setup -* @package acm -*/ -class cache extends acm -{ - /** - * Get config values - */ - function obtain_config() - { - global $db; - - if (($config = $this->get('config')) !== false) - { - $sql = 'SELECT config_name, config_value - FROM ' . CONFIG_TABLE . ' - WHERE is_dynamic = 1'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $config[$row['config_name']] = $row['config_value']; - } - $db->sql_freeresult($result); - } - else - { - $config = $cached_config = array(); - - $sql = 'SELECT config_name, config_value, is_dynamic - FROM ' . CONFIG_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if (!$row['is_dynamic']) - { - $cached_config[$row['config_name']] = $row['config_value']; - } - - $config[$row['config_name']] = $row['config_value']; - } - $db->sql_freeresult($result); - - $this->put('config', $cached_config); - } - - return $config; - } - - /** - * Obtain list of naughty words and build preg style replacement arrays for use by the - * calling script - */ - function obtain_word_list() - { - global $db; - - if (($censors = $this->get('_word_censors')) === false) - { - $sql = 'SELECT word, replacement - FROM ' . WORDS_TABLE; - $result = $db->sql_query($sql); - - $censors = array(); - while ($row = $db->sql_fetchrow($result)) - { - $censors['match'][] = get_censor_preg_expression($row['word']); - $censors['replace'][] = $row['replacement']; - } - $db->sql_freeresult($result); - - $this->put('_word_censors', $censors); - } - - return $censors; - } - - /** - * Obtain currently listed icons - */ - function obtain_icons() - { - if (($icons = $this->get('_icons')) === false) - { - global $db; - - // Topic icons - $sql = 'SELECT * - FROM ' . ICONS_TABLE . ' - ORDER BY icons_order'; - $result = $db->sql_query($sql); - - $icons = array(); - while ($row = $db->sql_fetchrow($result)) - { - $icons[$row['icons_id']]['img'] = $row['icons_url']; - $icons[$row['icons_id']]['width'] = (int) $row['icons_width']; - $icons[$row['icons_id']]['height'] = (int) $row['icons_height']; - $icons[$row['icons_id']]['display'] = (bool) $row['display_on_posting']; - } - $db->sql_freeresult($result); - - $this->put('_icons', $icons); - } - - return $icons; - } - - /** - * Obtain ranks - */ - function obtain_ranks() - { - if (($ranks = $this->get('_ranks')) === false) - { - global $db; - - $sql = 'SELECT * - FROM ' . RANKS_TABLE . ' - ORDER BY rank_min DESC'; - $result = $db->sql_query($sql); - - $ranks = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['rank_special']) - { - $ranks['special'][$row['rank_id']] = array( - 'rank_title' => $row['rank_title'], - 'rank_image' => $row['rank_image'] - ); - } - else - { - $ranks['normal'][] = array( - 'rank_title' => $row['rank_title'], - 'rank_min' => $row['rank_min'], - 'rank_image' => $row['rank_image'] - ); - } - } - $db->sql_freeresult($result); - - $this->put('_ranks', $ranks); - } - - return $ranks; - } - - /** - * Obtain allowed extensions - * - * @param mixed $forum_id If false then check for private messaging, if int then check for forum id. If true, then only return extension informations. - * - * @return array allowed extensions array. - */ - function obtain_attach_extensions($forum_id) - { - if (($extensions = $this->get('_extensions')) === false) - { - global $db; - - $extensions = array( - '_allowed_post' => array(), - '_allowed_pm' => array(), - ); - - // The rule is to only allow those extensions defined. ;) - $sql = 'SELECT e.extension, g.* - FROM ' . EXTENSIONS_TABLE . ' e, ' . EXTENSION_GROUPS_TABLE . ' g - WHERE e.group_id = g.group_id - AND (g.allow_group = 1 OR g.allow_in_pm = 1)'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $extension = strtolower(trim($row['extension'])); - - $extensions[$extension] = array( - 'display_cat' => (int) $row['cat_id'], - 'download_mode' => (int) $row['download_mode'], - 'upload_icon' => trim($row['upload_icon']), - 'max_filesize' => (int) $row['max_filesize'], - 'allow_group' => $row['allow_group'], - 'allow_in_pm' => $row['allow_in_pm'], - ); - - $allowed_forums = ($row['allowed_forums']) ? unserialize(trim($row['allowed_forums'])) : array(); - - // Store allowed extensions forum wise - if ($row['allow_group']) - { - $extensions['_allowed_post'][$extension] = (!sizeof($allowed_forums)) ? 0 : $allowed_forums; - } - - if ($row['allow_in_pm']) - { - $extensions['_allowed_pm'][$extension] = 0; - } - } - $db->sql_freeresult($result); - - $this->put('_extensions', $extensions); - } - - // Forum post - if ($forum_id === false) - { - // We are checking for private messages, therefore we only need to get the pm extensions... - $return = array('_allowed_' => array()); - - foreach ($extensions['_allowed_pm'] as $extension => $check) - { - $return['_allowed_'][$extension] = 0; - $return[$extension] = $extensions[$extension]; - } - - $extensions = $return; - } - else if ($forum_id === true) - { - return $extensions; - } - else - { - $forum_id = (int) $forum_id; - $return = array('_allowed_' => array()); - - foreach ($extensions['_allowed_post'] as $extension => $check) - { - // Check for allowed forums - if (is_array($check)) - { - $allowed = (!in_array($forum_id, $check)) ? false : true; - } - else - { - $allowed = true; - } - - if ($allowed) - { - $return['_allowed_'][$extension] = 0; - $return[$extension] = $extensions[$extension]; - } - } - - $extensions = $return; - } - - if (!isset($extensions['_allowed_'])) - { - $extensions['_allowed_'] = array(); - } - - return $extensions; - } - - /** - * Obtain active bots - */ - function obtain_bots() - { - if (($bots = $this->get('_bots')) === false) - { - global $db; - - switch ($db->sql_layer) - { - case 'mssql': - case 'mssql_odbc': - case 'mssqlnative': - $sql = 'SELECT user_id, bot_agent, bot_ip - FROM ' . BOTS_TABLE . ' - WHERE bot_active = 1 - ORDER BY LEN(bot_agent) DESC'; - break; - - case 'firebird': - $sql = 'SELECT user_id, bot_agent, bot_ip - FROM ' . BOTS_TABLE . ' - WHERE bot_active = 1 - ORDER BY CHAR_LENGTH(bot_agent) DESC'; - break; - - // LENGTH supported by MySQL, IBM DB2 and Oracle for sure... - default: - $sql = 'SELECT user_id, bot_agent, bot_ip - FROM ' . BOTS_TABLE . ' - WHERE bot_active = 1 - ORDER BY LENGTH(bot_agent) DESC'; - break; - } - $result = $db->sql_query($sql); - - $bots = array(); - while ($row = $db->sql_fetchrow($result)) - { - $bots[] = $row; - } - $db->sql_freeresult($result); - - $this->put('_bots', $bots); - } - - return $bots; - } - - /** - * Obtain cfg file data - */ - function obtain_cfg_items($theme) - { - global $config, $phpbb_root_path; - - $parsed_items = array( - 'theme' => array(), - 'template' => array(), - 'imageset' => array() - ); - - foreach ($parsed_items as $key => $parsed_array) - { - $parsed_array = $this->get('_cfg_' . $key . '_' . $theme[$key . '_path']); - - if ($parsed_array === false) - { - $parsed_array = array(); - } - - $reparse = false; - $filename = $phpbb_root_path . 'styles/' . $theme[$key . '_path'] . '/' . $key . '/' . $key . '.cfg'; - - if (!file_exists($filename)) - { - continue; - } - - if (!isset($parsed_array['filetime']) || (($config['load_tplcompile'] && @filemtime($filename) > $parsed_array['filetime']))) - { - $reparse = true; - } - - // Re-parse cfg file - if ($reparse) - { - $parsed_array = parse_cfg_file($filename); - $parsed_array['filetime'] = @filemtime($filename); - - $this->put('_cfg_' . $key . '_' . $theme[$key . '_path'], $parsed_array); - } - $parsed_items[$key] = $parsed_array; - } - - return $parsed_items; - } - - /** - * Obtain disallowed usernames - */ - function obtain_disallowed_usernames() - { - if (($usernames = $this->get('_disallowed_usernames')) === false) - { - global $db; - - $sql = 'SELECT disallow_username - FROM ' . DISALLOW_TABLE; - $result = $db->sql_query($sql); - - $usernames = array(); - while ($row = $db->sql_fetchrow($result)) - { - $usernames[] = str_replace('%', '.*?', preg_quote(utf8_clean_string($row['disallow_username']), '#')); - } - $db->sql_freeresult($result); - - $this->put('_disallowed_usernames', $usernames); - } - - return $usernames; - } - - /** - * Obtain hooks... - */ - function obtain_hooks() - { - global $phpbb_root_path, $phpEx; - - if (($hook_files = $this->get('_hooks')) === false) - { - $hook_files = array(); - - // Now search for hooks... - $dh = @opendir($phpbb_root_path . 'includes/hooks/'); - - if ($dh) - { - while (($file = readdir($dh)) !== false) - { - if (strpos($file, 'hook_') === 0 && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx) - { - $hook_files[] = substr($file, 0, -(strlen($phpEx) + 1)); - } - } - closedir($dh); - } - - $this->put('_hooks', $hook_files); - } - - return $hook_files; - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/captcha_factory.php b/phpBB/includes/captcha/captcha_factory.php deleted file mode 100644 index 131c0b3b77..0000000000 --- a/phpBB/includes/captcha/captcha_factory.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2008 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* A small class for 3.0.x (no autoloader in 3.0.x) -* -* @package VC -*/ -class phpbb_captcha_factory -{ - /** - * return an instance of class $name in file $name_plugin.php - */ - function &get_instance($name) - { - global $phpbb_root_path, $phpEx; - - $name = basename($name); - if (!class_exists($name)) - { - include($phpbb_root_path . "includes/captcha/plugins/{$name}_plugin." . $phpEx); - } - $instance = call_user_func(array($name, 'get_instance')); - return $instance; - } - - /** - * Call the garbage collector - */ - function garbage_collect($name) - { - global $phpbb_root_path, $phpEx; - - $name = basename($name); - if (!class_exists($name)) - { - include($phpbb_root_path . "includes/captcha/plugins/{$name}_plugin." . $phpEx); - } - call_user_func(array($name, 'garbage_collect'), 0); - } - - /** - * return a list of all discovered CAPTCHA plugins - */ - function get_captcha_types() - { - global $phpbb_root_path, $phpEx; - - $captchas = array( - 'available' => array(), - 'unavailable' => array(), - ); - - $dp = @opendir($phpbb_root_path . 'includes/captcha/plugins'); - - if ($dp) - { - while (($file = readdir($dp)) !== false) - { - if ((preg_match('#_plugin\.' . $phpEx . '$#', $file))) - { - $name = preg_replace('#^(.*?)_plugin\.' . $phpEx . '$#', '\1', $file); - if (!class_exists($name)) - { - include($phpbb_root_path . "includes/captcha/plugins/$file"); - } - - if (call_user_func(array($name, 'is_available'))) - { - $captchas['available'][$name] = call_user_func(array($name, 'get_name')); - } - else - { - $captchas['unavailable'][$name] = call_user_func(array($name, 'get_name')); - } - } - } - closedir($dp); - } - - return $captchas; - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/captcha_gd.php b/phpBB/includes/captcha/captcha_gd.php deleted file mode 100644 index ecdad43978..0000000000 --- a/phpBB/includes/captcha/captcha_gd.php +++ /dev/null @@ -1,2640 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Original Author - Xore (Robert Hetzler) -* With contributions from Neothermic -* -* @package VC -*/ -class captcha -{ - var $width = 360; - var $height = 96; - - - /** - * Create the image containing $code with a seed of $seed - */ - function execute($code, $seed) - { - global $config; - - mt_srand($seed); - - // Create image - $img = imagecreatetruecolor($this->width, $this->height); - - // Generate colours - $colour = new colour_manager($img, array( - 'random' => true, - 'min_value' => 60, - ), 'hsv'); - - $scheme = $colour->colour_scheme('background', false); - $scheme = $colour->mono_range($scheme, 10, false); - shuffle($scheme); - - $bg_colours = array_splice($scheme, mt_rand(6, 12)); - - // Generate code characters - $characters = $sizes = $bounding_boxes = $noise = array(); - $width_avail = $this->width - 15; - $code_len = strlen($code); - $captcha_bitmaps = $this->captcha_bitmaps(); - - for ($i = 0; $i < $code_len; ++$i) - { - $characters[$i] = new char_cube3d($captcha_bitmaps, $code[$i]); - - list($min, $max) = $characters[$i]->range(); - $sizes[$i] = mt_rand($min, $max); - - $box = $characters[$i]->dimensions($sizes[$i]); - $width_avail -= ($box[2] - $box[0]); - $bounding_boxes[$i] = $box; - } - - - // Redistribute leftover x-space - $offset = array(); - for ($i = 0; $i < $code_len; ++$i) - { - $denom = ($code_len - $i); - $denom = max(1.3, $denom); - $offset[$i] = phpbb_mt_rand(0, (int) round((1.5 * $width_avail) / $denom)); - $width_avail -= $offset[$i]; - } - - if ($config['captcha_gd_x_grid']) - { - $grid = (int) $config['captcha_gd_x_grid']; - for ($y = 0; $y < $this->height; $y += mt_rand($grid - 2, $grid + 2)) - { - $current_colour = $scheme[array_rand($scheme)]; - imageline($img, mt_rand(0,4), mt_rand($y - 3, $y), mt_rand($this->width - 5, $this->width), mt_rand($y - 3, $y), $current_colour); - } - } - - if ($config['captcha_gd_y_grid']) - { - $grid = (int) $config['captcha_gd_y_grid']; - for ($x = 0; $x < $this->width; $x += mt_rand($grid - 2, $grid + 2)) - { - $current_colour = $scheme[array_rand($scheme)]; - imagedashedline($img, mt_rand($x -3, $x + 3), mt_rand(0, 4), mt_rand($x -3, $x + 3), mt_rand($this->height - 5, $this->height), $current_colour); - } - } - if ($config['captcha_gd_wave'] && ($config['captcha_gd_y_grid'] || $config['captcha_gd_y_grid'])) - { - $this->wave($img); - } - - - if ($config['captcha_gd_3d_noise']) - { - $xoffset = mt_rand(0,9); - $noise_bitmaps = $this->captcha_noise_bg_bitmaps(); - for ($i = 0; $i < $code_len; ++$i) - { - $noise[$i] = new char_cube3d($noise_bitmaps, mt_rand(1, sizeof($noise_bitmaps['data']))); - - list($min, $max) = $noise[$i]->range(); - //$box = $noise[$i]->dimensions($sizes[$i]); - } - $xoffset = 0; - for ($i = 0; $i < $code_len; ++$i) - { - $dimm = $bounding_boxes[$i]; - $xoffset += ($offset[$i] - $dimm[0]); - $yoffset = mt_rand(-$dimm[1], $this->height - $dimm[3]); - - $noise[$i]->drawchar($sizes[$i], $xoffset, $yoffset, $img, $colour->get_resource('background'), $scheme); - $xoffset += $dimm[2]; - } - } - $xoffset = 5; - for ($i = 0; $i < $code_len; ++$i) - { - $dimm = $bounding_boxes[$i]; - $xoffset += ($offset[$i] - $dimm[0]); - $yoffset = mt_rand(-$dimm[1], $this->height - $dimm[3]); - - $characters[$i]->drawchar($sizes[$i], $xoffset, $yoffset, $img, $colour->get_resource('background'), $scheme); - $xoffset += $dimm[2]; - } - if ($config['captcha_gd_wave']) - { - $this->wave($img); - } - if ($config['captcha_gd_foreground_noise']) - { - $this->noise_line($img, 0, 0, $this->width, $this->height, $colour->get_resource('background'), $scheme, $bg_colours); - } - // Send image - header('Content-Type: image/png'); - header('Cache-control: no-cache, no-store'); - imagepng($img); - imagedestroy($img); - } - - /** - * Sinus - */ - function wave($img) - { - global $config; - - $period_x = mt_rand(12,18); - $period_y = mt_rand(7,14); - $amp_x = mt_rand(5,10); - $amp_y = mt_rand(2,4); - $socket = mt_rand(0,100); - - $dampen_x = mt_rand($this->width/5, $this->width/2); - $dampen_y = mt_rand($this->height/5, $this->height/2); - $direction_x = (mt_rand (0, 1)); - $direction_y = (mt_rand (0, 1)); - - for ($i = 0; $i < $this->width; $i++) - { - $dir = ($direction_x) ? $i : ($this->width - $i); - imagecopy($img, $img, $i-1, sin($socket+ $i/($period_x + $dir/$dampen_x)) * $amp_x, $i, 0, 1, $this->height); - } - $socket = mt_rand(0,100); - for ($i = 0; $i < $this->height; $i++) - { - $dir = ($direction_y) ? $i : ($this->height - $i); - imagecopy($img, $img ,sin($socket + $i/($period_y + ($dir)/$dampen_y)) * $amp_y, $i-1, 0, $i, $this->width, 1); - } - return $img; - } - - /** - * Noise line - */ - function noise_line($img, $min_x, $min_y, $max_x, $max_y, $bg, $font, $non_font) - { - imagesetthickness($img, 2); - - $x1 = $min_x; - $x2 = $max_x; - $y1 = $min_y; - $y2 = $min_y; - - do - { - $line = array_merge( - array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]), - array_fill(0, mt_rand(30, 60), $bg) - ); - - imagesetstyle($img, $line); - imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); - - $y1 += mt_rand(12, 35); - $y2 += mt_rand(12, 35); - } - while ($y1 < $max_y && $y2 < $max_y); - - $x1 = $min_x; - $x2 = $min_x; - $y1 = $min_y; - $y2 = $max_y; - - do - { - $line = array_merge( - array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]), - array_fill(0, mt_rand(30, 60), $bg) - ); - - imagesetstyle($img, $line); - imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); - - $x1 += mt_rand(20, 35); - $x2 += mt_rand(20, 35); - } - while ($x1 < $max_x && $x2 < $max_x); - imagesetthickness($img, 1); - } - - - function captcha_noise_bg_bitmaps() - { - return array( - 'width' => 15, - 'height' => 5, - 'data' => array( - - 1 => array( - array(1,0,0,0,1,0,0,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,1,0,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,1,0,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0,0,0,1,0,0,0), - ), - 2 => array( - array(1,1,mt_rand(0,1),1,0,1,1,1,1,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,1,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0,1,1,0,1,1,1), - ), - 3 => array( - array(1,0,0,0,0,0,0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0,0,0,0,0,1,0), - array(0,0,0,0,1,0,0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,0,0,0,0,0,0,1), - ), - 4 => array( - array(1,0,1,0,1,0,0,1,1,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,1,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(1,0,1,0,0,0,0,0,0,0,0,0,0,0,0), - ), - 5 => array( - array(1,1,1,1,0,0,0,1,1,1,0,0,1,0,1), - array(0,0,0,0,0,0,0,1,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(1,0,1,0,0,0,0,0,0,0,0,0,0,0,0), - ), - 6 => array( - array(mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),0,mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),mt_rand(0,1),0,mt_rand(0,1),mt_rand(0,1),mt_rand(0,1)), - array(0,0,0,0,0,0,0,mt_rand(0,1),0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(mt_rand(0,1),0,mt_rand(0,1),0,0,0,0,0,0,0,0,0,0,0,0), - ), - 7 => array( - array(0,0,0,0,0,0,0,0,0,0,1,1,0,1,1), - array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - array(0,0,1,1,0,0,0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,1,0,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0), - ), - )); - } - - /** - * Return bitmaps - */ - function captcha_bitmaps() - { - global $config; - - $chars = array( - 'A' => array( - array( - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,1,1,1,1,1,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,1,1,0,1,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,1,1,1,1,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,0,0,0,1,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,1,1,0,0,0,1,1,0), - array(1,1,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,1), - array(0,0,0,0,0,1,1,1,1), - array(0,0,0,1,1,1,0,0,1), - array(0,1,1,1,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,1,0,0,0,0,1,1,1), - array(0,1,1,1,1,1,1,0,1), - ), - ), - 'B' => array( - array( - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - ), - array( - array(1,1,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - ), - array( - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,1,1,1,1,0,0), - ), - ), - 'C' => array( - array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - array( - array(0,0,1,1,1,1,1,0,1), - array(0,1,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,1), - array(0,0,1,1,1,1,1,0,1), - ), - ), - 'D' => array( - array( - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - ), - array( - array(1,1,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,1,1,1,1,1,0,1), - array(0,1,1,0,0,0,1,1,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,1,0,0,0,1,1,1), - array(0,0,1,1,1,1,1,0,1), - ), - ), - 'E' => array( - array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,1,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,1,1), - ), - array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,1), - array(1,1,1,1,1,1,1,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,1,1,0,0,0,1,1,0), - array(1,1,0,0,0,0,0,1,1), - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,1), - array(1,1,0,0,0,0,0,1,1), - array(0,1,1,1,1,1,1,1,0), - ), - ), - 'F' => array( - array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - ), - array( - array(0,1,1,1,1,1,1,1,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,1,1,0,0,0,0,0,0), - ), - array( - array(0,0,0,1,1,0,0,0,0), - array(0,0,1,1,0,0,0,0,0), - array(0,1,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,1,1,1,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - ), - ), - 'G' => array( - array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,1,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - array( - array(0,0,1,1,1,1,1,0,1), - array(0,1,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,1,1,1,1,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,1), - array(0,0,1,1,1,1,1,0,1), - ), - array( - array(0,0,1,1,1,1,1,0,1), - array(0,1,1,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,1,1,0,0,0,0,0,1), - array(0,0,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,1), - array(1,1,1,1,1,1,1,1,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - ), - 'H' => array( - array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - ), - array( - array(1,1,1,0,0,0,1,1,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,1,1,1,1,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,0,0,0,1,1,1), - ), - array( - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,1,1,1,0,0,0), - array(1,1,1,1,0,1,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - ), - ), - 'I' => array( - array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(1,1,1,1,1,1,1,1,1), - ), - array( - array(0,0,0,1,1,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,1,1,0,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,1,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,1,1,0,0,0), - ), - ), - 'J' => array( - array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,0,1,1,0,0,0,0,0), - ), - array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,1,0,0,1,0,0,0,0), - array(1,0,1,1,0,0,0,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,0,1,1,0,0,0,0,0), - ), - ), - 'K' => array( - array( // New 'K', supplied by NeoThermic - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,1,0,0,0,0,0), - array(1,0,1,0,0,0,0,0,0), - array(1,1,0,0,0,0,0,0,0), - array(1,0,1,0,0,0,0,0,0), - array(1,0,0,1,0,0,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - ), - array( - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,1,0,0), - array(0,1,0,0,0,1,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,1,0,1,0,0,0,0,0), - array(0,1,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,1,0,0,0,0,0,0), - array(0,1,0,1,0,0,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,1,0,0,0,1,0,0,0), - array(0,1,0,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,0,0,0,1,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,1,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,1,0,1,0,0,0,0,0), - array(0,1,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,1,0,0,0,0,0,0), - array(0,1,0,1,0,0,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,1,0,0,0,1,0,0,0), - array(0,1,0,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - ), - ), - 'L' => array( - array( - array(0,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,1), - array(1,1,1,1,1,1,1,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,1,0,0,0,0,0,0), - array(0,0,1,1,1,0,0,0,0), - ), - ), - 'M' => array( - array( - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,0,0,0,1,1,0), - array(0,1,1,0,0,0,1,1,0), - array(0,1,1,0,0,0,1,1,0), - array(0,1,0,1,0,1,0,1,0), - array(0,1,0,1,0,1,0,1,0), - array(0,1,0,1,0,1,0,1,0), - array(0,1,0,0,1,0,0,1,0), - array(0,1,0,0,1,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,0,0,0,1,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,1,1,1,0,1,1,1,0), - array(1,1,0,1,1,1,0,1,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - ), - ), - 'N' => array( - array( - array(1,1,0,0,0,0,0,0,1), - array(1,1,0,0,0,0,0,0,1), - array(1,0,1,0,0,0,0,0,1), - array(1,0,1,0,0,0,0,0,1), - array(1,0,0,1,0,0,0,0,1), - array(1,0,0,1,0,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,0,1,0,0,1), - array(1,0,0,0,0,1,0,0,1), - array(1,0,0,0,0,0,1,0,1), - array(1,0,0,0,0,0,1,0,1), - array(1,0,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,0,0,0,0,1,0), - array(0,1,1,0,0,0,0,1,0), - array(0,1,1,0,0,0,0,1,0), - array(0,1,0,1,0,0,0,1,0), - array(0,1,0,1,0,0,0,1,0), - array(0,1,0,1,0,0,0,1,0), - array(0,1,0,0,1,0,0,1,0), - array(0,1,0,0,1,1,0,1,0), - array(0,1,0,0,0,1,0,1,0), - array(0,1,0,0,0,1,1,1,0), - array(0,1,0,0,0,0,1,1,0), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,0,0,0,1,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(1,0,1,1,1,1,0,0,0), - array(1,1,1,0,0,1,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - ), - ), - 'O' => array( - array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,1,1,1,1,1,0,0,0), - array(1,1,1,0,0,1,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,1,0,0,0,1,1,0,0), - array(0,1,1,1,1,1,0,0,0), - ), - ), - 'P' => array( - array( - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - ), - array( - array(1,1,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,1,1,0,0,0,0,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,1,1,0,0,0,0,0), - array(1,1,0,1,1,0,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,1,1,0,0,0,0), - array(1,1,1,1,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - ), - ), - 'Q' => array( - array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,1,0,0,1), - array(1,0,0,0,0,0,1,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,1), - ), - array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,1,0,0,1,1,0,1,1), - array(0,1,1,1,1,1,1,1,0), - array(0,0,0,0,0,0,1,1,0), - array(0,0,0,0,0,0,0,1,1), - array(0,0,0,0,0,0,0,0,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,1,1,1,1), - array(0,0,0,0,1,1,0,0,1), - array(0,0,0,0,1,0,0,0,1), - array(0,0,0,0,1,0,0,0,1), - array(0,0,0,0,1,1,0,1,1), - array(0,0,0,0,0,1,1,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - ), - ), - 'R' => array( - array( - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(1,1,1,0,0,0,0,0,0), - array(1,0,0,1,0,0,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - ), - array( - array(1,1,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(0,1,1,0,0,0,0,0,0), - array(0,1,1,1,0,0,0,0,0), - array(0,1,0,1,1,0,0,0,0), - array(0,1,0,0,1,1,0,0,0), - array(0,1,0,0,0,1,1,0,0), - array(0,1,0,0,0,0,1,1,0), - array(1,1,1,0,0,0,1,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,0,0,0,0), - array(1,1,0,0,1,1,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - ), - ), - 'S' => array( - array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - array( - array(0,0,1,1,1,1,1,0,1), - array(0,1,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,1,0,0,0,0,0,1,0), - array(1,0,1,1,1,1,1,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,1,1,1,1,0,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,0,0,0,0,0,0,0), - array(0,1,1,1,1,0,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(1,0,0,0,1,1,0,0,0), - array(0,1,1,1,1,0,0,0,0), - ), - ), - 'T' => array( - array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - ), - array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,1,0,0,0,1), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,1,1,0,0,0), - ), - array( - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,1,1,1,1,1,1,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,1,0,0,0), - array(0,0,0,0,0,1,1,1,0), - ), - ), - 'U' => array( - array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - array( - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,0,0,0,1,1,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,0,0,0,1,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,1), - array(0,0,1,0,0,0,0,0,1), - array(0,0,1,0,0,0,0,0,1), - array(0,0,1,0,0,0,0,0,1), - array(0,0,1,0,0,0,0,0,1), - array(0,0,1,0,0,0,0,1,1), - array(0,0,1,1,0,0,1,1,1), - array(0,0,0,1,1,1,1,0,1), - ), - ), - 'V' => array( - array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(1,1,1,0,0,0,1,1,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - ), - ), - 'W' => array( - array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(1,1,1,0,0,0,1,1,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,1,0,0,1,0), - array(0,1,0,0,1,0,0,1,0), - array(0,1,0,1,1,1,0,1,0), - array(0,1,0,1,0,1,0,1,0), - array(0,1,1,1,0,1,1,1,0), - array(0,1,1,0,0,0,1,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,1,0,0,1,0), - array(0,1,0,0,1,0,0,1,0), - array(0,1,0,1,1,1,0,1,0), - array(0,1,0,1,0,1,0,1,0), - array(0,1,1,1,0,1,1,1,0), - array(0,1,1,0,0,0,1,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,0), - ), - ), - 'X' => array( - array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(1,1,1,0,0,0,1,1,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,1,1,0,0,0,1,1,1), - array(0,0,0,0,0,0,0,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,0,0,0,1,1,0), - array(0,0,1,1,0,1,1,0,0), - array(0,0,0,1,1,1,0,0,0), - array(0,0,0,1,1,1,0,0,0), - array(0,0,1,1,0,1,1,0,0), - array(0,1,1,0,0,0,1,1,0), - array(0,0,0,0,0,0,0,0,0), - ), - ), - 'Y' => array( - array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(1,1,1,0,0,0,1,1,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,1,1,0,0,0), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,1,0,0,0,0,1), - array(0,0,0,1,1,0,0,0,1), - array(0,0,0,0,1,0,0,1,1), - array(0,0,0,0,1,1,0,1,0), - array(0,0,0,0,0,1,1,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,1,0,0,0), - array(0,0,1,1,1,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - ), - 'Z' => array( - array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,1), - array(1,1,1,1,1,1,1,1,1), - ), - array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,1,1), - ), - array( - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,1,1,1,1,1,1,1,0), - array(0,0,0,0,0,1,1,0,0), - array(0,0,0,0,1,1,0,0,0), - array(0,0,0,1,1,0,0,0,0), - array(0,0,1,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,1,1,1,1,1,1,0), - ), - ), - ); - return array( - 'width' => 9, - 'height' => 15, - 'data' => array( - - 'A' => $chars['A'][mt_rand(0, min(sizeof($chars['A']), $config['captcha_gd_fonts']) -1)], - 'B' => $chars['B'][mt_rand(0, min(sizeof($chars['B']), $config['captcha_gd_fonts']) -1)], - 'C' => $chars['C'][mt_rand(0, min(sizeof($chars['C']), $config['captcha_gd_fonts']) -1)], - 'D' => $chars['D'][mt_rand(0, min(sizeof($chars['D']), $config['captcha_gd_fonts']) -1)], - 'E' => $chars['E'][mt_rand(0, min(sizeof($chars['E']), $config['captcha_gd_fonts']) -1)], - 'F' => $chars['F'][mt_rand(0, min(sizeof($chars['F']), $config['captcha_gd_fonts']) -1)], - 'G' => $chars['G'][mt_rand(0, min(sizeof($chars['G']), $config['captcha_gd_fonts']) -1)], - 'H' => $chars['H'][mt_rand(0, min(sizeof($chars['H']), $config['captcha_gd_fonts']) -1)], - 'I' => $chars['I'][mt_rand(0, min(sizeof($chars['I']), $config['captcha_gd_fonts']) -1)], - 'J' => $chars['J'][mt_rand(0, min(sizeof($chars['J']), $config['captcha_gd_fonts']) -1)], - 'K' => $chars['K'][mt_rand(0, min(sizeof($chars['K']), $config['captcha_gd_fonts']) -1)], - 'L' => $chars['L'][mt_rand(0, min(sizeof($chars['L']), $config['captcha_gd_fonts']) -1)], - 'M' => $chars['M'][mt_rand(0, min(sizeof($chars['M']), $config['captcha_gd_fonts']) -1)], - 'N' => $chars['N'][mt_rand(0, min(sizeof($chars['N']), $config['captcha_gd_fonts']) -1)], - 'O' => $chars['O'][mt_rand(0, min(sizeof($chars['O']), $config['captcha_gd_fonts']) -1)], - 'P' => $chars['P'][mt_rand(0, min(sizeof($chars['P']), $config['captcha_gd_fonts']) -1)], - 'Q' => $chars['Q'][mt_rand(0, min(sizeof($chars['Q']), $config['captcha_gd_fonts']) -1)], - 'R' => $chars['R'][mt_rand(0, min(sizeof($chars['R']), $config['captcha_gd_fonts']) -1)], - 'S' => $chars['S'][mt_rand(0, min(sizeof($chars['S']), $config['captcha_gd_fonts']) -1)], - 'T' => $chars['T'][mt_rand(0, min(sizeof($chars['T']), $config['captcha_gd_fonts']) -1)], - 'U' => $chars['U'][mt_rand(0, min(sizeof($chars['U']), $config['captcha_gd_fonts']) -1)], - 'V' => $chars['V'][mt_rand(0, min(sizeof($chars['V']), $config['captcha_gd_fonts']) -1)], - 'W' => $chars['W'][mt_rand(0, min(sizeof($chars['W']), $config['captcha_gd_fonts']) -1)], - 'X' => $chars['X'][mt_rand(0, min(sizeof($chars['X']), $config['captcha_gd_fonts']) -1)], - 'Y' => $chars['Y'][mt_rand(0, min(sizeof($chars['Y']), $config['captcha_gd_fonts']) -1)], - 'Z' => $chars['Z'][mt_rand(0, min(sizeof($chars['Z']), $config['captcha_gd_fonts']) -1)], - - '1' => array( - array(0,0,0,1,1,0,0,0,0), - array(0,0,1,0,1,0,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,1,1,1,1,1,1,1,0), - ), - '2' => array( // New '2' supplied by Anon - array(0,0,0,1,1,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,1,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,0,0), - ), - '3' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - '4' => array( - array(0,0,0,0,0,0,1,1,0), - array(0,0,0,0,0,1,0,1,0), - array(0,0,0,0,1,0,0,1,0), - array(0,0,0,1,0,0,0,1,0), - array(0,0,1,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - ), - '5' => array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - '6' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,1,1,1,1,0,0), - array(1,0,1,0,0,0,0,1,0), - array(1,1,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - '7' => array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - ), - '8' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - '9' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,1), - array(0,1,0,0,0,0,1,0,1), - array(0,0,1,1,1,1,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - ) - ); - } -} - -/** -* @package VC -*/ -class char_cube3d -{ - var $bitmap; - var $bitmap_width; - var $bitmap_height; - - var $basis_matrix = array(array(1, 0, 0), array(0, 1, 0), array(0, 0, 1)); - var $abs_x = array(1, 0); - var $abs_y = array(0, 1); - var $x = 0; - var $y = 1; - var $z = 2; - var $letter = ''; - - /** - */ - function char_cube3d(&$bitmaps, $letter) - { - $this->bitmap = $bitmaps['data'][$letter]; - $this->bitmap_width = $bitmaps['width']; - $this->bitmap_height = $bitmaps['height']; - - $this->basis_matrix[0][0] = mt_rand(-600, 600); - $this->basis_matrix[0][1] = mt_rand(-600, 600); - $this->basis_matrix[0][2] = (mt_rand(0, 1) * 2000) - 1000; - $this->basis_matrix[1][0] = mt_rand(-1000, 1000); - $this->basis_matrix[1][1] = mt_rand(-1000, 1000); - $this->basis_matrix[1][2] = mt_rand(-1000, 1000); - - $this->normalize($this->basis_matrix[0]); - $this->normalize($this->basis_matrix[1]); - $this->basis_matrix[2] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[1]); - $this->normalize($this->basis_matrix[2]); - - // $this->basis_matrix[1] might not be (probably isn't) orthogonal to $basis_matrix[0] - $this->basis_matrix[1] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[2]); - $this->normalize($this->basis_matrix[1]); - - // Make sure our cube is facing into the canvas (assuming +z == in) - for ($i = 0; $i < 3; ++$i) - { - if ($this->basis_matrix[$i][2] < 0) - { - $this->basis_matrix[$i][0] *= -1; - $this->basis_matrix[$i][1] *= -1; - $this->basis_matrix[$i][2] *= -1; - } - } - - // Force our "z" basis vector to be the one with greatest absolute z value - $this->x = 0; - $this->y = 1; - $this->z = 2; - - // Swap "y" with "z" - if ($this->basis_matrix[1][2] > $this->basis_matrix[2][2]) - { - $this->z = 1; - $this->y = 2; - } - - // Swap "x" with "z" - if ($this->basis_matrix[0][2] > $this->basis_matrix[$this->z][2]) - { - $this->x = $this->z; - $this->z = 0; - } - - // Still need to determine which of $x,$y are which. - // wrong orientation if y's y-component is less than it's x-component - // likewise if x's x-component is less than it's y-component - // if they disagree, go with the one with the greater weight difference. - // rotate if positive - $weight = (abs($this->basis_matrix[$this->x][1]) - abs($this->basis_matrix[$this->x][0])) + (abs($this->basis_matrix[$this->y][0]) - abs($this->basis_matrix[$this->y][1])); - - // Swap "x" with "y" - if ($weight > 0) - { - list($this->x, $this->y) = array($this->y, $this->x); - } - - $this->abs_x = array($this->basis_matrix[$this->x][0], $this->basis_matrix[$this->x][1]); - $this->abs_y = array($this->basis_matrix[$this->y][0], $this->basis_matrix[$this->y][1]); - - if ($this->abs_x[0] < 0) - { - $this->abs_x[0] *= -1; - $this->abs_x[1] *= -1; - } - - if ($this->abs_y[1] > 0) - { - $this->abs_y[0] *= -1; - $this->abs_y[1] *= -1; - } - - $this->letter = $letter; - } - - /** - * Draw a character - */ - function drawchar($scale, $xoff, $yoff, $img, $background, $colours) - { - $width = $this->bitmap_width; - $height = $this->bitmap_height; - $bitmap = $this->bitmap; - - $colour1 = $colours[array_rand($colours)]; - $colour2 = $colours[array_rand($colours)]; - - $swapx = ($this->basis_matrix[$this->x][0] > 0); - $swapy = ($this->basis_matrix[$this->y][1] < 0); - - for ($y = 0; $y < $height; ++$y) - { - for ($x = 0; $x < $width; ++$x) - { - $xp = ($swapx) ? ($width - $x - 1) : $x; - $yp = ($swapy) ? ($height - $y - 1) : $y; - - if ($bitmap[$height - $yp - 1][$xp]) - { - $dx = $this->scale($this->abs_x, ($xp - ($swapx ? ($width / 2) : ($width / 2) - 1)) * $scale); - $dy = $this->scale($this->abs_y, ($yp - ($swapy ? ($height / 2) : ($height / 2) - 1)) * $scale); - $xo = $xoff + $dx[0] + $dy[0]; - $yo = $yoff + $dx[1] + $dy[1]; - - $origin = array(0, 0, 0); - $xvec = $this->scale($this->basis_matrix[$this->x], $scale); - $yvec = $this->scale($this->basis_matrix[$this->y], $scale); - $face_corner = $this->sum2($xvec, $yvec); - - $zvec = $this->scale($this->basis_matrix[$this->z], $scale); - $x_corner = $this->sum2($xvec, $zvec); - $y_corner = $this->sum2($yvec, $zvec); - - imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $xvec, $x_corner,$zvec), 4, $colour1); - imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $yvec, $y_corner,$zvec), 4, $colour2); - - $face = $this->gen_poly($xo, $yo, $origin, $xvec, $face_corner, $yvec); - - imagefilledpolygon($img, $face, 4, $background); - imagepolygon($img, $face, 4, $colour1); - } - } - } - } - - /* - * return a roughly acceptable range of sizes for rendering with this texttype - */ - function range() - { - return array(3, 4); - } - - /** - * Vector length - */ - function vectorlen($vector) - { - return sqrt(pow($vector[0], 2) + pow($vector[1], 2) + pow($vector[2], 2)); - } - - /** - * Normalize - */ - function normalize(&$vector, $length = 1) - { - $length = (( $length < 1) ? 1 : $length); - $length /= $this->vectorlen($vector); - $vector[0] *= $length; - $vector[1] *= $length; - $vector[2] *= $length; - } - - /** - */ - function cross_product($vector1, $vector2) - { - $retval = array(0, 0, 0); - $retval[0] = (($vector1[1] * $vector2[2]) - ($vector1[2] * $vector2[1])); - $retval[1] = -(($vector1[0] * $vector2[2]) - ($vector1[2] * $vector2[0])); - $retval[2] = (($vector1[0] * $vector2[1]) - ($vector1[1] * $vector2[0])); - - return $retval; - } - - /** - */ - function sum($vector1, $vector2) - { - return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1], $vector1[2] + $vector2[2]); - } - - /** - */ - function sum2($vector1, $vector2) - { - return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1]); - } - - /** - */ - function scale($vector, $length) - { - if (sizeof($vector) == 2) - { - return array($vector[0] * $length, $vector[1] * $length); - } - - return array($vector[0] * $length, $vector[1] * $length, $vector[2] * $length); - } - - /** - */ - function gen_poly($xoff, $yoff, &$vec1, &$vec2, &$vec3, &$vec4) - { - $poly = array(); - $poly[0] = $xoff + $vec1[0]; - $poly[1] = $yoff + $vec1[1]; - $poly[2] = $xoff + $vec2[0]; - $poly[3] = $yoff + $vec2[1]; - $poly[4] = $xoff + $vec3[0]; - $poly[5] = $yoff + $vec3[1]; - $poly[6] = $xoff + $vec4[0]; - $poly[7] = $yoff + $vec4[1]; - - return $poly; - } - - /** - * dimensions - */ - function dimensions($size) - { - $xn = $this->scale($this->basis_matrix[$this->x], -($this->bitmap_width / 2) * $size); - $xp = $this->scale($this->basis_matrix[$this->x], ($this->bitmap_width / 2) * $size); - $yn = $this->scale($this->basis_matrix[$this->y], -($this->bitmap_height / 2) * $size); - $yp = $this->scale($this->basis_matrix[$this->y], ($this->bitmap_height / 2) * $size); - - $p = array(); - $p[0] = $this->sum2($xn, $yn); - $p[1] = $this->sum2($xp, $yn); - $p[2] = $this->sum2($xp, $yp); - $p[3] = $this->sum2($xn, $yp); - - $min_x = $max_x = $p[0][0]; - $min_y = $max_y = $p[0][1]; - - for ($i = 1; $i < 4; ++$i) - { - $min_x = ($min_x > $p[$i][0]) ? $p[$i][0] : $min_x; - $min_y = ($min_y > $p[$i][1]) ? $p[$i][1] : $min_y; - $max_x = ($max_x < $p[$i][0]) ? $p[$i][0] : $max_x; - $max_y = ($max_y < $p[$i][1]) ? $p[$i][1] : $max_y; - } - - return array($min_x, $min_y, $max_x, $max_y); - } -} - -/** -* @package VC -*/ -class colour_manager -{ - var $img; - var $mode; - var $colours; - var $named_colours; - - /** - * Create the colour manager, link it to the image resource - */ - function colour_manager($img, $background = false, $mode = 'ahsv') - { - $this->img = $img; - $this->mode = $mode; - $this->colours = array(); - $this->named_colours = array(); - - if ($background !== false) - { - $bg = $this->allocate_named('background', $background); - imagefill($this->img, 0, 0, $bg); - } - } - - /** - * Lookup a named colour resource - */ - function get_resource($named_colour) - { - if (isset($this->named_colours[$named_colour])) - { - return $this->named_colours[$named_colour]; - } - - if (isset($this->named_rgb[$named_colour])) - { - return $this->allocate_named($named_colour, $this->named_rgb[$named_colour], 'rgb'); - } - - return false; - } - - /** - * Assign a name to a colour resource - */ - function name_colour($name, $resource) - { - $this->named_colours[$name] = $resource; - } - - /** - * names and allocates a colour resource - */ - function allocate_named($name, $colour, $mode = false) - { - $resource = $this->allocate($colour, $mode); - - if ($resource !== false) - { - $this->name_colour($name, $resource); - } - return $resource; - } - - /** - * allocates a specified colour into the image - */ - function allocate($colour, $mode = false) - { - if ($mode === false) - { - $mode = $this->mode; - } - - if (!is_array($colour)) - { - if (isset($this->named_rgb[$colour])) - { - return $this->allocate_named($colour, $this->named_rgb[$colour], 'rgb'); - } - - if (!is_int($colour)) - { - return false; - } - - $mode = 'rgb'; - $colour = array(255 & ($colour >> 16), 255 & ($colour >> 8), 255 & $colour); - } - - if (isset($colour['mode'])) - { - $mode = $colour['mode']; - unset($colour['mode']); - } - - if (isset($colour['random'])) - { - unset($colour['random']); - // everything else is params - return $this->random_colour($colour, $mode); - } - - $rgb = colour_manager::model_convert($colour, $mode, 'rgb'); - $store = ($this->mode == 'rgb') ? $rgb : colour_manager::model_convert($colour, $mode, $this->mode); - $resource = imagecolorallocate($this->img, $rgb[0], $rgb[1], $rgb[2]); - $this->colours[$resource] = $store; - - return $resource; - } - - /** - * randomly generates a colour, with optional params - */ - function random_colour($params = array(), $mode = false) - { - if ($mode === false) - { - $mode = $this->mode; - } - - switch ($mode) - { - case 'rgb': - // @TODO random rgb generation. do we intend to do this, or is it just too tedious? - break; - - case 'ahsv': - case 'hsv': - default: - - $default_params = array( - 'hue_bias' => false, // degree / 'r'/'g'/'b'/'c'/'m'/'y' /'o' - 'hue_range' => false, // if hue bias, then difference range +/- from bias - 'min_saturation' => 30, // 0 - 100 - 'max_saturation' => 80, // 0 - 100 - 'min_value' => 30, // 0 - 100 - 'max_value' => 80, // 0 - 100 - ); - - $alt = ($mode == 'ahsv') ? true : false; - $params = array_merge($default_params, $params); - - $min_hue = 0; - $max_hue = 359; - $min_saturation = max(0, $params['min_saturation']); - $max_saturation = min(100, $params['max_saturation']); - $min_value = max(0, $params['min_value']); - $max_value = min(100, $params['max_value']); - - if ($params['hue_bias'] !== false) - { - if (is_numeric($params['hue_bias'])) - { - $h = intval($params['hue_bias']) % 360; - } - else - { - switch ($params['hue_bias']) - { - case 'o': - $h = $alt ? 60 : 30; - break; - - case 'y': - $h = $alt ? 120 : 60; - break; - - case 'g': - $h = $alt ? 180 : 120; - break; - - case 'c': - $h = $alt ? 210 : 180; - break; - - case 'b': - $h = 240; - break; - - case 'm': - $h = 300; - break; - - case 'r': - default: - $h = 0; - break; - } - } - - $min_hue = $h + 360; - $max_hue = $h + 360; - - if ($params['hue_range']) - { - $min_hue -= min(180, $params['hue_range']); - $max_hue += min(180, $params['hue_range']); - } - } - - $h = mt_rand($min_hue, $max_hue); - $s = mt_rand($min_saturation, $max_saturation); - $v = mt_rand($min_value, $max_value); - - return $this->allocate(array($h, $s, $v), $mode); - - break; - } - } - - /** - */ - function colour_scheme($resource, $include_original = true) - { - $mode = 'hsv'; - - if (($pre = $this->get_resource($resource)) !== false) - { - $resource = $pre; - } - - $colour = colour_manager::model_convert($this->colours[$resource], $this->mode, $mode); - $results = ($include_original) ? array($resource) : array(); - $colour2 = $colour3 = $colour4 = $colour; - $colour2[0] += 150; - $colour3[0] += 180; - $colour4[0] += 210; - - - $results[] = $this->allocate($colour2, $mode); - $results[] = $this->allocate($colour3, $mode); - $results[] = $this->allocate($colour4, $mode); - - return $results; - } - - /** - */ - function mono_range($resource, $count = 5, $include_original = true) - { - if (is_array($resource)) - { - $results = array(); - for ($i = 0, $size = sizeof($resource); $i < $size; ++$i) - { - $results = array_merge($results, $this->mono_range($resource[$i], $count, $include_original)); - } - return $results; - } - - $mode = (in_array($this->mode, array('hsv', 'ahsv'), true) ? $this->mode : 'ahsv'); - if (($pre = $this->get_resource($resource)) !== false) - { - $resource = $pre; - } - - $colour = colour_manager::model_convert($this->colours[$resource], $this->mode, $mode); - - $results = array(); - if ($include_original) - { - $results[] = $resource; - $count--; - } - - // This is a hard problem. I chicken out and try to maintain readability at the cost of less randomness. - - while ($count > 0) - { - $colour[1] = ($colour[1] + mt_rand(40,60)) % 99; - $colour[2] = ($colour[2] + mt_rand(40,60)); - $results[] = $this->allocate($colour, $mode); - $count--; - } - return $results; - } - - /** - * Convert from one colour model to another - */ - function model_convert($colour, $from_model, $to_model) - { - if ($from_model == $to_model) - { - return $colour; - } - - switch ($to_model) - { - case 'hsv': - - switch ($from_model) - { - case 'ahsv': - return colour_manager::ah2h($colour); - break; - - case 'rgb': - return colour_manager::rgb2hsv($colour); - break; - } - break; - - case 'ahsv': - - switch ($from_model) - { - case 'hsv': - return colour_manager::h2ah($colour); - break; - - case 'rgb': - return colour_manager::h2ah(colour_manager::rgb2hsv($colour)); - break; - } - break; - - case 'rgb': - switch ($from_model) - { - case 'hsv': - return colour_manager::hsv2rgb($colour); - break; - - case 'ahsv': - return colour_manager::hsv2rgb(colour_manager::ah2h($colour)); - break; - } - break; - } - return false; - } - - /** - * Slightly altered from wikipedia's algorithm - */ - function hsv2rgb($hsv) - { - colour_manager::normalize_hue($hsv[0]); - - $h = $hsv[0]; - $s = min(1, max(0, $hsv[1] / 100)); - $v = min(1, max(0, $hsv[2] / 100)); - - // calculate hue sector - $hi = floor($hsv[0] / 60); - - // calculate opposite colour - $p = $v * (1 - $s); - - // calculate distance between hex vertices - $f = ($h / 60) - $hi; - - // coming in or going out? - if (!($hi & 1)) - { - $f = 1 - $f; - } - - // calculate adjacent colour - $q = $v * (1 - ($f * $s)); - - switch ($hi) - { - case 0: - $rgb = array($v, $q, $p); - break; - - case 1: - $rgb = array($q, $v, $p); - break; - - case 2: - $rgb = array($p, $v, $q); - break; - - case 3: - $rgb = array($p, $q, $v); - break; - - case 4: - $rgb = array($q, $p, $v); - break; - - case 5: - $rgb = array($v, $p, $q); - break; - - default: - return array(0, 0, 0); - break; - } - - return array(255 * $rgb[0], 255 * $rgb[1], 255 * $rgb[2]); - } - - /** - * (more than) Slightly altered from wikipedia's algorithm - */ - function rgb2hsv($rgb) - { - $r = min(255, max(0, $rgb[0])); - $g = min(255, max(0, $rgb[1])); - $b = min(255, max(0, $rgb[2])); - $max = max($r, $g, $b); - $min = min($r, $g, $b); - - $v = $max / 255; - $s = (!$max) ? 0 : 1 - ($min / $max); - - // if max - min is 0, we want hue to be 0 anyway. - $h = $max - $min; - - if ($h) - { - switch ($max) - { - case $g: - $h = 120 + (60 * ($b - $r) / $h); - break; - - case $b: - $h = 240 + (60 * ($r - $g) / $h); - break; - - case $r: - $h = 360 + (60 * ($g - $b) / $h); - break; - } - } - colour_manager::normalize_hue($h); - - return array($h, $s * 100, $v * 100); - } - - /** - */ - function normalize_hue(&$hue) - { - $hue %= 360; - - if ($hue < 0) - { - $hue += 360; - } - } - - /** - * Alternate hue to hue - */ - function ah2h($ahue) - { - if (is_array($ahue)) - { - $ahue[0] = colour_manager::ah2h($ahue[0]); - return $ahue; - } - colour_manager::normalize_hue($ahue); - - // blue through red is already ok - if ($ahue >= 240) - { - return $ahue; - } - - // ahue green is at 180 - if ($ahue >= 180) - { - // return (240 - (2 * (240 - $ahue))); - return (2 * $ahue) - 240; // equivalent - } - - // ahue yellow is at 120 (RYB rather than RGB) - if ($ahue >= 120) - { - return $ahue - 60; - } - - return $ahue / 2; - } - - /** - * hue to Alternate hue - */ - function h2ah($hue) - { - if (is_array($hue)) - { - $hue[0] = colour_manager::h2ah($hue[0]); - return $hue; - } - colour_manager::normalize_hue($hue); - - // blue through red is already ok - if ($hue >= 240) - { - return $hue; - } - else if ($hue <= 60) - { - return $hue * 2; - } - else if ($hue <= 120) - { - return $hue + 60; - } - else - { - return ($hue + 240) / 2; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/captcha_gd_wave.php b/phpBB/includes/captcha/captcha_gd_wave.php deleted file mode 100644 index 27422513d9..0000000000 --- a/phpBB/includes/captcha/captcha_gd_wave.php +++ /dev/null @@ -1,845 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* Wave3D CAPTCHA -* -* @author Robert Hetzler -* @package VC -*/ -class captcha -{ - var $width = 360; - var $height = 96; - - function execute($code, $seed) - { - global $starttime; - - // seed the random generator - mt_srand($seed); - - // set height and width - $img_x = $this->width; - $img_y = $this->height; - - // Generate image - $img = imagecreatetruecolor($img_x, $img_y); - $x_grid = mt_rand(6, 10); - $y_grid = mt_rand(6, 10); - - // Ok, so lets cut to the chase. We could accurately represent this in 3d and - // do all the appropriate linear transforms. my questions is... why bother? - // The computational overhead is unnecessary when you consider the simple fact: - // we're not here to accurately represent a model, but to just show off some random-ish - // polygons - - // Conceive of 3 spaces. - // 1) planar-space (discrete "pixel" grid) - // 2) 3-space. (planar-space with z/height aspect) - // 3) image space (pixels on the screen) - // resolution of the planar-space we're embedding the text code in - $plane_x = 100; - $plane_y = 30; - - $subdivision_factor = 3; - - // $box is the 4 points in img_space that correspond to the corners of the plane in 3-space - $box = array( - 'upper_left' => array( - 'x' => mt_rand(5, 15), - 'y' => mt_rand(10, 15) - ), - 'upper_right' => array( - 'x' => mt_rand($img_x - 35, $img_x - 19), - 'y' => mt_rand(10, 17) - ), - 'lower_left' => array( - 'x' => mt_rand($img_x - 45, $img_x - 5), - 'y' => mt_rand($img_y - 15, $img_y - 0), - ), - ); - - $box['lower_right'] = array( - 'x' => $box['lower_left']['x'] + $box['upper_left']['x'] - $box['upper_right']['x'], - 'y' => $box['lower_left']['y'] + $box['upper_left']['y'] - $box['upper_right']['y'], - ); - - // TODO - $background = imagecolorallocate($img, mt_rand(155, 255), mt_rand(155, 255), mt_rand(155, 255)); - imagefill($img, 0, 0, $background); - $black = imagecolorallocate($img, 0, 0, 0); - - $random = array(); - $fontcolors = array(); - - for ($i = 0; $i < 15; ++$i) - { - $random[$i] = imagecolorallocate($img, mt_rand(120, 255), mt_rand(120, 255), mt_rand(120, 255)); - } - - $fontcolors[0] = imagecolorallocate($img, mt_rand(0, 120), mt_rand(0, 120), mt_rand(0, 120)); - - $colors = array(); - - $minr = mt_rand(20, 30); - $ming = mt_rand(20, 30); - $minb = mt_rand(20, 30); - - $maxr = mt_rand(150, 230); - $maxg = mt_rand(150, 230); - $maxb = mt_rand(150, 230); - - for ($i = -30; $i <= 30; ++$i) - { - $coeff1 = ($i + 12) / 45; - $coeff2 = 1 - $coeff1; - $colors[$i] = imagecolorallocate($img, ($coeff2 * $maxr) + ($coeff1 * $minr), ($coeff2 * $maxg) + ($coeff1 * $ming), ($coeff2 * $maxb) + ($coeff1 * $minb)); - } - - // $img_buffer is the last row of 3-space positions (converted to img-space), cached - // (using this means we don't need to recalculate all 4 positions for each new polygon, - // merely the newest point that we're adding, which is then cached. - $img_buffer = array(array(), array()); - - // In image-space, the x- and y-offset necessary to move one unit in the x-direction in planar-space - $dxx = ($box['upper_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_x); - $dxy = ($box['upper_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_x); - - // In image-space, the x- and y-offset necessary to move one unit in the y-direction in planar-space - $dyx = ($box['lower_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_y); - $dyy = ($box['lower_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_y); - - // Initial captcha-letter offset in planar-space - $plane_offset_x = mt_rand(3, 8); - $plane_offset_y = mt_rand( 12, 15); - - // character map - $map = $this->captcha_bitmaps(); - - // matrix - $plane = array(); - - // for each character, we'll silkscreen it into our boolean pixel plane - for ($c = 0, $code_num = strlen($code); $c < $code_num; ++$c) - { - $letter = $code[$c]; - - for ($x = $map['width'] - 1; $x >= 0; --$x) - { - for ($y = $map['height'] - 1; $y >= 0; --$y) - { - if ($map['data'][$letter][$y][$x]) - { - $plane[$y + $plane_offset_y + (($c & 1) ? 1 : -1)][$x + $plane_offset_x] = true; - } - } - } - $plane_offset_x += 11; - } - - // calculate our first buffer, we can't actually draw polys with these yet - // img_pos_prev == screen x,y location to our immediate left. - // img_pos_cur == current screen x,y location - // we calculate screen position of our - // current cell based on the difference from the previous cell - // rather than recalculating from absolute coordinates - // What we cache into the $img_buffer contains the raised text coordinates. - $img_pos_prev = $img_buffer[0][0] = array($box['upper_left']['x'], $box['upper_left']['y']); - $cur_height = $prev_height = $this->wave_height(0, 0, $subdivision_factor); - $full_x = $plane_x * $subdivision_factor; - $full_y = $plane_y * $subdivision_factor; - - for ($x = 1; $x <= $full_x; ++$x) - { - $cur_height = $this->wave_height($x, 0, $subdivision_factor); - $offset = $cur_height - $prev_height; - $img_pos_cur = array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset); - - $img_buffer[0][$x] = $img_pos_cur; - $img_pos_prev = $img_pos_cur; - $prev_height = $cur_height; - } - - for ($y = 1; $y <= $full_y; ++$y) - { - // swap buffers - $buffer_cur = $y & 1; - $buffer_prev = 1 - $buffer_cur; - - $prev_height = $this->wave_height(0, $y, $subdivision_factor); - $offset = $prev_height - $this->wave_height(0, $y - 1, $subdivision_factor); - $img_pos_cur = array($img_buffer[$buffer_prev][0][0] + $dyx, min($img_buffer[$buffer_prev][0][1] + $dyy + $offset, $img_y - 1)); - - // make sure we don't try to write off the page - $img_pos_prev = $img_pos_cur; - - $img_buffer[$buffer_cur][0] = $img_pos_cur; - - for ($x = 1; $x <= $full_x; ++$x) - { - $cur_height = $this->wave_height($x, $y, $subdivision_factor) + $this->grid_height($x, $y, 1, $x_grid, $y_grid); - - // height is a z-factor, not a y-factor - $offset = $cur_height - $prev_height; - $img_pos_cur = array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset); - - // height is float, index it to an int, get closest color - $color = $colors[intval($cur_height)]; - $img_pos_prev = $img_pos_cur; - $prev_height = $cur_height; - - $y_index_old = intval(($y - 1) / $subdivision_factor); - $y_index_new = intval($y / $subdivision_factor); - $x_index_old = intval(($x - 1) / $subdivision_factor); - $x_index_new = intval($x / $subdivision_factor); - - if (!empty($plane[$y_index_new][$x_index_new])) - { - $img_pos_cur[1] += $this->wave_height($x, $y, $subdivision_factor, 1) - 30 - $cur_height; - $color = $colors[20]; - } - $img_pos_cur[1] = min($img_pos_cur[1], $img_y - 1); - $img_buffer[$buffer_cur][$x] = $img_pos_cur; - - // Smooth the edges as much as possible by having not more than one low<->high traingle per square - // Otherwise, just - $diag_down = (empty($plane[$y_index_old][$x_index_old]) == empty($plane[$y_index_new][$x_index_new])); - $diag_up = (empty($plane[$y_index_old][$x_index_new]) == empty($plane[$y_index_new][$x_index_old])); - - // natural switching - $mode = ($x + $y) & 1; - - // override if it requires it - if ($diag_down != $diag_up) - { - $mode = $diag_up; - } - - if ($mode) - { - // +-/ / - // 1 |/ 2 /| - // / /-+ - $poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x]); - $poly2 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_cur][$x], $img_buffer[$buffer_prev][$x]); - } - else - { - // \ \-+ - // 1 |\ 2 \| - // +-\ \ - $poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_cur][$x]); - $poly2 = array_merge($img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x], $img_buffer[$buffer_cur][$x]); - } - - imagefilledpolygon($img, $poly1, 3, $color); - imagefilledpolygon($img, $poly2, 3, $color); - } - } - - // Output image - header('Content-Type: image/png'); - header('Cache-control: no-cache, no-store'); - //$mtime = explode(' ', microtime()); - //$totaltime = $mtime[0] + $mtime[1] - $starttime; - - //echo $totaltime . "<br />\n"; - //echo memory_get_usage() - $tmp; - imagepng($img); - imagedestroy($img); - } - - function wave_height($x, $y, $factor = 1, $tweak = 0.7) - { - // stretch the wave. TODO: pretty it up - $x = $x/5 + 180; - $y = $y/4; - return ((sin($x / (3 * $factor)) + sin($y / (3 * $factor))) * 10 * $tweak); - } - - function grid_height($x, $y, $factor = 1, $x_grid, $y_grid) - { - return ((!($x % ($x_grid * $factor)) || !($y % ($y_grid * $factor))) ? 3 : 0); - } - - function captcha_bitmaps() - { - return array( - 'width' => 9, - 'height' => 13, - 'data' => array( - 'A' => array( - array(0,0,1,1,1,1,0,0,0), - array(0,1,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'B' => array( - array(1,1,1,1,1,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,1,0,0), - array(1,1,1,1,1,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,1,0,0), - array(1,1,1,1,1,1,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'C' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'D' => array( - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'E' => array( - array(0,0,1,1,1,1,1,1,1), - array(0,1,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'F' => array( - array(0,0,1,1,1,1,1,1,0), - array(0,1,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'G' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'H' => array( - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'I' => array( - array(0,1,1,1,1,1,1,1,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,1,1,1,1,1,1,1,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'J' => array( - array(0,0,0,0,0,0,1,1,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,0,1,0,0,0,0,1,0), - array(0,0,0,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'K' => array( - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,1,0,0,0,0,0), - array(1,0,1,0,0,0,0,0,0), - array(1,1,0,0,0,0,0,0,0), - array(1,0,1,0,0,0,0,0,0), - array(1,0,0,1,0,0,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'L' => array( - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'M' => array( - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,0,0,0,1,1,0), - array(0,1,0,1,0,1,0,1,0), - array(0,1,0,0,1,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'N' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,1,0,0,0,0,0,0,1), - array(1,0,1,0,0,0,0,0,1), - array(1,0,0,1,0,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,0,1,0,0,1), - array(1,0,0,0,0,0,1,0,1), - array(1,0,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'O' => array( - array(0,0,0,1,1,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,1,1,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'P' => array( - array(1,1,1,1,1,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,1,0,0), - array(1,1,1,1,1,1,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'Q' => array( - array(0,0,1,1,1,1,0,0,0), - array(0,1,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,1,0,0,1,0), - array(1,0,0,0,0,1,0,1,0), - array(0,1,0,0,0,0,1,0,0), - array(0,0,1,1,1,1,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'R' => array( - array(1,1,1,1,1,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,1,0,0), - array(1,1,1,1,1,1,0,0,0), - array(1,0,1,0,0,0,0,0,0), - array(1,0,0,1,0,0,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'S' => array( - array(0,0,1,1,1,1,1,1,1), - array(0,1,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'T' => array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'U' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'V' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'W' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,1,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'X' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'Y' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - 'Z' => array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,1), - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - '1' => array( - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,1,0,0,0,0), - array(0,0,1,0,1,0,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,1,1,1,1,1,1,1,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - '2' => array( - array(0,0,0,1,1,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,0,0), - ), - '3' => array( - array(0,0,0,1,1,1,1,0,0), - array(0,0,1,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,0,1,0,0,0,0,1,0), - array(0,0,0,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - '4' => array( - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,1,0), - array(0,0,0,0,0,1,0,1,0), - array(0,0,0,0,1,0,0,1,0), - array(0,0,0,1,0,0,0,1,0), - array(0,0,1,0,0,0,0,1,0), - array(0,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - '5' => array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - '6' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,1,1,1,1,0,0), - array(1,0,1,0,0,0,0,1,0), - array(1,1,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - '7' => array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - '8' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - '9' => array( - array(0,0,0,1,1,1,1,0,0), - array(0,0,1,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,1), - array(0,0,1,1,1,1,1,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,0,1), - array(0,0,1,0,0,0,0,1,0), - array(0,0,0,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,0,0), - array(0,0,0,0,0,0,0,0,0), - ), - ) - ); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/captcha_non_gd.php b/phpBB/includes/captcha/captcha_non_gd.php deleted file mode 100644 index 2adf909b96..0000000000 --- a/phpBB/includes/captcha/captcha_non_gd.php +++ /dev/null @@ -1,392 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Main non-gd captcha class -* @ignore -* @package VC -*/ -class captcha -{ - var $filtered_pngs; - var $width = 320; - var $height = 50; - - /** - * Define filtered pngs on init - */ - function captcha() - { - // If we can we will generate a single filtered png, we avoid nastiness via emulation of some Zlib stuff - $this->define_filtered_pngs(); - } - - /** - * Create the image containing $code with a seed of $seed - */ - function execute($code, $seed) - { - $img_height = $this->height - 10; - $img_width = 0; - - mt_srand($seed); - - $char_widths = $hold_chars = array(); - $code_len = strlen($code); - - for ($i = 0; $i < $code_len; $i++) - { - $char = $code[$i]; - - $width = mt_rand(0, 4); - $raw_width = $this->filtered_pngs[$char]['width']; - $char_widths[$i] = $width; - $img_width += $raw_width - $width; - - // Split the char into chunks of $raw_width + 1 length - if (empty($hold_chars[$char])) - { - $hold_chars[$char] = str_split(base64_decode($this->filtered_pngs[$char]['data']), $raw_width + 1); - } - } - - $offset_x = mt_rand(0, $this->width - $img_width); - $offset_y = mt_rand(0, $this->height - $img_height); - - $image = ''; - for ($i = 0; $i < $this->height; $i++) - { - $image .= chr(0); - - if ($i > $offset_y && $i < $offset_y + $img_height) - { - for ($j = 0; $j < $offset_x; $j++) - { - $image .= chr(mt_rand(140, 255)); - } - - for ($j = 0; $j < $code_len; $j++) - { - $image .= $this->randomise(substr($hold_chars[$code{$j}][$i - $offset_y - 1], 1), $char_widths[$j]); - } - - for ($j = $offset_x + $img_width; $j < $this->width; $j++) - { - $image .= chr(mt_rand(140, 255)); - } - } - else - { - for ($j = 0; $j < $this->width; $j++) - { - $image .= chr(mt_rand(140, 255)); - } - } - } - unset($hold_chars); - - $image = $this->create_png($image, $this->width, $this->height); - - // Output image - header('Content-Type: image/png'); - header('Cache-control: no-cache, no-store'); - echo $image; - exit; - } - - /** - * This is designed to randomise the pixels of the image data within - * certain limits so as to keep it readable. It also varies the image - * width a little - */ - function randomise($scanline, $width) - { - $new_line = ''; - - $end = strlen($scanline) - ceil($width/2); - for ($i = (int) floor($width / 2); $i < $end; $i++) - { - $pixel = ord($scanline{$i}); - - if ($pixel < 190) - { - $new_line .= chr(mt_rand(0, 205)); - } - else if ($pixel > 190) - { - $new_line .= chr(mt_rand(145, 255)); - } - else - { - $new_line .= $scanline{$i}; - } - } - - return $new_line; - } - - /** - * This creates a chunk of the given type, with the given data - * of the given length adding the relevant crc - */ - function png_chunk($length, $type, $data) - { - $raw = $type . $data; - - return pack('N', $length) . $raw . pack('N', crc32($raw)); - } - - /** - * Creates greyscale 8bit png - The PNG spec can be found at - * http://www.libpng.org/pub/png/spec/PNG-Contents.html we use - * png because it's a fully recognised open standard and supported - * by practically all modern browsers and OSs - */ - function create_png($raw_image, $width, $height) - { - // SIG - $image = pack('C8', 137, 80, 78, 71, 13, 10, 26, 10); - - // IHDR - $raw = pack('N2', $width, $height); - $raw .= pack('C5', 8, 0, 0, 0, 0); - $image .= $this->png_chunk(13, 'IHDR', $raw); - - // IDAT - if (@extension_loaded('zlib')) - { - $raw_image = gzcompress($raw_image); - $length = strlen($raw_image); - } - else - { - // The total length of this image, uncompressed, is just a calculation of pixels - $length = ($width + 1) * $height; - - // Adler-32 hash generation - // Note: The hash is _backwards_ so we must reverse it - - if (@extension_loaded('hash')) - { - $adler_hash = strrev(hash('adler32', $raw_image, true)); - } - else if (@extension_loaded('mhash')) - { - $adler_hash = strrev(mhash(MHASH_ADLER32, $raw_image)); - } - else - { - // Optimized Adler-32 loop ported from the GNU Classpath project - $temp_length = $length; - $s1 = 1; - $s2 = $index = 0; - - while ($temp_length > 0) - { - // We can defer the modulo operation: - // s1 maximally grows from 65521 to 65521 + 255 * 3800 - // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 - $substract_value = ($temp_length < 3800) ? $temp_length : 3800; - $temp_length -= $substract_value; - - while (--$substract_value >= 0) - { - $s1 += ord($raw_image[$index]); - $s2 += $s1; - - $index++; - } - - $s1 %= 65521; - $s2 %= 65521; - } - $adler_hash = pack('N', ($s2 << 16) | $s1); - } - - // This is the same thing as gzcompress($raw_image, 0) but does not need zlib - $raw_image = pack('C3v2', 0x78, 0x01, 0x01, $length, ~$length) . $raw_image . $adler_hash; - - // The Zlib header + Adler hash make us add on 11 - $length += 11; - } - - // IDAT - $image .= $this->png_chunk($length, 'IDAT', $raw_image); - - // IEND - $image .= $this->png_chunk(0, 'IEND', ''); - - return $image; - } - - /** - * png image data - * Each 'data' element is base64_encoded uncompressed IDAT - */ - function define_filtered_pngs() - { - $this->filtered_pngs = array( - '0' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////olFAkBAAAGDyA4P///M31/////////////wD////////////////0dAgAAAAAAAAAAAAEcPipFGHn////////////AP//////////////6DAAAAAAAAAAAAAAAAAALSEAN+T///////////8A//////////////xAAAAAAAAAAAAAAAAAAAAAACPA/////////////wD/////////////oAAAAAAAAAAAAAAAAAAAAAAAev//////////////AP////////////8oAAAAAAAAPNj/zDAAAAAAAABD//////////////8A////////////1AAAAAAAABjw////5BAAAAAAAADo/////////////wD///////////+QAAAAAAAAbP//////QgAAAAAAAKj/////////////AP///////////1wAAAAAAACs/////8AXAAAAAAAAcP////////////8A////////////OAAAAAAAAND////dNwAAAAAAAABI/////////////wD///////////8gAAAAAAAA4P//7koACwAAAAAAACT/////////////AP///////////wgAAAAAAAD///VqAwaPAAAAAAAAEP////////////8A////////////AAAAAAAAAP/8kQYDavUAAAAAAAAA/////////////wD///////////8AAAAAAAAA/6kNAEru/wAAAAAAAAD/////////////AP///////////wAAAAAAAADAIwA33f//AAAAAAAAAP////////////8A////////////FAAAAAAAADYAI8D///8AAAAAAAAQ/////////////wD///////////8kAAAAAAAAAA2p////5AAAAAAAACD/////////////AP///////////0gAAAAAAAAFkfz////UAAAAAAAAQP////////////8A////////////cAAAAAAAAET1/////7AAAAAAAABo/////////////wD///////////+oAAAAAAAAXfX/////sAAAAAAAAGj/////////////AAAAALgAAAAAAAAwAAAAAAAAAAAAAAD////////////oAAAAAAAACOT////oEAAAAAAAAOD/////////////AP////////////8+AAAAAAAAKMz/zDQAAAAAAAA0//////////////8A////////////7jgAAAAAAAAAAAAAAAAAAAAAAKT//////////////wD///////////VqAwIAAAAAAAAAAAAAAAAAAAA8////////////////AP//////////rQcDaVEAAAAAAAAAAAAAAAAAKOj///////////////8A///////////nblnu/IAIAAAAAAAAAAAAAFzw/////////////////wD////////////79////+iITCAAAAAgSITg////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////w==', - 'width' => 40 - ), - '1' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////8BAAAAAAAP//////////////////AP////////////////////////9sAAAAAAAA//////////////////8A////////////////////////pAAAAAAAAAD//////////////////wD//////////////////////6wEAAAAAAAAAP//////////////////AP////////////////////h4AAAAAAAAAAAA//////////////////8A//////////////////ygJAAAAAAAAAAAAAD//////////////////wD//////////////9x8HAAAAAAAAAAAAAAAAP//////////////////AP//////////////AAAAAAAAAAAAAAAAAAAA//////////////////8A//////////////8AAAAAAAAAAAAAAAAAAAD//////////////////wD//////////////wAAAAAAAAR4AAAAAAAAAP//////////////////AP//////////////AAAAAAA4zP8AAAAAAAAA//////////////////8A//////////////8AAAA4sP///wAAAAAAAAD//////////////////wD//////////////yR80P//////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '2' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////okFAkCAAABCBIfNT///////////////////8A///////////////8hAgAAAAAAAAAAAAAAFTo/////////////////wD//////////////1QAAAAAAAAAAAAAAAAAACjo////////////////AP////////////+MAAAAAAAAAAAAAAAAAAAAADj///////////////8A////////////9BAAAAAAAAAAAAAAAAAAAAAAALD//////////////wD///////////+gAAAAAAAAAHjs+KwMAAAAAAAAVP//////////////AP///////////1gAAAAAAABM/////6QAAAAAAAAU//////////////8A////////////KAAAAAAAALj/////+AAAAAAAAAD//////////////wD///////////+MfGBMOCAI8P/////wAAAAAAAACP//////////////AP///////////////////////////5wAAAAAAAAw//////////////8A///////////////////////////oFAAAAAAAAHz//////////////wD/////////////////////////6CgAAAAAAAAE3P//////////////AP///////////////////////9ggAAAAAAAAAHT///////////////8A//////////////////////+0DAAAAAAAAAA8+P///////////////wD/////////////////////gAAAAAAAAAAAKOj/////////////////AP//////////////////9FAAAAAAAAAAADzw//////////////////8A/////////////////+g4AAAAAAAAAABk/P///////////////////wD////////////////oKAAAAAAAAAAMqP//////////////////////AP//////////////6CgAAAAAAAAAMNz///////////////////////8A//////////////g4AAAAAAAAAFT0/////////////////////////wD/////////////bAAAAAAAAABU/P//////////////////////////AP///////////8wAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A////////////SAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////9AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////xAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '3' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////8sGg0FAAAACA4cLz8////////////////////AP//////////////rBgAAAAAAAAAAAAAACTA//////////////////8A/////////////3QAAAAAAAAAAAAAAAAAAASs/////////////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAjc////////////////AP//////////6AwAAAAAAAAAAAAAAAAAAAAAAGT///////////////8A//////////94AAAAAAAABJDw/8g4AAAAAAAAHP///////////////wD//////////yAAAAAAAACE/////9gAAAAAAAAA////////////////AP///////////NSwiGQ4FOT//////AAAAAAAABD///////////////8A//////////////////////////+YAAAAAAAAVP///////////////wD//////////////////////P/ggAQAAAAAAATM////////////////AP////////////////////9gAAAAAAAAAAAElP////////////////8A/////////////////////0AAAAAAAAAAHLj//////////////////wD/////////////////////OAAAAAAAAAAwkPj/////////////////AP////////////////////8gAAAAAAAAAAAAINj///////////////8A/////////////////////xAAAAAAAAAAAAAAIPD//////////////wD/////////////////////uOz/4HgEAAAAAAAAhP//////////////AP///////////////////////////3wAAAAAAAAw//////////////8A////////////////////////////6AAAAAAAAAj//////////////wD/////////////////////////////AAAAAAAAAP//////////////AP//////////tJh8YEQoDNz//////+AAAAAAAAAY//////////////8A//////////88AAAAAAAAaP//////dAAAAAAAAEz//////////////wD//////////6QAAAAAAAAAdOD/5HQAAAAAAAAApP//////////////AP///////////CgAAAAAAAAAAAAAAAAAAAAAACD4//////////////8A////////////yAQAAAAAAAAAAAAAAAAAAAAEuP///////////////wD/////////////rAQAAAAAAAAAAAAAAAAABJD/////////////////AP//////////////zDQAAAAAAAAAAAAAACTA//////////////////8A/////////////////8BwOCAAAAAUNGi0/P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '4' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////////////nAAAAAAAAAD///////////////8A/////////////////////////8AEAAAAAAAAAP///////////////wD////////////////////////gGAAAAAAAAAAA////////////////AP//////////////////////9DAAAAAAAAAAAAD///////////////8A//////////////////////9UAAAAAAAAAAAAAP///////////////wD/////////////////////hAAAAAAAAAAAAAAA////////////////AP///////////////////7QAAAAAAAAAAAAAAAD///////////////8A///////////////////UDAAAAAAUAAAAAAAAAP///////////////wD/////////////////7CQAAAAABMAAAAAAAAAA////////////////AP////////////////xEAAAAAACU/wAAAAAAAAD///////////////8A////////////////cAAAAAAAZP//AAAAAAAAAP///////////////wD//////////////6AAAAAAADz8//8AAAAAAAAA////////////////AP/////////////IBAAAAAAc6P///wAAAAAAAAD///////////////8A////////////5BgAAAAADMz/////AAAAAAAAAP///////////////wD///////////g0AAAAAACk//////8AAAAAAAAA////////////////AP//////////XAAAAAAAfP///////wAAAAAAAAD///////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP///////////////////////////wAAAAAAAAD///////////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '5' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////8AAAAAAAAAAAAAAAAAAAAAAA//////////////8A///////////////MAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////6wAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////iAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////////9kAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////0QAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////IAAAAAAAYP////////////////////////////8A//////////////wAAAAAAAB8/////////////////////////////wD/////////////3AAAAAAAAIj/////////////////////////////AP////////////+4AAAAAAAAoLRYHAAEKGTE//////////////////8A/////////////5QAAAAAAAAQAAAAAAAAAABY9P///////////////wD/////////////dAAAAAAAAAAAAAAAAAAAAAA89P//////////////AP////////////9QAAAAAAAAAAAAAAAAAAAAAABg//////////////8A/////////////zAAAAAAAAAAAAAAAAAAAAAAAADQ/////////////wD/////////////IAAAAAAAAGjY/+h4BAAAAAAAAGz/////////////AP//////////////9NS0lHSc//////90AAAAAAAALP////////////8A/////////////////////////////9QAAAAAAAAE/////////////wD//////////////////////////////wAAAAAAAAD/////////////AP/////////////////////////////8AAAAAAAAEP////////////8A////////////pIRwWEAgDOD//////8wAAAAAAAA8/////////////wD///////////9EAAAAAAAAaP//////ZAAAAAAAAHz/////////////AP///////////6QAAAAAAAAAaOD/4GQAAAAAAAAE4P////////////8A/////////////CQAAAAAAAAAAAAAAAAAAAAAAGD//////////////wD/////////////yAQAAAAAAAAAAAAAAAAAAAAc7P//////////////AP//////////////rAwAAAAAAAAAAAAAAAAAGNj///////////////8A////////////////0EAAAAAAAAAAAAAAAFTo/////////////////wD//////////////////8h4QCAAAAAcQHzU////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '6' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////+0ZCwMAAAUNGjI////////////////////AP/////////////////EMAAAAAAAAAAAAABM6P////////////////8A////////////////lAQAAAAAAAAAAAAAAAAo6P///////////////wD//////////////6wAAAAAAAAAAAAAAAAAAABI////////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAACw//////////////8A/////////////3AAAAAAAAAoxP/YPAAAAAAAAEj//////////////wD////////////4EAAAAAAACOD////YDCBAVGiAoP//////////////AP///////////7gAAAAAAABY//////////////////////////////8A////////////eAAAAAAAAJT//////////////////////////////wD///////////9MAAAAAAAAvP/IXBgABCx03P//////////////////AP///////////ygAAAAAAADcdAAAAAAAAAAEiP////////////////8A////////////FAAAAAAAAFAAAAAAAAAAAAAAcP///////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAlP//////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAQ8P////////////8A////////////AAAAAAAAAABAyP/kZAAAAAAAAACQ/////////////wD///////////8MAAAAAAAALPj/////WAAAAAAAAET/////////////AP///////////yQAAAAAAACY///////MAAAAAAAAFP////////////8A////////////SAAAAAAAAMD///////wAAAAAAAAA/////////////wD///////////9wAAAAAAAAvP///////wAAAAAAAAD/////////////AP///////////7QAAAAAAACI///////UAAAAAAAAJP////////////8A////////////+AwAAAAAACDw/////2wAAAAAAABY/////////////wD/////////////cAAAAAAAADC8/Ox4AAAAAAAAAKj/////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAAAk/P////////////8A//////////////+oAAAAAAAAAAAAAAAAAAAABLj//////////////wD///////////////+QAAAAAAAAAAAAAAAAAACQ////////////////AP////////////////+0JAAAAAAAAAAAAAAkuP////////////////8A///////////////////8sGg0FAAADCxgqPz//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '7' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAABP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAy4/////////////wD//////////////////////////+QUAAAAAAAEuP//////////////AP/////////////////////////8QAAAAAAAAKT///////////////8A/////////////////////////4wAAAAAAAB0/////////////////wD////////////////////////cCAAAAAAANPz/////////////////AP///////////////////////0QAAAAAAATY//////////////////8A//////////////////////+0AAAAAAAAeP///////////////////wD//////////////////////CQAAAAAABTw////////////////////AP////////////////////+gAAAAAAAAkP////////////////////8A/////////////////////ywAAAAAABDw/////////////////////wD///////////////////+4AAAAAAAAbP//////////////////////AP///////////////////1wAAAAAAADQ//////////////////////8A///////////////////4DAAAAAAAMP///////////////////////wD//////////////////7QAAAAAAAB8////////////////////////AP//////////////////aAAAAAAAAMj///////////////////////8A//////////////////8oAAAAAAAM/P///////////////////////wD/////////////////8AAAAAAAAET/////////////////////////AP////////////////+0AAAAAAAAcP////////////////////////8A/////////////////4wAAAAAAACY/////////////////////////wD/////////////////WAAAAAAAAMD/////////////////////////AP////////////////80AAAAAAAA4P////////////////////////8A/////////////////xAAAAAAAAD4/////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '8' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////////IdDQUAAAEIEiA1P//////////////////AP/////////////////gRAAAAAAAAAAAAAAAROD///////////////8A////////////////0BgAAAAAAAAAAAAAAAAAEMj//////////////wD///////////////AcAAAAAAAAAAAAAAAAAAAAHPD/////////////AP//////////////hAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A//////////////8sAAAAAAAAKMz/zCgAAAAAAAAs/////////////wD//////////////wAAAAAAAADM////zAAAAAAAAAD/////////////AP//////////////BAAAAAAAAP//////AAAAAAAABP////////////8A//////////////8sAAAAAAAAzP///9QAAAAAAAAw/////////////wD//////////////3wAAAAAAAAoyP/YNAAAAAAAAIT/////////////AP//////////////7BgAAAAAAAAAAAAAAAAAAAAc8P////////////8A////////////////xBgAAAAAAAAAAAAAAAAAGNj//////////////wD/////////////////tAQAAAAAAAAAAAAAAACo////////////////AP///////////////HAAAAAAAAAAAAAAAAAAAAB8//////////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB8/////////////wD/////////////wAAAAAAAAABk4P/UWAAAAAAAAATQ////////////AP////////////9UAAAAAAAAaP//////XAAAAAAAAGT///////////8A/////////////xgAAAAAAADg///////cAAAAAAAAJP///////////wD/////////////AAAAAAAAAP////////8AAAAAAAAA////////////AP////////////8AAAAAAAAA4P//////3AAAAAAAAAT///////////8A/////////////ygAAAAAAABg//////9cAAAAAAAALP///////////wD/////////////ZAAAAAAAAABY1P/cXAAAAAAAAABw////////////AP/////////////QAAAAAAAAAAAAAAAAAAAAAAAABNz///////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB0/////////////wD///////////////Q8AAAAAAAAAAAAAAAAAAAAUPz/////////////AP////////////////x4CAAAAAAAAAAAAAAAEIT8//////////////8A///////////////////smFQwGAAAABg0ZKT0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - '9' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////ysYCwMAAAUNGiw/P//////////////////AP////////////////+4JAAAAAAAAAAAAAAkuP////////////////8A////////////////lAQAAAAAAAAAAAAAAAAAkP///////////////wD//////////////8AEAAAAAAAAAAAAAAAAAAAAqP//////////////AP/////////////8JAAAAAAAAAAAAAAAAAAAAAAQ7P////////////8A/////////////6wAAAAAAAAAfOz8vCwAAAAAAABw/////////////wD/////////////WAAAAAAAAHD/////7BgAAAAAAAz4////////////AP////////////8kAAAAAAAA1P//////hAAAAAAAALT///////////8A/////////////wAAAAAAAAD///////+4AAAAAAAAcP///////////wD/////////////AAAAAAAAAPz//////8AAAAAAAABI////////////AP////////////8UAAAAAAAAzP//////lAAAAAAAACT///////////8A/////////////0QAAAAAAABY//////gsAAAAAAAADP///////////wD/////////////kAAAAAAAAABw5P/IPAAAAAAAAAAA////////////AP/////////////wEAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////////+UAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////9wAAAAAAAAAAAAAFAAAAAAAAAU////////////AP////////////////+IBAAAAAAAAABw3AAAAAAAACj///////////8A///////////////////cdCwEABhcxP+8AAAAAAAATP///////////wD//////////////////////////////5AAAAAAAAB4////////////AP//////////////////////////////UAAAAAAAALj///////////8A//////////////+kgGxUQCAM2P///+AIAAAAAAAQ+P///////////wD//////////////0gAAAAAAAA42P/EKAAAAAAAAHD/////////////AP//////////////sAAAAAAAAAAAAAAAAAAAAAAQ6P////////////8A////////////////TAAAAAAAAAAAAAAAAAAAAKz//////////////wD////////////////oKAAAAAAAAAAAAAAAAASU////////////////AP/////////////////sUAAAAAAAAAAAAAAwxP////////////////8A////////////////////yHA0FAAADCxktP///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'A' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////+QAAAAAAAAAAAAAAOT/////////////////AP//////////////////kAAAAAAAAAAAAAAAkP////////////////8A//////////////////88AAAAAAAAAAAAAAA8/////////////////wD/////////////////5AAAAAAAAAAAAAAAAADk////////////////AP////////////////+QAAAAAAAAAAAAAAAAAJD///////////////8A/////////////////zwAAAAAAAAAAAAAAAAAPP///////////////wD////////////////kAAAAAAAAAAgAAAAAAAAA5P//////////////AP///////////////5AAAAAAAAAAgAAAAAAAAACQ//////////////8A////////////////PAAAAAAAAAz8HAAAAAAAADz//////////////wD//////////////+QAAAAAAAAAWP9kAAAAAAAAANz/////////////AP//////////////kAAAAAAAAACk/7wAAAAAAAAAhP////////////8A//////////////88AAAAAAAABOz//BQAAAAAAAAw/////////////wD/////////////4AAAAAAAAAA8////ZAAAAAAAAADc////////////AP////////////+EAAAAAAAAAIj///+8AAAAAAAAAIT///////////8A/////////////zAAAAAAAAAA2P////wQAAAAAAAAMP///////////wD////////////cAAAAAAAAACT//////1wAAAAAAAAA3P//////////AP///////////4QAAAAAAAAAAAAAAAAAAAAAAAAAAACE//////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAAAAAADD//////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANz/////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhP////////8A//////////8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw/////////wD/////////3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADc////////AP////////+EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIT///////8A/////////zAAAAAAAAAAhP///////////2QAAAAAAAAAMP///////wD////////cAAAAAAAAAADM////////////vAAAAAAAAAAA3P//////AP///////4QAAAAAAAAAHP/////////////4DAAAAAAAAACE//////8A////////MAAAAAAAAABk//////////////9cAAAAAAAAADD//////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'B' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAEDh83P///////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAEhP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAeP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAABY////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAABT///////////8A//////////8AAAAAAAAAAP/////4zEwAAAAAAAAAAP///////////wD//////////wAAAAAAAAAA////////7AAAAAAAAAAQ////////////AP//////////AAAAAAAAAAD////////sAAAAAAAAAEj///////////8A//////////8AAAAAAAAAAP/////4zEQAAAAAAAAAtP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAFz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAiA/P////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAIjPj//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAGKz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJT///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAABNz//////////wD//////////wAAAAAAAAAA///////sqCAAAAAAAAAAbP//////////AP//////////AAAAAAAAAAD/////////yAAAAAAAAAAs//////////8A//////////8AAAAAAAAAAP//////////AAAAAAAAAAT//////////wD//////////wAAAAAAAAAA/////////7wAAAAAAAAAAP//////////AP//////////AAAAAAAAAAD//////+ikGAAAAAAAAAAY//////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFT//////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsP//////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAADj///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAc6P///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAATOj/////////////AP//////////AAAAAAAAAAAAAAAAAAAEIEBkkNj///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'C' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////5JRULBAAAAgkTIDQ//////////////////8A////////////////1FAAAAAAAAAAAAAAAABAyP///////////////wD//////////////4gEAAAAAAAAAAAAAAAAAAAElP//////////////AP////////////9wAAAAAAAAAAAAAAAAAAAAAAAAlP////////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAEyP///////////wD//////////9wIAAAAAAAAAAAAAAAAAAAAAAAAAAAw////////////AP//////////WAAAAAAAAAAAWMz/8JwQAAAAAAAAAACw//////////8A/////////+wEAAAAAAAAAID//////9QMAAAAAAAAAET//////////wD/////////nAAAAAAAAAAo/P///////3wAAAAABDBspP//////////AP////////9gAAAAAAAAAIz/////////3BxQjMT0//////////////8A/////////zQAAAAAAAAAzP///////////////////////////////wD/////////GAAAAAAAAADo////////////////////////////////AP////////8AAAAAAAAAAP////////////////////////////////8A/////////wAAAAAAAAAA/////////////////////////////////wD/////////AAAAAAAAAAD/////////////////////////////////AP////////8cAAAAAAAAAOj///////////////////////////////8A/////////zgAAAAAAAAA0P/////////kIGio7P///////////////wD/////////bAAAAAAAAACg/////////5wAAAAAMHS49P//////////AP////////+oAAAAAAAAAEz/////////PAAAAAAAAAAc//////////8A//////////QIAAAAAAAAALz//////6QAAAAAAAAAAGT//////////wD//////////3AAAAAAAAAADIzo/+SEBAAAAAAAAAAAyP//////////AP//////////7BAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////rAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD/////////////fAAAAAAAAAAAAAAAAAAAAAAAAJz/////////////AP//////////////iAQAAAAAAAAAAAAAAAAAAASY//////////////8A////////////////yEAAAAAAAAAAAAAAAAA8yP///////////////wD//////////////////9yIUCwQAAAAIEB4yP//////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'D' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAADChQkOT/////////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAABGjw//////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAACDY/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAABjk////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKj//////////wD///////////8AAAAAAAAAAP///+isSAAAAAAAAAAANP//////////AP///////////wAAAAAAAAAA////////hAAAAAAAAAAA2P////////8A////////////AAAAAAAAAAD/////////MAAAAAAAAACQ/////////wD///////////8AAAAAAAAAAP////////+MAAAAAAAAAFj/////////AP///////////wAAAAAAAAAA/////////8gAAAAAAAAAMP////////8A////////////AAAAAAAAAAD/////////5AAAAAAAAAAY/////////wD///////////8AAAAAAAAAAP//////////AAAAAAAAAAD/////////AP///////////wAAAAAAAAAA//////////8AAAAAAAAAAP////////8A////////////AAAAAAAAAAD//////////wAAAAAAAAAA/////////wD///////////8AAAAAAAAAAP/////////wAAAAAAAAABD/////////AP///////////wAAAAAAAAAA/////////9QAAAAAAAAAJP////////8A////////////AAAAAAAAAAD/////////qAAAAAAAAABI/////////wD///////////8AAAAAAAAAAP////////9QAAAAAAAAAHj/////////AP///////////wAAAAAAAAAA////////uAAAAAAAAAAAvP////////8A////////////AAAAAAAAAAD////w0HwEAAAAAAAAACT8/////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAADz8//////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAY6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAKNz/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAACHT0//////////////8A////////////AAAAAAAAAAAAAAAAABg4bKj0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'E' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'F' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'G' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////MB8TCgQAAAACCA4YJzs////////////////AP///////////////JQcAAAAAAAAAAAAAAAAAAhw8P////////////8A/////////////9gwAAAAAAAAAAAAAAAAAAAAAAAk2P///////////wD////////////EDAAAAAAAAAAAAAAAAAAAAAAAAAAc7P//////////AP//////////2AwAAAAAAAAAAAAAAAAAAAAAAAAAAABY//////////8A//////////wwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQ/////////wD/////////kAAAAAAAAAAAEHzQ/P/gmCAAAAAAAAAAAFz/////////AP////////wcAAAAAAAAACjg////////8CwAAAAAAAAgWP////////8A////////vAAAAAAAAAAI2P//////////yBRAcJjI8P///////////wD///////94AAAAAAAAAGD/////////////////////////////////AP///////0AAAAAAAAAAsP////////////////////////////////8A////////IAAAAAAAAADc/////////////////////////////////wD///////8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAD/////////AP///////wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAP////////8A////////AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAA/////////wD///////8gAAAAAAAAAOD//////wAAAAAAAAAAAAAAAAD/////////AP///////0AAAAAAAAAAtP//////AAAAAAAAAAAAAAAAAP////////8A////////cAAAAAAAAABw//////8AAAAAAAAAAAAAAAAA/////////wD///////+8AAAAAAAAABDs////////////AAAAAAAAAAD/////////AP////////wYAAAAAAAAADz0//////////AAAAAAAAAAAP////////8A/////////5AAAAAAAAAAACCY4P//3KhcCAAAAAAAAAAA/////////wD/////////+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////AP//////////xAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIP////////8A////////////rAQAAAAAAAAAAAAAAAAAAAAAAAAAAGTw/////////wD/////////////vBQAAAAAAAAAAAAAAAAAAAAAADjI////////////AP//////////////8HAQAAAAAAAAAAAAAAAAAEiw//////////////8A//////////////////iwcEAgBAAABCA4aKDk/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'H' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'I' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'J' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAj//////////////wD//////////+zMrIxwUDAQ//////wAAAAAAAAAIP//////////////AP//////////DAAAAAAAAADo////2AAAAAAAAAA0//////////////8A//////////8wAAAAAAAAAKj///+YAAAAAAAAAFj//////////////wD//////////2gAAAAAAAAAIND/yBgAAAAAAAAAkP//////////////AP//////////vAAAAAAAAAAAAAAAAAAAAAAAAADc//////////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAUP///////////////wD////////////EBAAAAAAAAAAAAAAAAAAAABjk////////////////AP////////////+sBAAAAAAAAAAAAAAAAAAY2P////////////////8A///////////////EMAAAAAAAAAAAAAAAVOj//////////////////wD/////////////////vHBAIAAAABg8fNT/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'K' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////8AAAAAAAAAAP//////////wAQAAAAAAAAAAABw////////AP///////wAAAAAAAAAA/////////9AMAAAAAAAAAAAAcP////////8A////////AAAAAAAAAAD////////cGAAAAAAAAAAAAHD//////////wD///////8AAAAAAAAAAP//////6CgAAAAAAAAAAABs////////////AP///////wAAAAAAAAAA//////Q0AAAAAAAAAAAAVPz///////////8A////////AAAAAAAAAAD////8RAAAAAAAAAAAAFT8/////////////wD///////8AAAAAAAAAAP///1gAAAAAAAAAAABU/P//////////////AP///////wAAAAAAAAAA//9wAAAAAAAAAAAASPz///////////////8A////////AAAAAAAAAAD/jAAAAAAAAAAAADz0/////////////////wD///////8AAAAAAAAAAKQAAAAAAAAAAAA89P//////////////////AP///////wAAAAAAAAAABAAAAAAAAAAAFPT///////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAApP///////////////////wD///////8AAAAAAAAAAAAAAAAAAAAAAAAU8P//////////////////AP///////wAAAAAAAAAAAAAAAAAAAAAAAABk//////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAAAADE/////////////////wD///////8AAAAAAAAAAAAAAAAoEAAAAAAAACz8////////////////AP///////wAAAAAAAAAAAAAAGNiAAAAAAAAAAIj///////////////8A////////AAAAAAAAAAAAABjY//gYAAAAAAAACOD//////////////wD///////8AAAAAAAAAAAAY2P///5wAAAAAAAAASP//////////////AP///////wAAAAAAAAAAGNj//////CgAAAAAAAAAqP////////////8A////////AAAAAAAAAADI////////sAAAAAAAAAAc8P///////////wD///////8AAAAAAAAAAP//////////QAAAAAAAAABs////////////AP///////wAAAAAAAAAA///////////IAAAAAAAAAATI//////////8A////////AAAAAAAAAAD///////////9YAAAAAAAAADD8/////////wD///////8AAAAAAAAAAP///////////9wEAAAAAAAAAJD/////////AP///////wAAAAAAAAAA/////////////3AAAAAAAAAADOT///////8A////////AAAAAAAAAAD/////////////7BAAAAAAAAAAUP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'L' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'M' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////8AAAAAAAAAAAAAAHz//////3wAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAATP//////UAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAc//////8cAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAADw////8AAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAAALz////AAAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAAkP///5AAAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAABc////ZAAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAoAAAAADD///8wAAAAACQAAAAAAAAA////////AP//////AAAAAAAAAFwAAAAABPz//AgAAAAAXAAAAAAAAAD///////8A//////8AAAAAAAAAkAAAAAAA0P/UAAAAAACQAAAAAAAAAP///////wD//////wAAAAAAAADMAAAAAACg/6gAAAAAAMQAAAAAAAAA////////AP//////AAAAAAAAAPgEAAAAAHD/dAAAAAAE+AAAAAAAAAD///////8A//////8AAAAAAAAA/zQAAAAAQP9IAAAAADD/AAAAAAAAAP///////wD//////wAAAAAAAAD/bAAAAAAQ/xQAAAAAaP8AAAAAAAAA////////AP//////AAAAAAAAAP+gAAAAAADQAAAAAACc/wAAAAAAAAD///////8A//////8AAAAAAAAA/9QAAAAAAGgAAAAAAND/AAAAAAAAAP///////wD//////wAAAAAAAAD//wwAAAAAFAAAAAAM/P8AAAAAAAAA////////AP//////AAAAAAAAAP//RAAAAAAAAAAAADz//wAAAAAAAAD///////8A//////8AAAAAAAAA//94AAAAAAAAAAAAcP//AAAAAAAAAP///////wD//////wAAAAAAAAD//7AAAAAAAAAAAACo//8AAAAAAAAA////////AP//////AAAAAAAAAP//5AAAAAAAAAAAANz//wAAAAAAAAD///////8A//////8AAAAAAAAA////HAAAAAAAAAAQ////AAAAAAAAAP///////wD//////wAAAAAAAAD///9QAAAAAAAAAEz///8AAAAAAAAA////////AP//////AAAAAAAAAP///4gAAAAAAAAAfP///wAAAAAAAAD///////8A//////8AAAAAAAAA////vAAAAAAAAACw////AAAAAAAAAP///////wD//////wAAAAAAAAD////wAAAAAAAAAOz///8AAAAAAAAA////////AP//////AAAAAAAAAP////8sAAAAAAAc/////wAAAAAAAAD///////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'N' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAALD/////////////AAAAAAAAAP//////////AP////////8AAAAAAAAAFOj///////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAASP///////////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAkP//////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAI1P////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAw+P///////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAABw////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAC8//////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAABzs/////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAFD/////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAJz///8AAAAAAAAA//////////8A/////////wAAAAAAAAAUAAAAAAAADNz//wAAAAAAAAD//////////wD/////////AAAAAAAAALQAAAAAAAAANPz/AAAAAAAAAP//////////AP////////8AAAAAAAAA/2wAAAAAAAAAfP8AAAAAAAAA//////////8A/////////wAAAAAAAAD/+CwAAAAAAAAExAAAAAAAAAD//////////wD/////////AAAAAAAAAP//0AQAAAAAAAAgAAAAAAAAAP//////////AP////////8AAAAAAAAA////jAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////RAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP/////kFAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA//////+sAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD///////9kAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP////////QkAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA/////////8wEAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD//////////4QAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP///////////DwAAAAAAAAAAP//////////AP////////8AAAAAAAAA////////////4BAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////////////qAAAAAAAAAD//////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'O' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////0qGw4HAAAABw4aKT0/////////////////wD////////////////wcAwAAAAAAAAAAAAAAAho6P//////////////AP//////////////uBQAAAAAAAAAAAAAAAAAAAAMoP////////////8A/////////////6AEAAAAAAAAAAAAAAAAAAAAAAAAkP///////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP//////////8BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAM5P////////8A//////////9wAAAAAAAAAAAsrPD/7KQsAAAAAAAAAABg/////////wD/////////+BAAAAAAAAAAUPj///////hQAAAAAAAAAAjs////////AP////////+sAAAAAAAAABDw//////////AYAAAAAAAAAKD///////8A/////////2wAAAAAAAAAdP///////////3wAAAAAAAAAYP///////wD/////////OAAAAAAAAAC4////////////xAAAAAAAAAAw////////AP////////8cAAAAAAAAAOD////////////oAAAAAAAAABT///////8A/////////wAAAAAAAAAA//////////////8AAAAAAAAAAP///////wD/////////AAAAAAAAAAD//////////////wAAAAAAAAAA////////AP////////8AAAAAAAAAAP/////////////8AAAAAAAAAAD///////8A/////////xwAAAAAAAAA5P///////////+AAAAAAAAAAHP///////wD/////////NAAAAAAAAAC8////////////uAAAAAAAAAA4////////AP////////9oAAAAAAAAAHj///////////98AAAAAAAAAGT///////8A/////////6gAAAAAAAAAGPD/////////+BgAAAAAAAAApP///////wD/////////9AwAAAAAAAAAUPz///////xcAAAAAAAAAAjs////////AP//////////cAAAAAAAAAAALKjs//CwOAAAAAAAAAAAYP////////8A///////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzk/////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP////////////+QAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A//////////////+sEAAAAAAAAAAAAAAAAAAAAAyg/////////////wD////////////////oZAgAAAAAAAAAAAAAAARg4P//////////////AP//////////////////9KhsOCAAAAAUMFyc7P////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'P' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////wAAAAAAAAAAAAAAAAAACCxguP////////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAOOD//////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAGOD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAARP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAABo////////////AP///////////wAAAAAAAAAA////6JwMAAAAAAAAADD///////////8A////////////AAAAAAAAAAD//////6AAAAAAAAAADP///////////wD///////////8AAAAAAAAAAP//////9AAAAAAAAAAA////////////AP///////////wAAAAAAAAAA///////0AAAAAAAAAAD///////////8A////////////AAAAAAAAAAD//////5gAAAAAAAAAHP///////////wD///////////8AAAAAAAAAAP///9iICAAAAAAAAABI////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAIT/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAABU/P////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAIhPz//////////////wD///////////8AAAAAAAAAAAAAAAAABCRMkOz/////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'Q' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////SoaDQcAAAAHDhoqPT///////////////////8A//////////////BwDAAAAAAAAAAAAAAACHDo/////////////////wD///////////+4FAAAAAAAAAAAAAAAAAAAABCo////////////////AP//////////nAQAAAAAAAAAAAAAAAAAAAAAAACQ//////////////8A/////////7gEAAAAAAAAAAAAAAAAAAAAAAAAAACg/////////////wD////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzo////////////AP///////3AAAAAAAAAAACyo8P/sqCwAAAAAAAAAAGT///////////8A///////4EAAAAAAAAABM+P///////FQAAAAAAAAACPT//////////wD//////7AAAAAAAAAAFPD/////////9BgAAAAAAAAApP//////////AP//////bAAAAAAAAAB4////////////fAAAAAAAAABk//////////8A//////84AAAAAAAAALz///////////+8AAAAAAAAADT//////////wD//////xwAAAAAAAAA6P///////////+QAAAAAAAAAHP//////////AP//////AAAAAAAAAAD//////////////wAAAAAAAAAA//////////8A//////8AAAAAAAAAAP//////////////AAAAAAAAAAD//////////wD//////wAAAAAAAAAA/P////////////8AAAAAAAAAAP//////////AP//////GAAAAAAAAADg////////////4AAAAAAAAAAc//////////8A//////84AAAAAAAAALT////MJHTo//+8AAAAAAAAADT//////////wD//////2wAAAAAAAAAdP///2AAABCg/3wAAAAAAAAAZP//////////AP//////rAAAAAAAAAAY9P/sCAAAAABMGAAAAAAAAACk//////////8A///////4EAAAAAAAAABU/P+0OAAAAAAAAAAAAAAACPT//////////wD///////94AAAAAAAAAAA4sPD/gAAAAAAAAAAAAABk////////////AP////////AcAAAAAAAAAAAAAAAAAAAAAAAAAAAADOT///////////8A/////////7wEAAAAAAAAAAAAAAAAAAAAAAAAAACQ/////////////wD//////////6wEAAAAAAAAAAAAAAAAAAAAAAAAABSs////////////AP///////////7gUAAAAAAAAAAAAAAAAAAAAAAAAAABAwP////////8A//////////////BwDAAAAAAAAAAAAAAABAgAAAAAAAA8/////////wD////////////////0qGg0GAAAABgwXJjkxBgAAAAAALD/////////AP//////////////////////////////////5DQAAAAk/P////////8A////////////////////////////////////+GwAAJD//////////wD//////////////////////////////////////8A49P//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'R' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////wAAAAAAAAAAAAAAAAAAAAQgOGSk+P///////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAcuP//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAEsP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ6P///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADD///////////8A/////////wAAAAAAAAAA///////svDgAAAAAAAAACP///////////wD/////////AAAAAAAAAAD/////////7AAAAAAAAAAA////////////AP////////8AAAAAAAAAAP/////////cAAAAAAAAABD///////////8A/////////wAAAAAAAAAA//////DQoCQAAAAAAAAAQP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACU////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIPj///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAzU/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAA02P//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAxctPz///////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAEDY/////////////////wD/////////AAAAAAAAAAD/9LAsAAAAAAAAAAzc////////////////AP////////8AAAAAAAAAAP///+wkAAAAAAAAADD8//////////////8A/////////wAAAAAAAAAA/////8QAAAAAAAAAAJD//////////////wD/////////AAAAAAAAAAD//////1QAAAAAAAAAFPD/////////////AP////////8AAAAAAAAAAP//////3AQAAAAAAAAAgP////////////8A/////////wAAAAAAAAAA////////aAAAAAAAAAAM6P///////////wD/////////AAAAAAAAAAD////////oCAAAAAAAAABs////////////AP////////8AAAAAAAAAAP////////+AAAAAAAAAAATc//////////8A/////////wAAAAAAAAAA//////////AUAAAAAAAAAFj//////////wD/////////AAAAAAAAAAD//////////5AAAAAAAAAAAND/////////AP////////8AAAAAAAAAAP//////////+CQAAAAAAAAAQP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'S' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////8vHBEIAgAAAQgQHC8/P////////////////8A////////////////pCQAAAAAAAAAAAAAAAAcoP///////////////wD//////////////FwAAAAAAAAAAAAAAAAAAAAAXP//////////////AP////////////9oAAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A////////////zAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////9cAAAAAAAAAAAAAAAAAAAAAAAAAACA////////////AP///////////xgAAAAAAAAAUOD/8KwkAAAAAAAAADj///////////8A////////////AAAAAAAAAAD0/////8wABCAgICxASP///////////wD///////////8MAAAAAAAAAMz/////////////////////////////AP///////////0AAAAAAAAAACFiQxPT///////////////////////8A////////////oAAAAAAAAAAAAAAAADBwtPT//////////////////wD////////////8QAAAAAAAAAAAAAAAAAAACFTA////////////////AP/////////////oOAAAAAAAAAAAAAAAAAAAAABM6P////////////8A///////////////4fAgAAAAAAAAAAAAAAAAAAAAY2P///////////wD/////////////////7IwwAAAAAAAAAAAAAAAAAAAo+P//////////AP/////////////////////koGw0BAAAAAAAAAAAAACU//////////8A///////////////////////////4uFgAAAAAAAAAADz//////////wD//////////2BgSEA0IBwA6P///////5QAAAAAAAAADP//////////AP//////////JAAAAAAAAACc/////////AAAAAAAAAAA//////////8A//////////9YAAAAAAAAACDo///////AAAAAAAAAABT//////////wD//////////6QAAAAAAAAAACCk7P/snBQAAAAAAAAAUP//////////AP//////////+BAAAAAAAAAAAAAAAAAAAAAAAAAAAACs//////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAAOP///////////wD////////////8RAAAAAAAAAAAAAAAAAAAAAAAABjc////////////AP/////////////0PAAAAAAAAAAAAAAAAAAAAAAg2P////////////8A///////////////8hBQAAAAAAAAAAAAAAAAMdPT//////////////wD/////////////////+LRwSCAMAAAAHDhoqPT/////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'T' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'U' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////JAAAAAAAAADk/////////+gAAAAAAAAAHP//////////AP////////9MAAAAAAAAAJz/////////nAAAAAAAAABE//////////8A/////////4gAAAAAAAAAHOj//////+ggAAAAAAAAAHz//////////wD/////////0AAAAAAAAAAAIJzs/+ykIAAAAAAAAAAA0P//////////AP//////////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A///////////IBAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAAAAJj/////////////AP////////////+UBAAAAAAAAAAAAAAAAAAAAASU//////////////8A///////////////IPAAAAAAAAAAAAAAAAAAwyP///////////////wD/////////////////0IxYOCAIAAAEIEiAyP//////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'V' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////zAAAAAAAAAAYP//////////////ZAAAAAAAAAAw////////AP//////kAAAAAAAAAAU/P////////////8UAAAAAAAAAJD///////8A///////oBAAAAAAAAADE////////////xAAAAAAAAAAE7P///////wD///////9MAAAAAAAAAHD///////////94AAAAAAAAAEz/////////AP///////6gAAAAAAAAAJP///////////yQAAAAAAAAArP////////8A////////+BAAAAAAAAAA1P/////////YAAAAAAAAABT4/////////wD/////////aAAAAAAAAACE/////////4QAAAAAAAAAbP//////////AP/////////EAAAAAAAAADT/////////OAAAAAAAAADM//////////8A//////////8kAAAAAAAAAOT//////+QAAAAAAAAAKP///////////wD//////////4QAAAAAAAAAmP//////nAAAAAAAAACI////////////AP//////////5AAAAAAAAABE//////9EAAAAAAAABOT///////////8A////////////QAAAAAAAAAT0////9AgAAAAAAABI/////////////wD///////////+gAAAAAAAAAKT///+kAAAAAAAAAKj/////////////AP////////////QIAAAAAAAAXP///1wAAAAAAAAM+P////////////8A/////////////1wAAAAAAAAM+P/8DAAAAAAAAGT//////////////wD/////////////vAAAAAAAAAC8/7wAAAAAAAAAxP//////////////AP//////////////HAAAAAAAAGj/aAAAAAAAACT///////////////8A//////////////94AAAAAAAAHP8cAAAAAAAAhP///////////////wD//////////////9gAAAAAAAAAkAAAAAAAAADk////////////////AP///////////////zgAAAAAAAAQAAAAAAAAQP////////////////8A////////////////lAAAAAAAAAAAAAAAAACg/////////////////wD////////////////sCAAAAAAAAAAAAAAADPT/////////////////AP////////////////9QAAAAAAAAAAAAAABg//////////////////8A/////////////////7AAAAAAAAAAAAAAAMD//////////////////wD//////////////////BQAAAAAAAAAAAAc////////////////////AP//////////////////cAAAAAAAAAAAAHz///////////////////8A///////////////////MAAAAAAAAAAAA3P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'W' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//8cAAAAAAAAALz/////4AAAAAAAAAAA6P////+8AAAAAAAAABz//wD//1QAAAAAAAAAjP////+gAAAAAAAAAACo/////4wAAAAAAAAAUP//AP//jAAAAAAAAABU/////2AAAAAAAAAAAGj/////VAAAAAAAAACM//8A///EAAAAAAAAACT/////IAAAAAAAAAAAKP////8kAAAAAAAAAMT//wD///gEAAAAAAAAAPD//+AAAAAAAAAAAAAA6P//8AAAAAAAAAAE9P//AP///zAAAAAAAAAAvP//oAAAAAAAAAAAAACo//+8AAAAAAAAADD///8A////bAAAAAAAAACM//9gAAAAAAAAAAAAAGT//4wAAAAAAAAAaP///wD///+kAAAAAAAAAFT//yAAAAAAAAAAAAAAIP//VAAAAAAAAACc////AP///9gAAAAAAAAAJP/gAAAAAAAAAAAAAAAA4P8kAAAAAAAAANT///8A/////xAAAAAAAAAA8KAAAAAAAAAAAAAAAACg8AAAAAAAAAAQ/////wD/////TAAAAAAAAAC8YAAAAAAAAAAAAAAAAGC8AAAAAAAAAET/////AP////+AAAAAAAAAAIwgAAAAAAAAAAAAAAAAIIwAAAAAAAAAfP////8A/////7gAAAAAAAAANAAAAAAAACwwAAAAAAAANAAAAAAAAACw/////wD/////8AAAAAAAAAAAAAAAAAAAdHgAAAAAAAAAAAAAAAAAAOz/////AP//////KAAAAAAAAAAAAAAAAAC4vAAAAAAAAAAAAAAAAAAg//////8A//////9gAAAAAAAAAAAAAAAACPj4CAAAAAAAAAAAAAAAAFj//////wD//////5QAAAAAAAAAAAAAAABE//9IAAAAAAAAAAAAAAAAkP//////AP//////0AAAAAAAAAAAAAAAAIj//4wAAAAAAAAAAAAAAADI//////8A///////8DAAAAAAAAAAAAAAAzP//1AAAAAAAAAAAAAAABPj//////wD///////88AAAAAAAAAAAAABT/////GAAAAAAAAAAAAAA0////////AP///////3QAAAAAAAAAAAAAWP////9gAAAAAAAAAAAAAHD///////8A////////sAAAAAAAAAAAAACg/////6QAAAAAAAAAAAAApP///////wD////////kAAAAAAAAAAAAAOT/////6AAAAAAAAAAAAADc////////AP////////8cAAAAAAAAAAAo////////MAAAAAAAAAAAEP////////8A/////////1QAAAAAAAAAAHD///////94AAAAAAAAAABM/////////wD/////////jAAAAAAAAAAAtP///////7wAAAAAAAAAAID/////////AP/////////EAAAAAAAAAAT0////////+AgAAAAAAAAAuP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'X' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////9UAAAAAAAAAKz///////////+sAAAAAAAAAFD/////////AP///////+QQAAAAAAAAFOT/////////8BwAAAAAAAAM5P////////8A/////////5gAAAAAAAAATP////////9kAAAAAAAAAJD//////////wD//////////0AAAAAAAAAAoP//////wAAAAAAAAAA0/P//////////AP//////////2AgAAAAAAAAQ4P////gkAAAAAAAABMz///////////8A////////////iAAAAAAAAABA////dAAAAAAAAABw/////////////wD////////////8MAAAAAAAAACU/9AEAAAAAAAAHPD/////////////AP/////////////IBAAAAAAAAAzYMAAAAAAAAACs//////////////8A//////////////90AAAAAAAAABAAAAAAAAAATP///////////////wD///////////////QgAAAAAAAAAAAAAAAAAAzg////////////////AP///////////////7wAAAAAAAAAAAAAAAAAjP////////////////8A/////////////////2AAAAAAAAAAAAAAADD8/////////////////wD/////////////////7BQAAAAAAAAAAAAEyP//////////////////AP/////////////////gDAAAAAAAAAAAAAjY//////////////////8A/////////////////0AAAAAAAAAAAAAAADj8/////////////////wD///////////////+UAAAAAAAAAAAAAAAAAJD/////////////////AP//////////////4AwAAAAAAAAAAAAAAAAADOD///////////////8A//////////////9AAAAAAAAAAAAAAAAAAAAAQP///////////////wD/////////////nAAAAAAAAAAAWAAAAAAAAAAAlP//////////////AP///////////+QQAAAAAAAAAGD/YAAAAAAAAAAM4P////////////8A////////////TAAAAAAAAAAs9P/0LAAAAAAAAABM/////////////wD//////////6AAAAAAAAAADNT////UDAAAAAAAAACg////////////AP/////////kEAAAAAAAAACg//////+gAAAAAAAAABDk//////////8A/////////0wAAAAAAAAAYP////////9gAAAAAAAAAEz//////////wD///////+oAAAAAAAAACz0//////////QsAAAAAAAAAKT/////////AP//////7BQAAAAAAAAM1P///////////9QMAAAAAAAAFOz///////8A//////9UAAAAAAAAAKD//////////////6AAAAAAAAAAVP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'Y' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////1QAAAAAAAAAAGj//////////2gAAAAAAAAAAFT///////8A////////5BAAAAAAAAAAAMT////////EAAAAAAAAAAAQ5P///////wD/////////mAAAAAAAAAAAKPj/////+CgAAAAAAAAAAJj/////////AP//////////PAAAAAAAAAAAgP////+AAAAAAAAAAAA8//////////8A///////////YCAAAAAAAAAAE2P//2AQAAAAAAAAACNj//////////wD///////////+AAAAAAAAAAAA4//84AAAAAAAAAACA////////////AP////////////woAAAAAAAAAACUlAAAAAAAAAAAKPz///////////8A/////////////8gAAAAAAAAAABAQAAAAAAAAAADI/////////////wD//////////////2wAAAAAAAAAAAAAAAAAAAAAbP//////////////AP//////////////8BwAAAAAAAAAAAAAAAAAABzw//////////////8A////////////////tAAAAAAAAAAAAAAAAAAAtP///////////////wD/////////////////VAAAAAAAAAAAAAAAAFT/////////////////AP/////////////////oEAAAAAAAAAAAAAAQ6P////////////////8A//////////////////+cAAAAAAAAAAAAAJz//////////////////wD///////////////////9AAAAAAAAAAABA////////////////////AP///////////////////9gAAAAAAAAAANj///////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - 'Z' => array( - 'data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAQ//////////////8A/////////////////////////1AAAAAAAAAABLz//////////////wD///////////////////////98AAAAAAAAAACY////////////////AP//////////////////////pAAAAAAAAAAAaP////////////////8A/////////////////////8QIAAAAAAAAAET8/////////////////wD////////////////////gGAAAAAAAAAAo9P//////////////////AP//////////////////9CwAAAAAAAAAFNz///////////////////8A//////////////////xMAAAAAAAAAATA/////////////////////wD/////////////////eAAAAAAAAAAAnP//////////////////////AP///////////////5wAAAAAAAAAAHT///////////////////////8A///////////////ABAAAAAAAAABM/P///////////////////////wD/////////////3BQAAAAAAAAALPT/////////////////////////AP////////////QoAAAAAAAAABjg//////////////////////////8A///////////8SAAAAAAAAAAExP///////////////////////////wD//////////2wAAAAAAAAAAKD/////////////////////////////AP////////+YAAAAAAAAAAB8//////////////////////////////8A/////////wQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=', - 'width' => 40 - ), - ); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/captcha_abstract.php b/phpBB/includes/captcha/plugins/captcha_abstract.php deleted file mode 100644 index 21cacd730c..0000000000 --- a/phpBB/includes/captcha/plugins/captcha_abstract.php +++ /dev/null @@ -1,380 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2006, 2008 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - - -/** -* This class holds the code shared by the two default 3.0.x CAPTCHAs. -* -* @package VC -*/ -class phpbb_default_captcha -{ - var $confirm_id; - var $confirm_code; - var $code; - var $seed; - var $attempts = 0; - var $type; - var $solved = 0; - var $captcha_vars = false; - - function init($type) - { - global $config, $db, $user; - - // read input - $this->confirm_id = request_var('confirm_id', ''); - $this->confirm_code = request_var('confirm_code', ''); - $refresh = request_var('refresh_vc', false) && $config['confirm_refresh']; - - $this->type = (int) $type; - - if (!strlen($this->confirm_id) || !$this->load_code()) - { - // we have no confirm ID, better get ready to display something - $this->generate_code(); - } - else if ($refresh) - { - $this->regenerate_code(); - } - } - - function execute_demo() - { - global $user; - - $this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $this->seed = hexdec(substr(unique_id(), 4, 10)); - - // compute $seed % 0x7fffffff - $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); - - $captcha = new captcha(); - define('IMAGE_OUTPUT', 1); - $captcha->execute($this->code, $this->seed); - } - - function execute() - { - if (empty($this->code)) - { - if (!$this->load_code()) - { - // invalid request, bail out - return false; - } - } - $captcha = new captcha(); - define('IMAGE_OUTPUT', 1); - $captcha->execute($this->code, $this->seed); - } - - function get_template() - { - global $config, $user, $template, $phpEx, $phpbb_root_path; - - if ($this->is_solved()) - { - return false; - } - else - { - $link = append_sid($phpbb_root_path . 'ucp.' . $phpEx, 'mode=confirm&confirm_id=' . $this->confirm_id . '&type=' . $this->type); - $explain = $user->lang(($this->type != CONFIRM_POST) ? 'CONFIRM_EXPLAIN' : 'POST_CONFIRM_EXPLAIN', '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'); - - $template->assign_vars(array( - 'CONFIRM_IMAGE_LINK' => $link, - 'CONFIRM_IMAGE' => '<img src="' . $link . '" />', - 'CONFIRM_IMG' => '<img src="' . $link . '" />', - 'CONFIRM_ID' => $this->confirm_id, - 'S_CONFIRM_CODE' => true, - 'S_TYPE' => $this->type, - 'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh'] && $this->type == CONFIRM_REG) ? true : false, - 'L_CONFIRM_EXPLAIN' => $explain, - )); - - return 'captcha_default.html'; - } - } - - function get_demo_template($id) - { - global $config, $user, $template, $phpbb_admin_path, $phpEx; - - $variables = ''; - - if (is_array($this->captcha_vars)) - { - foreach ($this->captcha_vars as $captcha_var => $template_var) - { - $variables .= '&' . rawurlencode($captcha_var) . '=' . request_var($captcha_var, (int) $config[$captcha_var]); - } - } - - // acp_captcha has a delivery function; let's use it - $template->assign_vars(array( - 'CONFIRM_IMAGE' => append_sid($phpbb_admin_path . 'index.' . $phpEx, 'captcha_demo=1&mode=visual&i=' . $id . '&select_captcha=' . $this->get_class_name()) . $variables, - 'CONFIRM_ID' => $this->confirm_id, - )); - - return 'captcha_default_acp_demo.html'; - } - - function get_hidden_fields() - { - $hidden_fields = array(); - - // this is required for posting.php - otherwise we would forget about the captcha being already solved - if ($this->solved) - { - $hidden_fields['confirm_code'] = $this->confirm_code; - } - $hidden_fields['confirm_id'] = $this->confirm_id; - return $hidden_fields; - } - - function garbage_collect($type) - { - global $db, $config; - - $sql = 'SELECT DISTINCT c.session_id - FROM ' . CONFIRM_TABLE . ' c - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) - WHERE s.session_id IS NULL' . - ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $sql_in = array(); - do - { - $sql_in[] = (string) $row['session_id']; - } - while ($row = $db->sql_fetchrow($result)); - - if (sizeof($sql_in)) - { - $sql = 'DELETE FROM ' . CONFIRM_TABLE . ' - WHERE ' . $db->sql_in_set('session_id', $sql_in); - $db->sql_query($sql); - } - } - $db->sql_freeresult($result); - } - - function uninstall() - { - $this->garbage_collect(0); - } - - function install() - { - return; - } - - function validate() - { - global $config, $db, $user; - - if (empty($user->lang)) - { - $user->setup(); - } - - $error = ''; - if (!$this->confirm_id) - { - $error = $user->lang['CONFIRM_CODE_WRONG']; - } - else - { - if ($this->check_code()) - { - // $this->delete_code(); commented out to allow posting.php to repeat the question - $this->solved = true; - } - else - { - $error = $user->lang['CONFIRM_CODE_WRONG']; - } - } - - if (strlen($error)) - { - // okay, incorrect answer. Let's ask a new question. - $this->new_attempt(); - return $error; - } - else - { - return false; - } - } - - /** - * The old way to generate code, suitable for GD and non-GD. Resets the internal state. - */ - function generate_code() - { - global $db, $user; - - $this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $this->confirm_id = md5(unique_id($user->ip)); - $this->seed = hexdec(substr(unique_id(), 4, 10)); - $this->solved = 0; - // compute $seed % 0x7fffffff - $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); - - $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $this->confirm_id, - 'session_id' => (string) $user->session_id, - 'confirm_type' => (int) $this->type, - 'code' => (string) $this->code, - 'seed' => (int) $this->seed) - ); - $db->sql_query($sql); - } - - /** - * New Question, if desired. - */ - function regenerate_code() - { - global $db, $user; - - $this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $this->seed = hexdec(substr(unique_id(), 4, 10)); - $this->solved = 0; - // compute $seed % 0x7fffffff - $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); - - $sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( - 'code' => (string) $this->code, - 'seed' => (int) $this->seed)) . ' - WHERE - confirm_id = \'' . $db->sql_escape($this->confirm_id) . '\' - AND session_id = \'' . $db->sql_escape($user->session_id) . '\''; - $db->sql_query($sql); - } - - /** - * New Question, if desired. - */ - function new_attempt() - { - global $db, $user; - - $this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $this->seed = hexdec(substr(unique_id(), 4, 10)); - $this->solved = 0; - // compute $seed % 0x7fffffff - $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); - - $sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( - 'code' => (string) $this->code, - 'seed' => (int) $this->seed)) . ' - , attempts = attempts + 1 - WHERE - confirm_id = \'' . $db->sql_escape($this->confirm_id) . '\' - AND session_id = \'' . $db->sql_escape($user->session_id) . '\''; - $db->sql_query($sql); - } - - /** - * Look up everything we need for painting&checking. - */ - function load_code() - { - global $db, $user; - - $sql = 'SELECT code, seed, attempts - FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . $this->type; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $this->code = $row['code']; - $this->seed = $row['seed']; - $this->attempts = $row['attempts']; - return true; - } - - return false; - } - - function check_code() - { - return (strcasecmp($this->code, $this->confirm_code) === 0); - } - - function delete_code() - { - global $db, $user; - - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . $this->type; - $db->sql_query($sql); - } - - function get_attempt_count() - { - return $this->attempts; - } - - function reset() - { - global $db, $user; - - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . (int) $this->type; - $db->sql_query($sql); - - // we leave the class usable by generating a new question - $this->generate_code(); - } - - function is_solved() - { - if (request_var('confirm_code', false) && $this->solved === 0) - { - $this->validate(); - } - return (bool) $this->solved; - } - - /** - * API function - */ - function has_config() - { - return false; - } - -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php deleted file mode 100644 index 6e899adc16..0000000000 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php +++ /dev/null @@ -1,165 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2006, 2008 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Placeholder for autoload -*/ -if (!class_exists('phpbb_default_captcha')) -{ - include($phpbb_root_path . 'includes/captcha/plugins/captcha_abstract.' . $phpEx); -} - -/** -* @package VC -*/ -class phpbb_captcha_gd extends phpbb_default_captcha -{ - - var $captcha_vars = array( - 'captcha_gd_x_grid' => 'CAPTCHA_GD_X_GRID', - 'captcha_gd_y_grid' => 'CAPTCHA_GD_Y_GRID', - 'captcha_gd_foreground_noise' => 'CAPTCHA_GD_FOREGROUND_NOISE', -// 'captcha_gd' => 'CAPTCHA_GD_PREVIEWED', - 'captcha_gd_wave' => 'CAPTCHA_GD_WAVE', - 'captcha_gd_3d_noise' => 'CAPTCHA_GD_3D_NOISE', - 'captcha_gd_fonts' => 'CAPTCHA_GD_FONTS', - ); - - function phpbb_captcha_gd() - { - global $phpbb_root_path, $phpEx; - - if (!class_exists('captcha')) - { - include($phpbb_root_path . 'includes/captcha/captcha_gd.' . $phpEx); - } - } - - function &get_instance() - { - $instance =& new phpbb_captcha_gd(); - return $instance; - } - - function is_available() - { - global $phpbb_root_path, $phpEx; - - if (@extension_loaded('gd')) - { - return true; - } - - if (!function_exists('can_load_dll')) - { - include($phpbb_root_path . 'includes/functions_install.' . $phpEx); - } - - return can_load_dll('gd'); - } - - /** - * API function - */ - function has_config() - { - return true; - } - - function get_name() - { - return 'CAPTCHA_GD'; - } - - function get_class_name() - { - return 'phpbb_captcha_gd'; - } - - function acp_page($id, &$module) - { - global $db, $user, $auth, $template; - global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; - - $user->add_lang('acp/board'); - - $config_vars = array( - 'enable_confirm' => 'REG_ENABLE', - 'enable_post_confirm' => 'POST_ENABLE', - 'confirm_refresh' => 'CONFIRM_REFRESH', - 'captcha_gd' => 'CAPTCHA_GD', - ); - - $module->tpl_name = 'captcha_gd_acp'; - $module->page_title = 'ACP_VC_SETTINGS'; - $form_key = 'acp_captcha'; - add_form_key($form_key); - - $submit = request_var('submit', ''); - - if ($submit && check_form_key($form_key)) - { - $captcha_vars = array_keys($this->captcha_vars); - foreach ($captcha_vars as $captcha_var) - { - $value = request_var($captcha_var, 0); - if ($value >= 0) - { - set_config($captcha_var, $value); - } - } - - add_log('admin', 'LOG_CONFIG_VISUAL'); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action)); - } - else if ($submit) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action)); - } - else - { - foreach ($this->captcha_vars as $captcha_var => $template_var) - { - $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var]; - $template->assign_var($template_var, $var); - } - - $template->assign_vars(array( - 'CAPTCHA_PREVIEW' => $this->get_demo_template($id), - 'CAPTCHA_NAME' => $this->get_class_name(), - 'U_ACTION' => $module->u_action, - )); - } - } - - function execute_demo() - { - global $config; - - $config_old = $config; - foreach ($this->captcha_vars as $captcha_var => $template_var) - { - $config[$captcha_var] = request_var($captcha_var, (int) $config[$captcha_var]); - } - parent::execute_demo(); - $config = $config_old; - } - -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php deleted file mode 100644 index 2f55d15efd..0000000000 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php +++ /dev/null @@ -1,83 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2006, 2008 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Placeholder for autoload -*/ -if (!class_exists('phpbb_default_captcha')) -{ - include($phpbb_root_path . 'includes/captcha/plugins/captcha_abstract.' . $phpEx); -} - -/** -* @package VC -*/ -class phpbb_captcha_gd_wave extends phpbb_default_captcha -{ - - function phpbb_captcha_gd_wave() - { - global $phpbb_root_path, $phpEx; - - if (!class_exists('captcha')) - { - include_once($phpbb_root_path . 'includes/captcha/captcha_gd_wave.' . $phpEx); - } - } - - function get_instance() - { - return new phpbb_captcha_gd_wave(); - } - - function is_available() - { - global $phpbb_root_path, $phpEx; - - if (@extension_loaded('gd')) - { - return true; - } - - if (!function_exists('can_load_dll')) - { - include($phpbb_root_path . 'includes/functions_install.' . $phpEx); - } - - return can_load_dll('gd'); - } - - function get_name() - { - return 'CAPTCHA_GD_3D'; - } - - function get_class_name() - { - return 'phpbb_captcha_gd_wave'; - } - - function acp_page($id, &$module) - { - global $config, $db, $template, $user; - - trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php deleted file mode 100644 index ac30ed4297..0000000000 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2006, 2008 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Placeholder for autoload -*/ -if (!class_exists('phpbb_default_captcha')) -{ - include($phpbb_root_path . 'includes/captcha/plugins/captcha_abstract.' . $phpEx); -} - -/** -* @package VC -*/ -class phpbb_captcha_nogd extends phpbb_default_captcha -{ - - function phpbb_captcha_nogd() - { - global $phpbb_root_path, $phpEx; - - if (!class_exists('captcha')) - { - include_once($phpbb_root_path . 'includes/captcha/captcha_non_gd.' . $phpEx); - } - } - - function &get_instance() - { - $instance =& new phpbb_captcha_nogd(); - return $instance; - } - - function is_available() - { - return true; - } - - function get_name() - { - return 'CAPTCHA_NO_GD'; - } - - function get_class_name() - { - return 'phpbb_captcha_nogd'; - } - - function acp_page($id, &$module) - { - global $user; - - trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php deleted file mode 100644 index 45f76bd676..0000000000 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ /dev/null @@ -1,1022 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2006, 2008 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -global $table_prefix; - -define('CAPTCHA_QUESTIONS_TABLE', $table_prefix . 'captcha_questions'); -define('CAPTCHA_ANSWERS_TABLE', $table_prefix . 'captcha_answers'); -define('CAPTCHA_QA_CONFIRM_TABLE', $table_prefix . 'qa_confirm'); - -/** -* And now to something completely different. Let's make a captcha without extending the abstract class. -* QA CAPTCHA sample implementation -* -* @package VC -*/ -class phpbb_captcha_qa -{ - var $confirm_id; - var $answer; - var $question_ids; - var $question_text; - var $question_lang; - var $question_strict; - var $attempts = 0; - var $type; - // dirty trick: 0 is false, but can still encode that the captcha is not yet validated - var $solved = 0; - - /** - * @param int $type as per the CAPTCHA API docs, the type - */ - function init($type) - { - global $config, $db, $user; - - // load our language file - $user->add_lang('captcha_qa'); - - // read input - $this->confirm_id = request_var('qa_confirm_id', ''); - $this->answer = utf8_normalize_nfc(request_var('qa_answer', '', true)); - - $this->type = (int) $type; - $this->question_lang = $user->lang_name; - - // we need all defined questions - shouldn't be too many, so we can just grab them - // try the user's lang first - $sql = 'SELECT question_id - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($user->lang_name) . "'"; - $result = $db->sql_query($sql, 3600); - - while ($row = $db->sql_fetchrow($result)) - { - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - - // fallback to the board default lang - if (!sizeof($this->question_ids)) - { - $this->question_lang = $config['default_lang']; - - $sql = 'SELECT question_id - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query($sql, 7200); - - while ($row = $db->sql_fetchrow($result)) - { - $this->question_ids[$row['question_id']] = $row['question_id']; - } - $db->sql_freeresult($result); - } - - // okay, if there is a confirm_id, we try to load that confirm's state. If not, we try to find one - if (!$this->load_answer() && (!$this->load_confirm_id() || !$this->load_answer())) - { - // we have no valid confirm ID, better get ready to ask something - $this->select_question(); - } - } - - /** - * API function - */ - function &get_instance() - { - $instance =& new phpbb_captcha_qa(); - - return $instance; - } - - /** - * See if the captcha has created its tables. - */ - function is_installed() - { - global $db, $phpbb_root_path, $phpEx; - - if (!class_exists('phpbb_db_tools')) - { - include("$phpbb_root_path/includes/db/db_tools.$phpEx"); - } - $db_tool = new phpbb_db_tools($db); - - return $db_tool->sql_table_exists(CAPTCHA_QUESTIONS_TABLE); - } - - /** - * API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang - */ - function is_available() - { - global $config, $db, $phpbb_root_path, $phpEx, $user; - - // load language file for pretty display in the ACP dropdown - $user->add_lang('captcha_qa'); - - if (!phpbb_captcha_qa::is_installed()) - { - return false; - } - - $sql = 'SELECT COUNT(question_id) AS question_count - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - return ((bool) $row['question_count']); - } - - /** - * API function - */ - function has_config() - { - return true; - } - - /** - * API function - */ - function get_name() - { - return 'CAPTCHA_QA'; - } - - /** - * API function - */ - function get_class_name() - { - return 'phpbb_captcha_qa'; - } - - /** - * API function - not needed as we don't display an image - */ - function execute_demo() - { - } - - /** - * API function - not needed as we don't display an image - */ - function execute() - { - } - - /** - * API function - send the question to the template - */ - function get_template() - { - global $template; - - if ($this->is_solved()) - { - return false; - } - else - { - $template->assign_vars(array( - 'QA_CONFIRM_QUESTION' => $this->question_text, - 'QA_CONFIRM_ID' => $this->confirm_id, - 'S_CONFIRM_CODE' => true, - 'S_TYPE' => $this->type, - )); - - return 'captcha_qa.html'; - } - } - - /** - * API function - we just display a mockup so that the captcha doesn't need to be installed - */ - function get_demo_template() - { - global $config, $db, $template; - - if ($this->is_available()) - { - $sql = 'SELECT question_text - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; - $result = $db->sql_query_limit($sql, 1); - if ($row = $db->sql_fetchrow($result)) - { - $template->assign_vars(array( - 'QA_CONFIRM_QUESTION' => $row['question_text'], - )); - } - $db->sql_freeresult($result); - } - return 'captcha_qa_acp_demo.html'; - } - - /** - * API function - */ - function get_hidden_fields() - { - $hidden_fields = array(); - - // this is required - otherwise we would forget about the captcha being already solved - if ($this->solved) - { - $hidden_fields['qa_answer'] = $this->answer; - } - $hidden_fields['qa_confirm_id'] = $this->confirm_id; - - return $hidden_fields; - } - - /** - * API function - */ - function garbage_collect($type = 0) - { - global $db, $config; - - $sql = 'SELECT c.confirm_id - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' c - LEFT JOIN ' . SESSIONS_TABLE . ' s - ON (c.session_id = s.session_id) - WHERE s.session_id IS NULL' . - ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $sql_in = array(); - - do - { - $sql_in[] = (string) $row['confirm_id']; - } - while ($row = $db->sql_fetchrow($result)); - - if (sizeof($sql_in)) - { - $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' - WHERE ' . $db->sql_in_set('confirm_id', $sql_in); - $db->sql_query($sql); - } - } - $db->sql_freeresult($result); - } - - /** - * API function - we don't drop the tables here, as that would cause the loss of all entered questions. - */ - function uninstall() - { - $this->garbage_collect(0); - } - - /** - * API function - set up shop - */ - function install() - { - global $db, $phpbb_root_path, $phpEx; - - if (!class_exists('phpbb_db_tools')) - { - include("$phpbb_root_path/includes/db/db_tools.$phpEx"); - } - $db_tool = new phpbb_db_tools($db); - - $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE, CAPTCHA_QA_CONFIRM_TABLE); - - $schemas = array( - CAPTCHA_QUESTIONS_TABLE => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', Null, 'auto_increment'), - 'strict' => array('BOOL', 0), - 'lang_id' => array('UINT', 0), - 'lang_iso' => array('VCHAR:30', ''), - 'question_text' => array('TEXT_UNI', ''), - ), - 'PRIMARY_KEY' => 'question_id', - 'KEYS' => array( - 'lang' => array('INDEX', 'lang_iso'), - ), - ), - CAPTCHA_ANSWERS_TABLE => array ( - 'COLUMNS' => array( - 'question_id' => array('UINT', 0), - 'answer_text' => array('STEXT_UNI', ''), - ), - 'KEYS' => array( - 'qid' => array('INDEX', 'question_id'), - ), - ), - CAPTCHA_QA_CONFIRM_TABLE => array ( - 'COLUMNS' => array( - 'session_id' => array('CHAR:32', ''), - 'confirm_id' => array('CHAR:32', ''), - 'lang_iso' => array('VCHAR:30', ''), - 'question_id' => array('UINT', 0), - 'attempts' => array('UINT', 0), - 'confirm_type' => array('USINT', 0), - ), - 'KEYS' => array( - 'session_id' => array('INDEX', 'session_id'), - 'lookup' => array('INDEX', array('confirm_id', 'session_id', 'lang_iso')), - ), - 'PRIMARY_KEY' => 'confirm_id', - ), - ); - - foreach($schemas as $table => $schema) - { - if (!$db_tool->sql_table_exists($table)) - { - $db_tool->sql_create_table($table, $schema); - } - } - } - - /** - * API function - see what has to be done to validate - */ - function validate() - { - global $config, $db, $user; - - $error = ''; - - if (!sizeof($this->question_ids)) - { - return false; - } - - if (!$this->confirm_id) - { - $error = $user->lang['CONFIRM_QUESTION_WRONG']; - } - else - { - if ($this->check_answer()) - { - // $this->delete_code(); commented out to allow posting.php to repeat the question - $this->solved = true; - } - else - { - $error = $user->lang['CONFIRM_QUESTION_WRONG']; - } - } - - if (strlen($error)) - { - // okay, incorrect answer. Let's ask a new question. - $this->new_attempt(); - $this->solved = false; - - return $error; - } - else - { - return false; - } - } - - /** - * Select a question - */ - function select_question() - { - global $db, $user; - - if (!sizeof($this->question_ids)) - { - return false; - } - $this->confirm_id = md5(unique_id($user->ip)); - $this->question = (int) array_rand($this->question_ids); - - $sql = 'INSERT INTO ' . CAPTCHA_QA_CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $this->confirm_id, - 'session_id' => (string) $user->session_id, - 'lang_iso' => (string) $this->question_lang, - 'confirm_type' => (int) $this->type, - 'question_id' => (int) $this->question, - )); - $db->sql_query($sql); - - $this->load_answer(); - } - - /** - * New Question, if desired. - */ - function reselect_question() - { - global $db, $user; - - if (!sizeof($this->question_ids)) - { - return false; - } - - $this->question = (int) array_rand($this->question_ids); - $this->solved = 0; - - $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' - SET question_id = ' . (int) $this->question . " - WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $db->sql_query($sql); - - $this->load_answer(); - } - - /** - * Wrong answer, so we increase the attempts and use a different question. - */ - function new_attempt() - { - global $db, $user; - - // yah, I would prefer a stronger rand, but this should work - $this->question = (int) array_rand($this->question_ids); - $this->solved = 0; - - $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' - SET question_id = ' . (int) $this->question . ", - attempts = attempts + 1 - WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "'"; - $db->sql_query($sql); - - $this->load_answer(); - } - - - /** - * See if there is already an entry for the current session. - */ - function load_confirm_id() - { - global $db, $user; - - $sql = 'SELECT confirm_id - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " - WHERE - session_id = '" . $db->sql_escape($user->session_id) . "' - AND lang_iso = '" . $db->sql_escape($this->question_lang) . "' - AND confirm_type = " . $this->type; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $this->confirm_id = $row['confirm_id']; - return true; - } - return false; - } - - /** - * Look up everything we need and populate the instance variables. - */ - function load_answer() - { - global $db, $user; - - if (!strlen($this->confirm_id) || !sizeof($this->question_ids)) - { - return false; - } - - $sql = 'SELECT con.question_id, attempts, question_text, strict - FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' con, ' . CAPTCHA_QUESTIONS_TABLE . " qes - WHERE con.question_id = qes.question_id - AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND qes.lang_iso = '" . $db->sql_escape($this->question_lang) . "' - AND confirm_type = " . $this->type; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $this->question = $row['question_id']; - - $this->attempts = $row['attempts']; - $this->question_strict = $row['strict']; - $this->question_text = $row['question_text']; - - return true; - } - - return false; - } - - /** - * The actual validation - */ - function check_answer() - { - global $db; - - $answer = ($this->question_strict) ? utf8_normalize_nfc(request_var('qa_answer', '', true)) : utf8_clean_string(utf8_normalize_nfc(request_var('qa_answer', '', true))); - - $sql = 'SELECT answer_text - FROM ' . CAPTCHA_ANSWERS_TABLE . ' - WHERE question_id = ' . (int) $this->question; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $solution = ($this->question_strict) ? $row['answer_text'] : utf8_clean_string($row['answer_text']); - - if ($solution === $answer) - { - $this->solved = true; - - break; - } - } - $db->sql_freeresult($result); - - return $this->solved; - } - - /** - * API function - clean the entry - */ - function delete_code() - { - global $db, $user; - - $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . $this->type; - $db->sql_query($sql); - } - - /** - * API function - */ - function get_attempt_count() - { - return $this->attempts; - } - - /** - * API function - */ - function reset() - { - global $db, $user; - - $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . (int) $this->type; - $db->sql_query($sql); - - // we leave the class usable by generating a new question - $this->select_question(); - } - - /** - * API function - */ - function is_solved() - { - if (request_var('qa_answer', false) && $this->solved === 0) - { - $this->validate(); - } - - return (bool) $this->solved; - } - - /** - * API function - The ACP backend, this marks the end of the easy methods - */ - function acp_page($id, &$module) - { - global $db, $user, $auth, $template; - global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; - - $user->add_lang('acp/board'); - $user->add_lang('captcha_qa'); - - if (!$this->is_installed()) - { - $this->install(); - } - - $module->tpl_name = 'captcha_qa_acp'; - $module->page_title = 'ACP_VC_SETTINGS'; - $form_key = 'acp_captcha'; - add_form_key($form_key); - - $submit = request_var('submit', false); - $question_id = request_var('question_id', 0); - $action = request_var('action', ''); - - // we have two pages, so users might want to navigate from one to the other - $list_url = $module->u_action . "&configure=1&select_captcha=" . $this->get_class_name(); - - $template->assign_vars(array( - 'U_ACTION' => $module->u_action, - 'QUESTION_ID' => $question_id , - 'CLASS' => $this->get_class_name(), - )); - - // show the list? - if (!$question_id && $action != 'add') - { - $this->acp_question_list($module); - } - else if ($question_id && $action == 'delete') - { - if ($this->get_class_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id)) - { - if (confirm_box(true)) - { - $this->acp_delete_question($question_id); - - trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url)); - } - else - { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'question_id' => $question_id, - 'action' => $action, - 'configure' => 1, - 'select_captcha' => $this->get_class_name(), - )) - ); - } - } - else - { - trigger_error($user->lang['QA_LAST_QUESTION'] . adm_back_link($list_url), E_USER_WARNING); - } - } - else - { - // okay, show the editor - $error = false; - $input_question = request_var('question_text', '', true); - $input_answers = request_var('answers', '', true); - $input_lang = request_var('lang_iso', '', true); - $input_strict = request_var('strict', false); - $langs = $this->get_languages(); - - foreach ($langs as $lang => $entry) - { - $template->assign_block_vars('langs', array( - 'ISO' => $lang, - 'NAME' => $entry['name'], - )); - } - - $template->assign_vars(array( - 'U_LIST' => $list_url, - )); - - if ($question_id) - { - if ($question = $this->acp_get_question_data($question_id)) - { - $answers = (isset($input_answers[$lang])) ? $input_answers[$lang] : implode("\n", $question['answers']); - - $template->assign_vars(array( - 'QUESTION_TEXT' => ($input_question) ? $input_question : $question['question_text'], - 'LANG_ISO' => ($input_lang) ? $input_lang : $question['lang_iso'], - 'STRICT' => (isset($_REQUEST['strict'])) ? $input_strict : $question['strict'], - 'ANSWERS' => $answers, - )); - } - else - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); - } - } - else - { - $template->assign_vars(array( - 'QUESTION_TEXT' => $input_question, - 'LANG_ISO' => $input_lang, - 'STRICT' => $input_strict, - 'ANSWERS' => $input_answers, - )); - } - - if ($submit && check_form_key($form_key)) - { - $data = $this->acp_get_question_input(); - - if (!$this->validate_input($data)) - { - $template->assign_vars(array( - 'S_ERROR' => true, - )); - } - else - { - if ($question_id) - { - $this->acp_update_question($data, $question_id); - } - else - { - $this->acp_add_question($data); - } - - add_log('admin', 'LOG_CONFIG_VISUAL'); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url)); - } - } - else if ($submit) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url), E_USER_WARNING); - } - } - } - - /** - * This handles the list overview - */ - function acp_question_list(&$module) - { - global $db, $template; - - $sql = 'SELECT * - FROM ' . CAPTCHA_QUESTIONS_TABLE; - $result = $db->sql_query($sql); - - $template->assign_vars(array( - 'S_LIST' => true, - )); - - while ($row = $db->sql_fetchrow($result)) - { - $url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_class_name() . '&'; - - $template->assign_block_vars('questions', array( - 'QUESTION_TEXT' => $row['question_text'], - 'QUESTION_ID' => $row['question_id'], - 'QUESTION_LANG' => $row['lang_iso'], - 'U_DELETE' => "{$url}action=delete", - 'U_EDIT' => "{$url}action=edit", - )); - } - $db->sql_freeresult($result); - } - - /** - * Grab a question and bring it into a format the editor understands - */ - function acp_get_question_data($question_id) - { - global $db; - - if ($question_id) - { - $sql = 'SELECT * - FROM ' . CAPTCHA_QUESTIONS_TABLE . ' - WHERE question_id = ' . $question_id; - $result = $db->sql_query($sql); - $question = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$question) - { - return false; - } - - $question['answers'] = array(); - - $sql = 'SELECT * - FROM ' . CAPTCHA_ANSWERS_TABLE . ' - WHERE question_id = ' . $question_id; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $question['answers'][] = $row['answer_text']; - } - $db->sql_freeresult($result); - - return $question; - } - } - - /** - * Grab a question from input and bring it into a format the editor understands - */ - function acp_get_question_input() - { - $answers = utf8_normalize_nfc(request_var('answers', '', true)); - $question = array( - 'question_text' => request_var('question_text', '', true), - 'strict' => request_var('strict', false), - 'lang_iso' => request_var('lang_iso', ''), - 'answers' => (strlen($answers)) ? explode("\n", $answers) : '', - ); - - return $question; - } - - /** - * Update a question. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_update_question($data, $question_id) - { - global $db, $cache; - - // easier to delete all answers than to figure out which to update - $sql = 'DELETE FROM ' . CAPTCHA_ANSWERS_TABLE . " WHERE question_id = $question_id"; - $db->sql_query($sql); - - $langs = $this->get_languages(); - $question_ary = $data; - $question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id']; - unset($question_ary['answers']); - - $sql = 'UPDATE ' . CAPTCHA_QUESTIONS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $question_ary) . " - WHERE question_id = $question_id"; - $db->sql_query($sql); - - $this->acp_insert_answers($data, $question_id); - - $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); - } - - /** - * Insert a question. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_add_question($data) - { - global $db, $cache; - - $langs = $this->get_languages(); - $question_ary = $data; - - $question_ary['lang_id'] = $langs[$data['lang_iso']]['id']; - unset($question_ary['answers']); - - $sql = 'INSERT INTO ' . CAPTCHA_QUESTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $question_ary); - $db->sql_query($sql); - - $question_id = $db->sql_nextid(); - - $this->acp_insert_answers($data, $question_id); - - $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); - } - - /** - * Insert the answers. - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function acp_insert_answers($data, $question_id) - { - global $db, $cache; - - foreach ($data['answers'] as $answer) - { - $answer_ary = array( - 'question_id' => $question_id, - 'answer_text' => $answer, - ); - - $sql = 'INSERT INTO ' . CAPTCHA_ANSWERS_TABLE . ' ' . $db->sql_build_array('INSERT', $answer_ary); - $db->sql_query($sql); - } - - $cache->destroy('sql', CAPTCHA_ANSWERS_TABLE); - } - - /** - * Delete a question. - */ - function acp_delete_question($question_id) - { - global $db, $cache; - - $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE); - - foreach ($tables as $table) - { - $sql = "DELETE FROM $table - WHERE question_id = $question_id"; - $db->sql_query($sql); - } - - $cache->destroy('sql', $tables); - } - - /** - * Check if the entered data can be inserted/used - * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data - */ - function validate_input($question_data) - { - $langs = $this->get_languages(); - - if (!isset($question_data['lang_iso']) || - !isset($question_data['question_text']) || - !isset($question_data['strict']) || - !isset($question_data['answers'])) - { - return false; - } - - if (!isset($langs[$question_data['lang_iso']]) || - !strlen($question_data['question_text']) || - !sizeof($question_data['answers']) || - !is_array($question_data['answers'])) - { - return false; - } - - return true; - } - - /** - * List the installed language packs - */ - function get_languages() - { - global $db; - - $sql = 'SELECT * - FROM ' . LANG_TABLE; - $result = $db->sql_query($sql); - - $langs = array(); - while ($row = $db->sql_fetchrow($result)) - { - $langs[$row['lang_iso']] = array( - 'name' => $row['lang_local_name'], - 'id' => (int) $row['lang_id'], - ); - } - $db->sql_freeresult($result); - - return $langs; - } - - - - /** - * See if there is a question other than the one we have - */ - function acp_is_last($question_id) - { - global $config, $db; - - if ($question_id) - { - $sql = 'SELECT question_id - FROM ' . CAPTCHA_QUESTIONS_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "' - AND question_id <> " . (int) $question_id; - $result = $db->sql_query_limit($sql, 1); - $question = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$question) - { - return true; - } - return false; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php deleted file mode 100644 index 0b0270f568..0000000000 --- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php +++ /dev/null @@ -1,345 +0,0 @@ -<?php -/** -* -* @package VC -* @version $Id$ -* @copyright (c) 2006, 2008 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -if (!class_exists('phpbb_default_captcha')) -{ - // we need the classic captcha code for tracking solutions and attempts - include($phpbb_root_path . 'includes/captcha/plugins/captcha_abstract.' . $phpEx); -} - -/** -* @package VC -*/ -class phpbb_recaptcha extends phpbb_default_captcha -{ - var $recaptcha_server = 'http://www.google.com/recaptcha/api'; - var $recaptcha_server_secure = 'https://www.google.com/recaptcha/api'; // class constants :( - - // We are opening a socket to port 80 of this host and send - // the POST request asking for verification to the path specified here. - var $recaptcha_verify_server = 'www.google.com'; - var $recaptcha_verify_path = '/recaptcha/api/verify'; - - var $challenge; - var $response; - - // PHP4 Constructor - function phpbb_recaptcha() - { - $this->recaptcha_server = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? $this->recaptcha_server_secure : $this->recaptcha_server; - } - - function init($type) - { - global $config, $db, $user; - - $user->add_lang('captcha_recaptcha'); - parent::init($type); - $this->challenge = request_var('recaptcha_challenge_field', ''); - $this->response = request_var('recaptcha_response_field', ''); - } - - function &get_instance() - { - $instance =& new phpbb_recaptcha(); - return $instance; - } - - function is_available() - { - global $config, $user; - $user->add_lang('captcha_recaptcha'); - return (isset($config['recaptcha_pubkey']) && !empty($config['recaptcha_pubkey'])); - } - - /** - * API function - */ - function has_config() - { - return true; - } - - function get_name() - { - return 'CAPTCHA_RECAPTCHA'; - } - - function get_class_name() - { - return 'phpbb_recaptcha'; - } - - function acp_page($id, &$module) - { - global $config, $db, $template, $user; - - $captcha_vars = array( - 'recaptcha_pubkey' => 'RECAPTCHA_PUBKEY', - 'recaptcha_privkey' => 'RECAPTCHA_PRIVKEY', - ); - - $module->tpl_name = 'captcha_recaptcha_acp'; - $module->page_title = 'ACP_VC_SETTINGS'; - $form_key = 'acp_captcha'; - add_form_key($form_key); - - $submit = request_var('submit', ''); - - if ($submit && check_form_key($form_key)) - { - $captcha_vars = array_keys($captcha_vars); - foreach ($captcha_vars as $captcha_var) - { - $value = request_var($captcha_var, ''); - if ($value) - { - set_config($captcha_var, $value); - } - } - - add_log('admin', 'LOG_CONFIG_VISUAL'); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action)); - } - else if ($submit) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action)); - } - else - { - foreach ($captcha_vars as $captcha_var => $template_var) - { - $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, '') : ((isset($config[$captcha_var])) ? $config[$captcha_var] : ''); - $template->assign_var($template_var, $var); - } - - $template->assign_vars(array( - 'CAPTCHA_PREVIEW' => $this->get_demo_template($id), - 'CAPTCHA_NAME' => $this->get_class_name(), - 'U_ACTION' => $module->u_action, - )); - - } - } - - // not needed - function execute_demo() - { - } - - // not needed - function execute() - { - } - - function get_template() - { - global $config, $user, $template; - - if ($this->is_solved()) - { - return false; - } - else - { - $explain = $user->lang(($this->type != CONFIRM_POST) ? 'CONFIRM_EXPLAIN' : 'POST_CONFIRM_EXPLAIN', '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'); - - $template->assign_vars(array( - 'RECAPTCHA_SERVER' => $this->recaptcha_server, - 'RECAPTCHA_PUBKEY' => isset($config['recaptcha_pubkey']) ? $config['recaptcha_pubkey'] : '', - 'RECAPTCHA_ERRORGET' => '', - 'S_RECAPTCHA_AVAILABLE' => $this->is_available(), - 'S_CONFIRM_CODE' => true, - 'S_TYPE' => $this->type, - 'L_CONFIRM_EXPLAIN' => $explain, - )); - - return 'captcha_recaptcha.html'; - } - } - - function get_demo_template($id) - { - return $this->get_template(); - } - - function get_hidden_fields() - { - $hidden_fields = array(); - - // this is required for posting.php - otherwise we would forget about the captcha being already solved - if ($this->solved) - { - $hidden_fields['confirm_code'] = $this->code; - } - $hidden_fields['confirm_id'] = $this->confirm_id; - return $hidden_fields; - } - - function uninstall() - { - $this->garbage_collect(0); - } - - function install() - { - return; - } - - function validate() - { - if (!parent::validate()) - { - return false; - } - else - { - return $this->recaptcha_check_answer(); - } - } - -// Code from here on is based on recaptchalib.php -/* - * This is a PHP library that handles calling reCAPTCHA. - * - Documentation and latest version - * http://recaptcha.net/plugins/php/ - * - Get a reCAPTCHA API Key - * http://recaptcha.net/api/getkey - * - Discussion group - * http://groups.google.com/group/recaptcha - * - * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net - * AUTHORS: - * Mike Crawford - * Ben Maurer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - /** - * Submits an HTTP POST to a reCAPTCHA server - * @param string $host - * @param string $path - * @param array $data - * @param int port - * @return array response - */ - function _recaptcha_http_post($host, $path, $data, $port = 80) - { - $req = $this->_recaptcha_qsencode ($data); - - $http_request = "POST $path HTTP/1.0\r\n"; - $http_request .= "Host: $host\r\n"; - $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; - $http_request .= "Content-Length: " . strlen($req) . "\r\n"; - $http_request .= "User-Agent: reCAPTCHA/PHP/phpBB\r\n"; - $http_request .= "\r\n"; - $http_request .= $req; - - $response = ''; - if (false == ($fs = @fsockopen($host, $port, $errno, $errstr, 10))) - { - trigger_error('Could not open socket', E_USER_ERROR); - } - - fwrite($fs, $http_request); - - while (!feof($fs)) - { - // One TCP-IP packet - $response .= fgets($fs, 1160); - } - fclose($fs); - $response = explode("\r\n\r\n", $response, 2); - - return $response; - } - - /** - * Calls an HTTP POST function to verify if the user's guess was correct - * @param array $extra_params an array of extra variables to post to the server - * @return ReCaptchaResponse - */ - function recaptcha_check_answer($extra_params = array()) - { - global $config, $user; - - //discard spam submissions - if ($this->challenge == null || strlen($this->challenge) == 0 || $this->response == null || strlen($this->response) == 0) - { - return $user->lang['RECAPTCHA_INCORRECT']; - } - - $response = $this->_recaptcha_http_post($this->recaptcha_verify_server, $this->recaptcha_verify_path, - array( - 'privatekey' => $config['recaptcha_privkey'], - 'remoteip' => $user->ip, - 'challenge' => $this->challenge, - 'response' => $this->response - ) + $extra_params - ); - - $answers = explode("\n", $response[1]); - - if (trim($answers[0]) === 'true') - { - $this->solved = true; - return false; - } - else - { - return $user->lang['RECAPTCHA_INCORRECT']; - } - } - - /** - * Encodes the given data into a query string format - * @param $data - array of string elements to be encoded - * @return string - encoded request - */ - function _recaptcha_qsencode($data) - { - $req = ''; - foreach ($data as $key => $value) - { - $req .= $key . '=' . urlencode(stripslashes($value)) . '&'; - } - - // Cut the last '&' - $req = substr($req, 0, strlen($req) - 1); - return $req; - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/compatibility_globals.php b/phpBB/includes/compatibility_globals.php new file mode 100644 index 0000000000..54c9287c96 --- /dev/null +++ b/phpBB/includes/compatibility_globals.php @@ -0,0 +1,47 @@ +<?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. +* +*/ + +/** +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +// set up caching +$cache = $phpbb_container->get('cache'); + +// Instantiate some basic classes +$phpbb_dispatcher = $phpbb_container->get('dispatcher'); +$request = $phpbb_container->get('request'); +$user = $phpbb_container->get('user'); +$auth = $phpbb_container->get('auth'); +$db = $phpbb_container->get('dbal.conn'); + +// make sure request_var uses this request instance +request_var('', 0, false, false, $request); // "dependency injection" for a function + +// Grab global variables, re-cache if necessary +$config = $phpbb_container->get('config'); +set_config(null, null, null, $config); +set_config_count(null, null, null, $config); + +$phpbb_log = $phpbb_container->get('log'); +$symfony_request = $phpbb_container->get('symfony_request'); +$phpbb_filesystem = $phpbb_container->get('filesystem'); +$phpbb_path_helper = $phpbb_container->get('path_helper'); + +// load extensions +$phpbb_extension_manager = $phpbb_container->get('ext.manager'); + +$template = $phpbb_container->get('template'); diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index b0e814cc6a..2fa489ff2d 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -25,7 +28,7 @@ if (!defined('IN_PHPBB')) */ // phpBB Version -define('PHPBB_VERSION', '3.0.14-dev'); +define('PHPBB_VERSION', '3.1.4-RC1'); // QA-related // define('PHPBB_QA', 1); @@ -47,10 +50,10 @@ define('USER_INACTIVE', 1); define('USER_IGNORE', 2); define('USER_FOUNDER', 3); -define('INACTIVE_REGISTER', 1); -define('INACTIVE_PROFILE', 2); -define('INACTIVE_MANUAL', 3); -define('INACTIVE_REMIND', 4); +define('INACTIVE_REGISTER', 1); // Newly registered account +define('INACTIVE_PROFILE', 2); // Profile details changed +define('INACTIVE_MANUAL', 3); // Account deactivated by administrator +define('INACTIVE_REMIND', 4); // Forced user account reactivation // ACL define('ACL_NEVER', 0); @@ -62,6 +65,7 @@ define('LOGIN_CONTINUE', 1); define('LOGIN_BREAK', 2); define('LOGIN_SUCCESS', 3); define('LOGIN_SUCCESS_CREATE_PROFILE', 20); +define('LOGIN_SUCCESS_LINK_PROFILE', 21); define('LOGIN_ERROR_USERNAME', 10); define('LOGIN_ERROR_PASSWORD', 11); define('LOGIN_ERROR_ACTIVE', 12); @@ -88,6 +92,11 @@ define('ITEM_UNLOCKED', 0); define('ITEM_LOCKED', 1); define('ITEM_MOVED', 2); +define('ITEM_UNAPPROVED', 0); // => has not yet been approved +define('ITEM_APPROVED', 1); // => has been approved, and has not been soft deleted +define('ITEM_DELETED', 2); // => has been soft deleted +define('ITEM_REAPPROVE', 3); // => has been edited and needs to be re-approved + // Forum Flags define('FORUM_FLAG_LINK_TRACK', 1); define('FORUM_FLAG_PRUNE_POLL', 2); @@ -224,9 +233,11 @@ define('BBCODES_TABLE', $table_prefix . 'bbcodes'); define('BOOKMARKS_TABLE', $table_prefix . 'bookmarks'); define('BOTS_TABLE', $table_prefix . 'bots'); define('CONFIG_TABLE', $table_prefix . 'config'); +define('CONFIG_TEXT_TABLE', $table_prefix . 'config_text'); define('CONFIRM_TABLE', $table_prefix . 'confirm'); define('DISALLOW_TABLE', $table_prefix . 'disallow'); define('DRAFTS_TABLE', $table_prefix . 'drafts'); +define('EXT_TABLE', $table_prefix . 'ext'); define('EXTENSIONS_TABLE', $table_prefix . 'extensions'); define('EXTENSION_GROUPS_TABLE', $table_prefix . 'extension_groups'); define('FORUMS_TABLE', $table_prefix . 'forums'); @@ -238,8 +249,11 @@ define('ICONS_TABLE', $table_prefix . 'icons'); define('LANG_TABLE', $table_prefix . 'lang'); define('LOG_TABLE', $table_prefix . 'log'); define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts'); +define('MIGRATIONS_TABLE', $table_prefix . 'migrations'); define('MODERATOR_CACHE_TABLE', $table_prefix . 'moderator_cache'); define('MODULES_TABLE', $table_prefix . 'modules'); +define('NOTIFICATION_TYPES_TABLE', $table_prefix . 'notification_types'); +define('NOTIFICATIONS_TABLE', $table_prefix . 'notifications'); define('POLL_OPTIONS_TABLE', $table_prefix . 'poll_options'); define('POLL_VOTES_TABLE', $table_prefix . 'poll_votes'); define('POSTS_TABLE', $table_prefix . 'posts'); @@ -261,23 +275,23 @@ define('SESSIONS_TABLE', $table_prefix . 'sessions'); define('SESSIONS_KEYS_TABLE', $table_prefix . 'sessions_keys'); define('SITELIST_TABLE', $table_prefix . 'sitelist'); define('SMILIES_TABLE', $table_prefix . 'smilies'); +define('SPHINX_TABLE', $table_prefix . 'sphinx'); define('STYLES_TABLE', $table_prefix . 'styles'); define('STYLES_TEMPLATE_TABLE', $table_prefix . 'styles_template'); define('STYLES_TEMPLATE_DATA_TABLE',$table_prefix . 'styles_template_data'); define('STYLES_THEME_TABLE', $table_prefix . 'styles_theme'); define('STYLES_IMAGESET_TABLE', $table_prefix . 'styles_imageset'); define('STYLES_IMAGESET_DATA_TABLE',$table_prefix . 'styles_imageset_data'); +define('TEAMPAGE_TABLE', $table_prefix . 'teampage'); define('TOPICS_TABLE', $table_prefix . 'topics'); define('TOPICS_POSTED_TABLE', $table_prefix . 'topics_posted'); define('TOPICS_TRACK_TABLE', $table_prefix . 'topics_track'); define('TOPICS_WATCH_TABLE', $table_prefix . 'topics_watch'); define('USER_GROUP_TABLE', $table_prefix . 'user_group'); +define('USER_NOTIFICATIONS_TABLE', $table_prefix . 'user_notifications'); define('USERS_TABLE', $table_prefix . 'users'); define('WARNINGS_TABLE', $table_prefix . 'warnings'); define('WORDS_TABLE', $table_prefix . 'words'); define('ZEBRA_TABLE', $table_prefix . 'zebra'); // Additional tables - - -?> diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php deleted file mode 100644 index 6913960185..0000000000 --- a/phpBB/includes/db/db_tools.php +++ /dev/null @@ -1,2525 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2007 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Database Tools for handling cross-db actions such as altering columns, etc. -* Currently not supported is returning SQL for creating tables. -* -* @package dbal -* @note currently not used within phpBB3, but may be utilized later. -*/ -class phpbb_db_tools -{ - /** - * Current sql layer - */ - var $sql_layer = ''; - - /** - * @var object DB object - */ - var $db = NULL; - - /** - * The Column types for every database we support - * @var array - */ - var $dbms_type_map = array( - 'mysql_41' => array( - 'INT:' => 'int(%d)', - 'BINT' => 'bigint(20)', - 'UINT' => 'mediumint(8) UNSIGNED', - 'UINT:' => 'int(%d) UNSIGNED', - 'TINT:' => 'tinyint(%d)', - 'USINT' => 'smallint(4) UNSIGNED', - 'BOOL' => 'tinyint(1) UNSIGNED', - 'VCHAR' => 'varchar(255)', - 'VCHAR:' => 'varchar(%d)', - 'CHAR:' => 'char(%d)', - 'XSTEXT' => 'text', - 'XSTEXT_UNI'=> 'varchar(100)', - 'STEXT' => 'text', - 'STEXT_UNI' => 'varchar(255)', - 'TEXT' => 'text', - 'TEXT_UNI' => 'text', - 'MTEXT' => 'mediumtext', - 'MTEXT_UNI' => 'mediumtext', - 'TIMESTAMP' => 'int(11) UNSIGNED', - 'DECIMAL' => 'decimal(5,2)', - 'DECIMAL:' => 'decimal(%d,2)', - 'PDECIMAL' => 'decimal(6,3)', - 'PDECIMAL:' => 'decimal(%d,3)', - 'VCHAR_UNI' => 'varchar(255)', - 'VCHAR_UNI:'=> 'varchar(%d)', - 'VCHAR_CI' => 'varchar(255)', - 'VARBINARY' => 'varbinary(255)', - ), - - 'mysql_40' => array( - 'INT:' => 'int(%d)', - 'BINT' => 'bigint(20)', - 'UINT' => 'mediumint(8) UNSIGNED', - 'UINT:' => 'int(%d) UNSIGNED', - 'TINT:' => 'tinyint(%d)', - 'USINT' => 'smallint(4) UNSIGNED', - 'BOOL' => 'tinyint(1) UNSIGNED', - 'VCHAR' => 'varbinary(255)', - 'VCHAR:' => 'varbinary(%d)', - 'CHAR:' => 'binary(%d)', - 'XSTEXT' => 'blob', - 'XSTEXT_UNI'=> 'blob', - 'STEXT' => 'blob', - 'STEXT_UNI' => 'blob', - 'TEXT' => 'blob', - 'TEXT_UNI' => 'blob', - 'MTEXT' => 'mediumblob', - 'MTEXT_UNI' => 'mediumblob', - 'TIMESTAMP' => 'int(11) UNSIGNED', - 'DECIMAL' => 'decimal(5,2)', - 'DECIMAL:' => 'decimal(%d,2)', - 'PDECIMAL' => 'decimal(6,3)', - 'PDECIMAL:' => 'decimal(%d,3)', - 'VCHAR_UNI' => 'blob', - 'VCHAR_UNI:'=> array('varbinary(%d)', 'limit' => array('mult', 3, 255, 'blob')), - 'VCHAR_CI' => 'blob', - 'VARBINARY' => 'varbinary(255)', - ), - - 'firebird' => array( - 'INT:' => 'INTEGER', - 'BINT' => 'DOUBLE PRECISION', - 'UINT' => 'INTEGER', - 'UINT:' => 'INTEGER', - 'TINT:' => 'INTEGER', - 'USINT' => 'INTEGER', - 'BOOL' => 'INTEGER', - 'VCHAR' => 'VARCHAR(255) CHARACTER SET NONE', - 'VCHAR:' => 'VARCHAR(%d) CHARACTER SET NONE', - 'CHAR:' => 'CHAR(%d) CHARACTER SET NONE', - 'XSTEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE', - 'STEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE', - 'TEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE', - 'MTEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE', - 'XSTEXT_UNI'=> 'VARCHAR(100) CHARACTER SET UTF8', - 'STEXT_UNI' => 'VARCHAR(255) CHARACTER SET UTF8', - 'TEXT_UNI' => 'BLOB SUB_TYPE TEXT CHARACTER SET UTF8', - 'MTEXT_UNI' => 'BLOB SUB_TYPE TEXT CHARACTER SET UTF8', - 'TIMESTAMP' => 'INTEGER', - 'DECIMAL' => 'DOUBLE PRECISION', - 'DECIMAL:' => 'DOUBLE PRECISION', - 'PDECIMAL' => 'DOUBLE PRECISION', - 'PDECIMAL:' => 'DOUBLE PRECISION', - 'VCHAR_UNI' => 'VARCHAR(255) CHARACTER SET UTF8', - 'VCHAR_UNI:'=> 'VARCHAR(%d) CHARACTER SET UTF8', - 'VCHAR_CI' => 'VARCHAR(255) CHARACTER SET UTF8', - 'VARBINARY' => 'CHAR(255) CHARACTER SET NONE', - ), - - 'mssql' => array( - 'INT:' => '[int]', - 'BINT' => '[float]', - 'UINT' => '[int]', - 'UINT:' => '[int]', - 'TINT:' => '[int]', - 'USINT' => '[int]', - 'BOOL' => '[int]', - 'VCHAR' => '[varchar] (255)', - 'VCHAR:' => '[varchar] (%d)', - 'CHAR:' => '[char] (%d)', - 'XSTEXT' => '[varchar] (1000)', - 'STEXT' => '[varchar] (3000)', - 'TEXT' => '[varchar] (8000)', - 'MTEXT' => '[text]', - 'XSTEXT_UNI'=> '[varchar] (100)', - 'STEXT_UNI' => '[varchar] (255)', - 'TEXT_UNI' => '[varchar] (4000)', - 'MTEXT_UNI' => '[text]', - 'TIMESTAMP' => '[int]', - 'DECIMAL' => '[float]', - 'DECIMAL:' => '[float]', - 'PDECIMAL' => '[float]', - 'PDECIMAL:' => '[float]', - 'VCHAR_UNI' => '[varchar] (255)', - 'VCHAR_UNI:'=> '[varchar] (%d)', - 'VCHAR_CI' => '[varchar] (255)', - 'VARBINARY' => '[varchar] (255)', - ), - - 'mssqlnative' => array( - 'INT:' => '[int]', - 'BINT' => '[float]', - 'UINT' => '[int]', - 'UINT:' => '[int]', - 'TINT:' => '[int]', - 'USINT' => '[int]', - 'BOOL' => '[int]', - 'VCHAR' => '[varchar] (255)', - 'VCHAR:' => '[varchar] (%d)', - 'CHAR:' => '[char] (%d)', - 'XSTEXT' => '[varchar] (1000)', - 'STEXT' => '[varchar] (3000)', - 'TEXT' => '[varchar] (8000)', - 'MTEXT' => '[text]', - 'XSTEXT_UNI'=> '[varchar] (100)', - 'STEXT_UNI' => '[varchar] (255)', - 'TEXT_UNI' => '[varchar] (4000)', - 'MTEXT_UNI' => '[text]', - 'TIMESTAMP' => '[int]', - 'DECIMAL' => '[float]', - 'DECIMAL:' => '[float]', - 'PDECIMAL' => '[float]', - 'PDECIMAL:' => '[float]', - 'VCHAR_UNI' => '[varchar] (255)', - 'VCHAR_UNI:'=> '[varchar] (%d)', - 'VCHAR_CI' => '[varchar] (255)', - 'VARBINARY' => '[varchar] (255)', - ), - - 'oracle' => array( - 'INT:' => 'number(%d)', - 'BINT' => 'number(20)', - 'UINT' => 'number(8)', - 'UINT:' => 'number(%d)', - 'TINT:' => 'number(%d)', - 'USINT' => 'number(4)', - 'BOOL' => 'number(1)', - 'VCHAR' => 'varchar2(255)', - 'VCHAR:' => 'varchar2(%d)', - 'CHAR:' => 'char(%d)', - 'XSTEXT' => 'varchar2(1000)', - 'STEXT' => 'varchar2(3000)', - 'TEXT' => 'clob', - 'MTEXT' => 'clob', - 'XSTEXT_UNI'=> 'varchar2(300)', - 'STEXT_UNI' => 'varchar2(765)', - 'TEXT_UNI' => 'clob', - 'MTEXT_UNI' => 'clob', - 'TIMESTAMP' => 'number(11)', - 'DECIMAL' => 'number(5, 2)', - 'DECIMAL:' => 'number(%d, 2)', - 'PDECIMAL' => 'number(6, 3)', - 'PDECIMAL:' => 'number(%d, 3)', - 'VCHAR_UNI' => 'varchar2(765)', - 'VCHAR_UNI:'=> array('varchar2(%d)', 'limit' => array('mult', 3, 765, 'clob')), - 'VCHAR_CI' => 'varchar2(255)', - 'VARBINARY' => 'raw(255)', - ), - - 'sqlite' => array( - 'INT:' => 'int(%d)', - 'BINT' => 'bigint(20)', - 'UINT' => 'INTEGER UNSIGNED', //'mediumint(8) UNSIGNED', - 'UINT:' => 'INTEGER UNSIGNED', // 'int(%d) UNSIGNED', - 'TINT:' => 'tinyint(%d)', - 'USINT' => 'INTEGER UNSIGNED', //'mediumint(4) UNSIGNED', - 'BOOL' => 'INTEGER UNSIGNED', //'tinyint(1) UNSIGNED', - 'VCHAR' => 'varchar(255)', - 'VCHAR:' => 'varchar(%d)', - 'CHAR:' => 'char(%d)', - 'XSTEXT' => 'text(65535)', - 'STEXT' => 'text(65535)', - 'TEXT' => 'text(65535)', - 'MTEXT' => 'mediumtext(16777215)', - 'XSTEXT_UNI'=> 'text(65535)', - 'STEXT_UNI' => 'text(65535)', - 'TEXT_UNI' => 'text(65535)', - 'MTEXT_UNI' => 'mediumtext(16777215)', - 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED', - 'DECIMAL' => 'decimal(5,2)', - 'DECIMAL:' => 'decimal(%d,2)', - 'PDECIMAL' => 'decimal(6,3)', - 'PDECIMAL:' => 'decimal(%d,3)', - 'VCHAR_UNI' => 'varchar(255)', - 'VCHAR_UNI:'=> 'varchar(%d)', - 'VCHAR_CI' => 'varchar(255)', - 'VARBINARY' => 'blob', - ), - - 'postgres' => array( - 'INT:' => 'INT4', - 'BINT' => 'INT8', - 'UINT' => 'INT4', // unsigned - 'UINT:' => 'INT4', // unsigned - 'USINT' => 'INT2', // unsigned - 'BOOL' => 'INT2', // unsigned - 'TINT:' => 'INT2', - 'VCHAR' => 'varchar(255)', - 'VCHAR:' => 'varchar(%d)', - 'CHAR:' => 'char(%d)', - 'XSTEXT' => 'varchar(1000)', - 'STEXT' => 'varchar(3000)', - 'TEXT' => 'varchar(8000)', - 'MTEXT' => 'TEXT', - 'XSTEXT_UNI'=> 'varchar(100)', - 'STEXT_UNI' => 'varchar(255)', - 'TEXT_UNI' => 'varchar(4000)', - 'MTEXT_UNI' => 'TEXT', - 'TIMESTAMP' => 'INT4', // unsigned - 'DECIMAL' => 'decimal(5,2)', - 'DECIMAL:' => 'decimal(%d,2)', - 'PDECIMAL' => 'decimal(6,3)', - 'PDECIMAL:' => 'decimal(%d,3)', - 'VCHAR_UNI' => 'varchar(255)', - 'VCHAR_UNI:'=> 'varchar(%d)', - 'VCHAR_CI' => 'varchar_ci', - 'VARBINARY' => 'bytea', - ), - ); - - /** - * A list of types being unsigned for better reference in some db's - * @var array - */ - var $unsigned_types = array('UINT', 'UINT:', 'USINT', 'BOOL', 'TIMESTAMP'); - - /** - * A list of supported DBMS. We change this class to support more DBMS, the DBMS itself only need to follow some rules. - * @var array - */ - var $supported_dbms = array('firebird', 'mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite'); - - /** - * This is set to true if user only wants to return the 'to-be-executed' SQL statement(s) (as an array). - * This mode has no effect on some methods (inserting of data for example). This is expressed within the methods command. - */ - var $return_statements = false; - - /** - * Constructor. Set DB Object and set {@link $return_statements return_statements}. - * - * @param phpbb_dbal $db DBAL object - * @param bool $return_statements True if only statements should be returned and no SQL being executed - */ - function phpbb_db_tools(&$db, $return_statements = false) - { - $this->db = $db; - $this->return_statements = $return_statements; - - // Determine mapping database type - switch ($this->db->sql_layer) - { - case 'mysql': - $this->sql_layer = 'mysql_40'; - break; - - case 'mysql4': - if (version_compare($this->db->sql_server_info(true), '4.1.3', '>=')) - { - $this->sql_layer = 'mysql_41'; - } - else - { - $this->sql_layer = 'mysql_40'; - } - break; - - case 'mysqli': - $this->sql_layer = 'mysql_41'; - break; - - case 'mssql': - case 'mssql_odbc': - $this->sql_layer = 'mssql'; - break; - - case 'mssqlnative': - $this->sql_layer = 'mssqlnative'; - break; - - default: - $this->sql_layer = $this->db->sql_layer; - break; - } - } - - /** - * Gets a list of tables in the database. - * - * @return array Array of table names (all lower case) - */ - function sql_list_tables() - { - switch ($this->db->sql_layer) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $sql = 'SHOW TABLES'; - break; - - case 'sqlite': - $sql = 'SELECT name - FROM sqlite_master - WHERE type = "table"'; - break; - - case 'mssql': - case 'mssql_odbc': - case 'mssqlnative': - $sql = "SELECT name - FROM sysobjects - WHERE type='U'"; - break; - - case 'postgres': - $sql = 'SELECT relname - FROM pg_stat_user_tables'; - break; - - case 'firebird': - $sql = 'SELECT rdb$relation_name - FROM rdb$relations - WHERE rdb$view_source is null - AND rdb$system_flag = 0'; - break; - - case 'oracle': - $sql = 'SELECT table_name - FROM USER_TABLES'; - break; - } - - $result = $this->db->sql_query($sql); - - $tables = array(); - while ($row = $this->db->sql_fetchrow($result)) - { - $name = current($row); - $tables[$name] = $name; - } - $this->db->sql_freeresult($result); - - return $tables; - } - - /** - * Check if table exists - * - * - * @param string $table_name The table name to check for - * @return bool true if table exists, else false - */ - function sql_table_exists($table_name) - { - $this->db->sql_return_on_error(true); - $result = $this->db->sql_query_limit('SELECT * FROM ' . $table_name, 1); - $this->db->sql_return_on_error(false); - - if ($result) - { - $this->db->sql_freeresult($result); - return true; - } - - return false; - } - - /** - * Create SQL Table - * - * @param string $table_name The table name to create - * @param array $table_data Array containing table data. - * @return array Statements if $return_statements is true. - */ - function sql_create_table($table_name, $table_data) - { - // holds the DDL for a column - $columns = $statements = array(); - - if ($this->sql_table_exists($table_name)) - { - return $this->_sql_run_sql($statements); - } - - // Begin transaction - $statements[] = 'begin'; - - // Determine if we have created a PRIMARY KEY in the earliest - $primary_key_gen = false; - - // Determine if the table requires a sequence - $create_sequence = false; - - // Begin table sql statement - switch ($this->sql_layer) - { - case 'mssql': - case 'mssqlnative': - $table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n"; - break; - - default: - $table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n"; - break; - } - - if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') - { - if (!isset($table_data['PRIMARY_KEY'])) - { - $table_data['COLUMNS']['mssqlindex'] = array('UINT', null, 'auto_increment'); - $table_data['PRIMARY_KEY'] = 'mssqlindex'; - } - } - - // Iterate through the columns to create a table - foreach ($table_data['COLUMNS'] as $column_name => $column_data) - { - // here lies an array, filled with information compiled on the column's data - $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data); - - if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen" - { - trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR); - } - - // here we add the definition of the new column to the list of columns - switch ($this->sql_layer) - { - case 'mssql': - case 'mssqlnative': - $columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default']; - break; - - default: - $columns[] = "\t {$column_name} " . $prepared_column['column_type_sql']; - break; - } - - // see if we have found a primary key set due to a column definition if we have found it, we can stop looking - if (!$primary_key_gen) - { - $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set']; - } - - // create sequence DDL based off of the existance of auto incrementing columns - if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment']) - { - $create_sequence = $column_name; - } - } - - // this makes up all the columns in the create table statement - $table_sql .= implode(",\n", $columns); - - // Close the table for two DBMS and add to the statements - switch ($this->sql_layer) - { - case 'firebird': - case 'mssql': - case 'mssqlnative': - $table_sql .= "\n);"; - $statements[] = $table_sql; - break; - } - - // we have yet to create a primary key for this table, - // this means that we can add the one we really wanted instead - if (!$primary_key_gen) - { - // Write primary key - if (isset($table_data['PRIMARY_KEY'])) - { - if (!is_array($table_data['PRIMARY_KEY'])) - { - $table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']); - } - - switch ($this->sql_layer) - { - case 'mysql_40': - case 'mysql_41': - case 'postgres': - case 'sqlite': - $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')'; - break; - - case 'firebird': - case 'mssql': - case 'mssqlnative': - // We need the data here - $old_return_statements = $this->return_statements; - $this->return_statements = true; - - $primary_key_stmts = $this->sql_create_primary_key($table_name, $table_data['PRIMARY_KEY']); - foreach ($primary_key_stmts as $pk_stmt) - { - $statements[] = $pk_stmt; - } - - $this->return_statements = $old_return_statements; - break; - - case 'oracle': - $table_sql .= ",\n\t CONSTRAINT pk_{$table_name} PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')'; - break; - } - } - } - - // close the table - switch ($this->sql_layer) - { - case 'mysql_41': - // make sure the table is in UTF-8 mode - $table_sql .= "\n) CHARACTER SET `utf8` COLLATE `utf8_bin`;"; - $statements[] = $table_sql; - break; - - case 'mysql_40': - case 'sqlite': - $table_sql .= "\n);"; - $statements[] = $table_sql; - break; - - case 'postgres': - // do we need to add a sequence for auto incrementing columns? - if ($create_sequence) - { - $statements[] = "CREATE SEQUENCE {$table_name}_seq;"; - } - - $table_sql .= "\n);"; - $statements[] = $table_sql; - break; - - case 'oracle': - $table_sql .= "\n)"; - $statements[] = $table_sql; - - // do we need to add a sequence and a tigger for auto incrementing columns? - if ($create_sequence) - { - // create the actual sequence - $statements[] = "CREATE SEQUENCE {$table_name}_seq"; - - // the trigger is the mechanism by which we increment the counter - $trigger = "CREATE OR REPLACE TRIGGER t_{$table_name}\n"; - $trigger .= "BEFORE INSERT ON {$table_name}\n"; - $trigger .= "FOR EACH ROW WHEN (\n"; - $trigger .= "\tnew.{$create_sequence} IS NULL OR new.{$create_sequence} = 0\n"; - $trigger .= ")\n"; - $trigger .= "BEGIN\n"; - $trigger .= "\tSELECT {$table_name}_seq.nextval\n"; - $trigger .= "\tINTO :new.{$create_sequence}\n"; - $trigger .= "\tFROM dual;\n"; - $trigger .= "END;"; - - $statements[] = $trigger; - } - break; - - case 'firebird': - if ($create_sequence) - { - $statements[] = "CREATE GENERATOR {$table_name}_gen;"; - $statements[] = "SET GENERATOR {$table_name}_gen TO 0;"; - - $trigger = "CREATE TRIGGER t_$table_name FOR $table_name\n"; - $trigger .= "BEFORE INSERT\nAS\nBEGIN\n"; - $trigger .= "\tNEW.{$create_sequence} = GEN_ID({$table_name}_gen, 1);\nEND;"; - $statements[] = $trigger; - } - break; - } - - // Write Keys - if (isset($table_data['KEYS'])) - { - foreach ($table_data['KEYS'] as $key_name => $key_data) - { - if (!is_array($key_data[1])) - { - $key_data[1] = array($key_data[1]); - } - - $old_return_statements = $this->return_statements; - $this->return_statements = true; - - $key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]); - - foreach ($key_stmts as $key_stmt) - { - $statements[] = $key_stmt; - } - - $this->return_statements = $old_return_statements; - } - } - - // Commit Transaction - $statements[] = 'commit'; - - return $this->_sql_run_sql($statements); - } - - /** - * Handle passed database update array. - * Expected structure... - * Key being one of the following - * change_columns: Column changes (only type, not name) - * add_columns: Add columns to a table - * drop_keys: Dropping keys - * drop_columns: Removing/Dropping columns - * add_primary_keys: adding primary keys - * add_unique_index: adding an unique index - * add_index: adding an index (can be column:index_size if you need to provide size) - * - * The values are in this format: - * {TABLE NAME} => array( - * {COLUMN NAME} => array({COLUMN TYPE}, {DEFAULT VALUE}, {OPTIONAL VARIABLES}), - * {KEY/INDEX NAME} => array({COLUMN NAMES}), - * ) - * - * For more information have a look at /develop/create_schema_files.php (only available through SVN) - */ - function perform_schema_changes($schema_changes) - { - if (empty($schema_changes)) - { - return; - } - - $statements = array(); - $sqlite = false; - - // For SQLite we need to perform the schema changes in a much more different way - if ($this->db->sql_layer == 'sqlite' && $this->return_statements) - { - $sqlite_data = array(); - $sqlite = true; - } - - // Drop tables? - if (!empty($schema_changes['drop_tables'])) - { - foreach ($schema_changes['drop_tables'] as $table) - { - // only drop table if it exists - if ($this->sql_table_exists($table)) - { - $result = $this->sql_table_drop($table); - if ($this->return_statements) - { - $statements = array_merge($statements, $result); - } - } - } - } - - // Add tables? - if (!empty($schema_changes['add_tables'])) - { - foreach ($schema_changes['add_tables'] as $table => $table_data) - { - $result = $this->sql_create_table($table, $table_data); - if ($this->return_statements) - { - $statements = array_merge($statements, $result); - } - } - } - - // Change columns? - if (!empty($schema_changes['change_columns'])) - { - foreach ($schema_changes['change_columns'] as $table => $columns) - { - foreach ($columns as $column_name => $column_data) - { - // If the column exists we change it, else we add it ;) - if ($column_exists = $this->sql_column_exists($table, $column_name)) - { - $result = $this->sql_column_change($table, $column_name, $column_data, true); - } - else - { - $result = $this->sql_column_add($table, $column_name, $column_data, true); - } - - if ($sqlite) - { - if ($column_exists) - { - $sqlite_data[$table]['change_columns'][] = $result; - } - else - { - $sqlite_data[$table]['add_columns'][] = $result; - } - } - else if ($this->return_statements) - { - $statements = array_merge($statements, $result); - } - } - } - } - - // Add columns? - if (!empty($schema_changes['add_columns'])) - { - foreach ($schema_changes['add_columns'] as $table => $columns) - { - foreach ($columns as $column_name => $column_data) - { - // Only add the column if it does not exist yet - if ($column_exists = $this->sql_column_exists($table, $column_name)) - { - continue; - // This is commented out here because it can take tremendous time on updates -// $result = $this->sql_column_change($table, $column_name, $column_data, true); - } - else - { - $result = $this->sql_column_add($table, $column_name, $column_data, true); - } - - if ($sqlite) - { - if ($column_exists) - { - continue; -// $sqlite_data[$table]['change_columns'][] = $result; - } - else - { - $sqlite_data[$table]['add_columns'][] = $result; - } - } - else if ($this->return_statements) - { - $statements = array_merge($statements, $result); - } - } - } - } - - // Remove keys? - if (!empty($schema_changes['drop_keys'])) - { - foreach ($schema_changes['drop_keys'] as $table => $indexes) - { - foreach ($indexes as $index_name) - { - if (!$this->sql_index_exists($table, $index_name)) - { - continue; - } - - $result = $this->sql_index_drop($table, $index_name); - - if ($this->return_statements) - { - $statements = array_merge($statements, $result); - } - } - } - } - - // Drop columns? - if (!empty($schema_changes['drop_columns'])) - { - foreach ($schema_changes['drop_columns'] as $table => $columns) - { - foreach ($columns as $column) - { - // Only remove the column if it exists... - if ($this->sql_column_exists($table, $column)) - { - $result = $this->sql_column_remove($table, $column, true); - - if ($sqlite) - { - $sqlite_data[$table]['drop_columns'][] = $result; - } - else if ($this->return_statements) - { - $statements = array_merge($statements, $result); - } - } - } - } - } - - // Add primary keys? - if (!empty($schema_changes['add_primary_keys'])) - { - foreach ($schema_changes['add_primary_keys'] as $table => $columns) - { - $result = $this->sql_create_primary_key($table, $columns, true); - - if ($sqlite) - { - $sqlite_data[$table]['primary_key'] = $result; - } - else if ($this->return_statements) - { - $statements = array_merge($statements, $result); - } - } - } - - // Add unique indexes? - if (!empty($schema_changes['add_unique_index'])) - { - foreach ($schema_changes['add_unique_index'] as $table => $index_array) - { - foreach ($index_array as $index_name => $column) - { - if ($this->sql_unique_index_exists($table, $index_name)) - { - continue; - } - - $result = $this->sql_create_unique_index($table, $index_name, $column); - - if ($this->return_statements) - { - $statements = array_merge($statements, $result); - } - } - } - } - - // Add indexes? - if (!empty($schema_changes['add_index'])) - { - foreach ($schema_changes['add_index'] as $table => $index_array) - { - foreach ($index_array as $index_name => $column) - { - if ($this->sql_index_exists($table, $index_name)) - { - continue; - } - - $result = $this->sql_create_index($table, $index_name, $column); - - if ($this->return_statements) - { - $statements = array_merge($statements, $result); - } - } - } - } - - if ($sqlite) - { - foreach ($sqlite_data as $table_name => $sql_schema_changes) - { - // Create temporary table with original data - $statements[] = 'begin'; - - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) - { - continue; - } - - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); - $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; - $statements[] = 'DROP TABLE ' . $table_name; - - // Get the columns... - preg_match('#\((.*)\)#s', $row['sql'], $matches); - - $plain_table_cols = trim($matches[1]); - $new_table_cols = preg_split('/,(?![\s\w]+\))/m', $plain_table_cols); - $column_list = array(); - - foreach ($new_table_cols as $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY') - { - continue; - } - $column_list[] = $entities[0]; - } - - // note down the primary key notation because sqlite only supports adding it to the end for the new table - $primary_key = false; - $_new_cols = array(); - - foreach ($new_table_cols as $key => $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY') - { - $primary_key = $declaration; - continue; - } - $_new_cols[] = $declaration; - } - - $new_table_cols = $_new_cols; - - // First of all... change columns - if (!empty($sql_schema_changes['change_columns'])) - { - foreach ($sql_schema_changes['change_columns'] as $column_sql) - { - foreach ($new_table_cols as $key => $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - if (strpos($column_sql, $entities[0] . ' ') === 0) - { - $new_table_cols[$key] = $column_sql; - } - } - } - } - - if (!empty($sql_schema_changes['add_columns'])) - { - foreach ($sql_schema_changes['add_columns'] as $column_sql) - { - $new_table_cols[] = $column_sql; - } - } - - // Now drop them... - if (!empty($sql_schema_changes['drop_columns'])) - { - foreach ($sql_schema_changes['drop_columns'] as $column_name) - { - // Remove from column list... - $new_column_list = array(); - foreach ($column_list as $key => $value) - { - if ($value === $column_name) - { - continue; - } - - $new_column_list[] = $value; - } - - $column_list = $new_column_list; - - // Remove from table... - $_new_cols = array(); - foreach ($new_table_cols as $key => $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - if (strpos($column_name . ' ', $entities[0] . ' ') === 0) - { - continue; - } - $_new_cols[] = $declaration; - } - $new_table_cols = $_new_cols; - } - } - - // Primary key... - if (!empty($sql_schema_changes['primary_key'])) - { - $new_table_cols[] = 'PRIMARY KEY (' . implode(', ', $sql_schema_changes['primary_key']) . ')'; - } - // Add a new one or the old primary key - else if ($primary_key !== false) - { - $new_table_cols[] = $primary_key; - } - - $columns = implode(',', $column_list); - - // create a new table and fill it up. destroy the temp one - $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $new_table_cols) . ');'; - $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; - $statements[] = 'DROP TABLE ' . $table_name . '_temp'; - - $statements[] = 'commit'; - } - } - - if ($this->return_statements) - { - return $statements; - } - } - - /** - * Gets a list of columns of a table. - * - * @param string $table Table name - * - * @return array Array of column names (all lower case) - */ - function sql_list_columns($table) - { - $columns = array(); - - switch ($this->sql_layer) - { - case 'mysql_40': - case 'mysql_41': - $sql = "SHOW COLUMNS FROM $table"; - break; - - // PostgreSQL has a way of doing this in a much simpler way but would - // not allow us to support all versions of PostgreSQL - case 'postgres': - $sql = "SELECT a.attname - FROM pg_class c, pg_attribute a - WHERE c.relname = '{$table}' - AND a.attnum > 0 - AND a.attrelid = c.oid"; - break; - - // same deal with PostgreSQL, we must perform more complex operations than - // we technically could - case 'mssql': - case 'mssqlnative': - $sql = "SELECT c.name - FROM syscolumns c - LEFT JOIN sysobjects o ON c.id = o.id - WHERE o.name = '{$table}'"; - break; - - case 'oracle': - $sql = "SELECT column_name - FROM user_tab_columns - WHERE LOWER(table_name) = '" . strtolower($table) . "'"; - break; - - case 'firebird': - $sql = "SELECT RDB\$FIELD_NAME as FNAME - FROM RDB\$RELATION_FIELDS - WHERE RDB\$RELATION_NAME = '" . strtoupper($table) . "'"; - break; - - case 'sqlite': - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table}'"; - - $result = $this->db->sql_query($sql); - - if (!$result) - { - return false; - } - - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - preg_match('#\((.*)\)#s', $row['sql'], $matches); - - $cols = trim($matches[1]); - $col_array = preg_split('/,(?![\s\w]+\))/m', $cols); - - foreach ($col_array as $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY') - { - continue; - } - - $column = strtolower($entities[0]); - $columns[$column] = $column; - } - - return $columns; - break; - } - - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - $column = strtolower(current($row)); - $columns[$column] = $column; - } - $this->db->sql_freeresult($result); - - return $columns; - } - - /** - * Check whether a specified column exist in a table - * - * @param string $table Table to check - * @param string $column_name Column to check - * - * @return bool True if column exists, false otherwise - */ - function sql_column_exists($table, $column_name) - { - $columns = $this->sql_list_columns($table); - - return isset($columns[$column_name]); - } - - /** - * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes. - * - * @param string $table_name Table to check the index at - * @param string $index_name The index name to check - * - * @return bool True if index exists, else false - */ - function sql_index_exists($table_name, $index_name) - { - if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') - { - $sql = "EXEC sp_statistics '$table_name'"; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - if ($row['TYPE'] == 3) - { - if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) - { - $this->db->sql_freeresult($result); - return true; - } - } - } - $this->db->sql_freeresult($result); - - return false; - } - - switch ($this->sql_layer) - { - case 'firebird': - $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name - FROM RDB\$INDICES - WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "' - AND RDB\$UNIQUE_FLAG IS NULL - AND RDB\$FOREIGN_KEY IS NULL"; - $col = 'index_name'; - break; - - case 'postgres': - $sql = "SELECT ic.relname as index_name - FROM pg_class bc, pg_class ic, pg_index i - WHERE (bc.oid = i.indrelid) - AND (ic.oid = i.indexrelid) - AND (bc.relname = '" . $table_name . "') - AND (i.indisunique != 't') - AND (i.indisprimary != 't')"; - $col = 'index_name'; - break; - - case 'mysql_40': - case 'mysql_41': - $sql = 'SHOW KEYS - FROM ' . $table_name; - $col = 'Key_name'; - break; - - case 'oracle': - $sql = "SELECT index_name - FROM user_indexes - WHERE table_name = '" . strtoupper($table_name) . "' - AND generated = 'N' - AND uniqueness = 'NONUNIQUE'"; - $col = 'index_name'; - break; - - case 'sqlite': - $sql = "PRAGMA index_list('" . $table_name . "');"; - $col = 'name'; - break; - } - - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) - { - continue; - } - - // These DBMS prefix index name with the table name - switch ($this->sql_layer) - { - case 'firebird': - case 'oracle': - case 'postgres': - case 'sqlite': - $row[$col] = substr($row[$col], strlen($table_name) + 1); - break; - } - - if (strtolower($row[$col]) == strtolower($index_name)) - { - $this->db->sql_freeresult($result); - return true; - } - } - $this->db->sql_freeresult($result); - - return false; - } - - /** - * Check if a specified index exists in table. Does not return PRIMARY KEY indexes. - * - * @param string $table_name Table to check the index at - * @param string $index_name The index name to check - * - * @return bool True if index exists, else false - */ - function sql_unique_index_exists($table_name, $index_name) - { - if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') - { - $sql = "EXEC sp_statistics '$table_name'"; - $result = $this->db->sql_query($sql); - - while ($row = $this->db->sql_fetchrow($result)) - { - // Usually NON_UNIQUE is the column we want to check, but we allow for both - if ($row['TYPE'] == 3) - { - if (strtolower($row['INDEX_NAME']) == strtolower($index_name)) - { - $this->db->sql_freeresult($result); - return true; - } - } - } - $this->db->sql_freeresult($result); - return false; - } - - switch ($this->sql_layer) - { - case 'firebird': - $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name - FROM RDB\$INDICES - WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "' - AND RDB\$UNIQUE_FLAG IS NOT NULL - AND RDB\$FOREIGN_KEY IS NULL"; - $col = 'index_name'; - break; - - case 'postgres': - $sql = "SELECT ic.relname as index_name, i.indisunique - FROM pg_class bc, pg_class ic, pg_index i - WHERE (bc.oid = i.indrelid) - AND (ic.oid = i.indexrelid) - AND (bc.relname = '" . $table_name . "') - AND (i.indisprimary != 't')"; - $col = 'index_name'; - break; - - case 'mysql_40': - case 'mysql_41': - $sql = 'SHOW KEYS - FROM ' . $table_name; - $col = 'Key_name'; - break; - - case 'oracle': - $sql = "SELECT index_name, table_owner - FROM user_indexes - WHERE table_name = '" . strtoupper($table_name) . "' - AND generated = 'N' - AND uniqueness = 'UNIQUE'"; - $col = 'index_name'; - break; - - case 'sqlite': - $sql = "PRAGMA index_list('" . $table_name . "');"; - $col = 'name'; - break; - } - - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY')) - { - continue; - } - - if ($this->sql_layer == 'sqlite' && !$row['unique']) - { - continue; - } - - if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't') - { - continue; - } - - // These DBMS prefix index name with the table name - switch ($this->sql_layer) - { - case 'oracle': - // Two cases here... prefixed with U_[table_owner] and not prefixed with table_name - if (strpos($row[$col], 'U_') === 0) - { - $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1); - } - else if (strpos($row[$col], strtoupper($table_name)) === 0) - { - $row[$col] = substr($row[$col], strlen($table_name) + 1); - } - break; - - case 'firebird': - case 'postgres': - case 'sqlite': - $row[$col] = substr($row[$col], strlen($table_name) + 1); - break; - } - - if (strtolower($row[$col]) == strtolower($index_name)) - { - $this->db->sql_freeresult($result); - return true; - } - } - $this->db->sql_freeresult($result); - - return false; - } - - /** - * Private method for performing sql statements (either execute them or return them) - * @access private - */ - function _sql_run_sql($statements) - { - if ($this->return_statements) - { - return $statements; - } - - // We could add error handling here... - foreach ($statements as $sql) - { - if ($sql === 'begin') - { - $this->db->sql_transaction('begin'); - } - else if ($sql === 'commit') - { - $this->db->sql_transaction('commit'); - } - else - { - $this->db->sql_query($sql); - } - } - - return true; - } - - /** - * Function to prepare some column information for better usage - * @access private - */ - function sql_prepare_column_data($table_name, $column_name, $column_data) - { - if (strlen($column_name) > 30) - { - trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR); - } - - // Get type - if (strpos($column_data[0], ':') !== false) - { - list($orig_column_type, $column_length) = explode(':', $column_data[0]); - if (!is_array($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'])) - { - $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'], $column_length); - } - else - { - if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'])) - { - switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][0]) - { - case 'div': - $column_length /= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][1]; - $column_length = ceil($column_length); - $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length); - break; - } - } - - if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'])) - { - switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][0]) - { - case 'mult': - $column_length *= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][1]; - if ($column_length > $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][2]) - { - $column_type = $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][3]; - } - else - { - $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length); - } - break; - } - } - } - $orig_column_type .= ':'; - } - else - { - $orig_column_type = $column_data[0]; - $column_type = $this->dbms_type_map[$this->sql_layer][$column_data[0]]; - } - - // Adjust default value if db-dependant specified - if (is_array($column_data[1])) - { - $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default']; - } - - $sql = ''; - - $return_array = array(); - - switch ($this->sql_layer) - { - case 'firebird': - $sql .= " {$column_type} "; - $return_array['column_type_sql_type'] = " {$column_type} "; - - if (!is_null($column_data[1])) - { - $sql .= 'DEFAULT ' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' '; - $return_array['column_type_sql_default'] = ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' '; - } - - $sql .= 'NOT NULL'; - - // This is a UNICODE column and thus should be given it's fair share - if (preg_match('/^X?STEXT_UNI|VCHAR_(CI|UNI:?)/', $column_data[0])) - { - $sql .= ' COLLATE UNICODE'; - } - - $return_array['auto_increment'] = false; - if (isset($column_data[2]) && $column_data[2] == 'auto_increment') - { - $return_array['auto_increment'] = true; - } - - break; - - case 'mssql': - case 'mssqlnative': - $sql .= " {$column_type} "; - $sql_default = " {$column_type} "; - - // For adding columns we need the default definition - if (!is_null($column_data[1])) - { - // For hexadecimal values do not use single quotes - if (strpos($column_data[1], '0x') === 0) - { - $return_array['default'] = 'DEFAULT (' . $column_data[1] . ') '; - $sql_default .= $return_array['default']; - } - else - { - $return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') '; - $sql_default .= $return_array['default']; - } - } - - if (isset($column_data[2]) && $column_data[2] == 'auto_increment') - { -// $sql .= 'IDENTITY (1, 1) '; - $sql_default .= 'IDENTITY (1, 1) '; - } - - $return_array['textimage'] = $column_type === '[text]'; - - $sql .= 'NOT NULL'; - $sql_default .= 'NOT NULL'; - - $return_array['column_type_sql_default'] = $sql_default; - - break; - - case 'mysql_40': - case 'mysql_41': - $sql .= " {$column_type} "; - - // For hexadecimal values do not use single quotes - if (!is_null($column_data[1]) && substr($column_type, -4) !== 'text' && substr($column_type, -4) !== 'blob') - { - $sql .= (strpos($column_data[1], '0x') === 0) ? "DEFAULT {$column_data[1]} " : "DEFAULT '{$column_data[1]}' "; - } - $sql .= 'NOT NULL'; - - if (isset($column_data[2])) - { - if ($column_data[2] == 'auto_increment') - { - $sql .= ' auto_increment'; - } - else if ($this->sql_layer === 'mysql_41' && $column_data[2] == 'true_sort') - { - $sql .= ' COLLATE utf8_unicode_ci'; - } - } - - break; - - case 'oracle': - $sql .= " {$column_type} "; - $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}' " : ''; - - // In Oracle empty strings ('') are treated as NULL. - // Therefore in oracle we allow NULL's for all DEFAULT '' entries - // Oracle does not like setting NOT NULL on a column that is already NOT NULL (this happens only on number fields) - if (!preg_match('/number/i', $column_type)) - { - $sql .= ($column_data[1] === '') ? '' : 'NOT NULL'; - } - - $return_array['auto_increment'] = false; - if (isset($column_data[2]) && $column_data[2] == 'auto_increment') - { - $return_array['auto_increment'] = true; - } - - break; - - case 'postgres': - $return_array['column_type'] = $column_type; - - $sql .= " {$column_type} "; - - $return_array['auto_increment'] = false; - if (isset($column_data[2]) && $column_data[2] == 'auto_increment') - { - $default_val = "nextval('{$table_name}_seq')"; - $return_array['auto_increment'] = true; - } - else if (!is_null($column_data[1])) - { - $default_val = "'" . $column_data[1] . "'"; - $return_array['null'] = 'NOT NULL'; - $sql .= 'NOT NULL '; - } - - $return_array['default'] = $default_val; - - $sql .= "DEFAULT {$default_val}"; - - // Unsigned? Then add a CHECK contraint - if (in_array($orig_column_type, $this->unsigned_types)) - { - $return_array['constraint'] = "CHECK ({$column_name} >= 0)"; - $sql .= " CHECK ({$column_name} >= 0)"; - } - - break; - - case 'sqlite': - $return_array['primary_key_set'] = false; - if (isset($column_data[2]) && $column_data[2] == 'auto_increment') - { - $sql .= ' INTEGER PRIMARY KEY'; - $return_array['primary_key_set'] = true; - } - else - { - $sql .= ' ' . $column_type; - } - - $sql .= ' NOT NULL '; - $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}'" : ''; - - break; - } - - $return_array['column_type_sql'] = $sql; - - return $return_array; - } - - /** - * Add new column - */ - function sql_column_add($table_name, $column_name, $column_data, $inline = false) - { - $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); - $statements = array(); - - switch ($this->sql_layer) - { - case 'firebird': - // Does not support AFTER statement, only POSITION (and there you need the column position) - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD "' . strtoupper($column_name) . '" ' . $column_data['column_type_sql']; - break; - - case 'mssql': - case 'mssqlnative': - // Does not support AFTER, only through temporary table - $statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default']; - break; - - case 'mysql_40': - case 'mysql_41': - $after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : ''; - $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after; - break; - - case 'oracle': - // Does not support AFTER, only through temporary table - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql']; - break; - - case 'postgres': - // Does not support AFTER, only through temporary table - if (version_compare($this->db->sql_server_info(true), '8.0', '>=')) - { - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; - } - else - { - // old versions cannot add columns with default and null information - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint']; - - if (isset($column_data['null'])) - { - if ($column_data['null'] == 'NOT NULL') - { - $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL'; - } - } - - if (isset($column_data['default'])) - { - $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default']; - } - } - - break; - - case 'sqlite': - - if ($inline && $this->return_statements) - { - return $column_name . ' ' . $column_data['column_type_sql']; - } - - if (version_compare(sqlite_libversion(), '3.0') == -1) - { - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) - { - break; - } - - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - $statements[] = 'begin'; - - // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); - $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; - $statements[] = 'DROP TABLE ' . $table_name; - - preg_match('#\((.*)\)#s', $row['sql'], $matches); - - $new_table_cols = trim($matches[1]); - $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); - $column_list = array(); - - foreach ($old_table_cols as $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY') - { - continue; - } - $column_list[] = $entities[0]; - } - - $columns = implode(',', $column_list); - - $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols; - - // create a new table and fill it up. destroy the temp one - $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; - $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; - $statements[] = 'DROP TABLE ' . $table_name . '_temp'; - - $statements[] = 'commit'; - } - else - { - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' [' . $column_data['column_type_sql'] . ']'; - } - break; - } - - return $this->_sql_run_sql($statements); - } - - /** - * Drop column - */ - function sql_column_remove($table_name, $column_name, $inline = false) - { - $statements = array(); - - switch ($this->sql_layer) - { - case 'firebird': - $statements[] = 'ALTER TABLE ' . $table_name . ' DROP "' . strtoupper($column_name) . '"'; - break; - - case 'mssql': - case 'mssqlnative': - $sql = "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(25)) AS mssql_version"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - // Remove default constraints - if ($row['mssql_version'][0] == '8') // SQL Server 2000 - { - // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx - // Deprecated in SQL Server 2005 - $statements[] = "DECLARE @drop_default_name VARCHAR(100), @cmd VARCHAR(1000) - SET @drop_default_name = - (SELECT so.name FROM sysobjects so - JOIN sysconstraints sc ON so.id = sc.constid - WHERE object_name(so.parent_obj) = '{$table_name}' - AND so.xtype = 'D' - AND sc.colid = (SELECT colid FROM syscolumns - WHERE id = object_id('{$table_name}') - AND name = '{$column_name}')) - IF @drop_default_name <> '' - BEGIN - SET @cmd = 'ALTER TABLE [{$table_name}] DROP CONSTRAINT [' + @drop_default_name + ']' - EXEC(@cmd) - END"; - } - else - { - $sql = "SELECT dobj.name AS def_name - FROM sys.columns col - LEFT OUTER JOIN sys.objects dobj ON (dobj.object_id = col.default_object_id AND dobj.type = 'D') - WHERE col.object_id = object_id('{$table_name}') - AND col.name = '{$column_name}' - AND dobj.name IS NOT NULL"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - $statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $row['def_name'] . ']'; - } - } - - $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']'; - break; - - case 'mysql_40': - case 'mysql_41': - $statements[] = 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column_name . '`'; - break; - - case 'oracle': - $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name; - break; - - case 'postgres': - $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"'; - break; - - case 'sqlite': - - if ($inline && $this->return_statements) - { - return $column_name; - } - - if (version_compare(sqlite_libversion(), '3.0') == -1) - { - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) - { - break; - } - - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - $statements[] = 'begin'; - - // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); - $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; - $statements[] = 'DROP TABLE ' . $table_name; - - preg_match('#\((.*)\)#s', $row['sql'], $matches); - - $new_table_cols = trim($matches[1]); - $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); - $column_list = array(); - - foreach ($old_table_cols as $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name) - { - continue; - } - $column_list[] = $entities[0]; - } - - $columns = implode(',', $column_list); - - $new_table_cols = preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols); - - // create a new table and fill it up. destroy the temp one - $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; - $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; - $statements[] = 'DROP TABLE ' . $table_name . '_temp'; - - $statements[] = 'commit'; - } - else - { - $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name; - } - break; - } - - return $this->_sql_run_sql($statements); - } - - /** - * Drop Index - */ - function sql_index_drop($table_name, $index_name) - { - $statements = array(); - - switch ($this->sql_layer) - { - case 'mssql': - case 'mssqlnative': - $statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name; - break; - - case 'mysql_40': - case 'mysql_41': - $statements[] = 'DROP INDEX ' . $index_name . ' ON ' . $table_name; - break; - - case 'firebird': - case 'oracle': - case 'postgres': - case 'sqlite': - $statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name; - break; - } - - return $this->_sql_run_sql($statements); - } - - /** - * Drop Table - */ - function sql_table_drop($table_name) - { - $statements = array(); - - if (!$this->sql_table_exists($table_name)) - { - return $this->_sql_run_sql($statements); - } - - // the most basic operation, get rid of the table - $statements[] = 'DROP TABLE ' . $table_name; - - switch ($this->sql_layer) - { - case 'firebird': - $sql = 'SELECT RDB$GENERATOR_NAME as gen - FROM RDB$GENERATORS - WHERE RDB$SYSTEM_FLAG = 0 - AND RDB$GENERATOR_NAME = \'' . strtoupper($table_name) . "_GEN'"; - $result = $this->db->sql_query($sql); - - // does a generator exist? - if ($row = $this->db->sql_fetchrow($result)) - { - $statements[] = "DROP GENERATOR {$row['gen']};"; - } - $this->db->sql_freeresult($result); - break; - - case 'oracle': - $sql = 'SELECT A.REFERENCED_NAME - FROM USER_DEPENDENCIES A, USER_TRIGGERS B - WHERE A.REFERENCED_TYPE = \'SEQUENCE\' - AND A.NAME = B.TRIGGER_NAME - AND B.TABLE_NAME = \'' . strtoupper($table_name) . "'"; - $result = $this->db->sql_query($sql); - - // any sequences ref'd to this table's triggers? - while ($row = $this->db->sql_fetchrow($result)) - { - $statements[] = "DROP SEQUENCE {$row['referenced_name']}"; - } - $this->db->sql_freeresult($result); - break; - - case 'postgres': - // PGSQL does not "tightly" bind sequences and tables, we must guess... - $sql = "SELECT relname - FROM pg_class - WHERE relkind = 'S' - AND relname = '{$table_name}_seq'"; - $result = $this->db->sql_query($sql); - - // We don't even care about storing the results. We already know the answer if we get rows back. - if ($this->db->sql_fetchrow($result)) - { - $statements[] = "DROP SEQUENCE {$table_name}_seq;\n"; - } - $this->db->sql_freeresult($result); - break; - } - - return $this->_sql_run_sql($statements); - } - - /** - * Add primary key - */ - function sql_create_primary_key($table_name, $column, $inline = false) - { - $statements = array(); - - switch ($this->sql_layer) - { - case 'firebird': - case 'postgres': - case 'mysql_40': - case 'mysql_41': - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')'; - break; - - case 'mssql': - case 'mssqlnative': - $sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD "; - $sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY CLUSTERED ("; - $sql .= '[' . implode("],\n\t\t[", $column) . ']'; - $sql .= ')'; - - $statements[] = $sql; - break; - - case 'oracle': - $statements[] = 'ALTER TABLE ' . $table_name . 'add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')'; - break; - - case 'sqlite': - - if ($inline && $this->return_statements) - { - return $column; - } - - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) - { - break; - } - - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - $statements[] = 'begin'; - - // Create a backup table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); - $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; - $statements[] = 'DROP TABLE ' . $table_name; - - preg_match('#\((.*)\)#s', $row['sql'], $matches); - - $new_table_cols = trim($matches[1]); - $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); - $column_list = array(); - - foreach ($old_table_cols as $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] == 'PRIMARY') - { - continue; - } - $column_list[] = $entities[0]; - } - - $columns = implode(',', $column_list); - - // create a new table and fill it up. destroy the temp one - $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ', PRIMARY KEY (' . implode(', ', $column) . '));'; - $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; - $statements[] = 'DROP TABLE ' . $table_name . '_temp'; - - $statements[] = 'commit'; - break; - } - - return $this->_sql_run_sql($statements); - } - - /** - * Add unique index - */ - function sql_create_unique_index($table_name, $index_name, $column) - { - $statements = array(); - - $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) - if (strlen($table_name . $index_name) - strlen($table_prefix) > 24) - { - $max_length = strlen($table_prefix) + 24; - trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); - } - - switch ($this->sql_layer) - { - case 'firebird': - case 'postgres': - case 'oracle': - case 'sqlite': - $statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; - break; - - case 'mysql_40': - case 'mysql_41': - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD UNIQUE INDEX ' . $index_name . '(' . implode(', ', $column) . ')'; - break; - - case 'mssql': - case 'mssqlnative': - $statements[] = 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; - break; - } - - return $this->_sql_run_sql($statements); - } - - /** - * Add index - */ - function sql_create_index($table_name, $index_name, $column) - { - $statements = array(); - - $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config) - if (strlen($table_name . $index_name) - strlen($table_prefix) > 24) - { - $max_length = strlen($table_prefix) + 24; - trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR); - } - - // remove index length unless MySQL4 - if ('mysql_40' != $this->sql_layer) - { - $column = preg_replace('#:.*$#', '', $column); - } - - switch ($this->sql_layer) - { - case 'firebird': - case 'postgres': - case 'oracle': - case 'sqlite': - $statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; - break; - - case 'mysql_40': - // add index size to definition as required by MySQL4 - foreach ($column as $i => $col) - { - if (false !== strpos($col, ':')) - { - list($col, $index_size) = explode(':', $col); - $column[$i] = "$col($index_size)"; - } - } - // no break - case 'mysql_41': - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . '(' . implode(', ', $column) . ')'; - break; - - case 'mssql': - case 'mssqlnative': - $statements[] = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; - break; - } - - return $this->_sql_run_sql($statements); - } - - /** - * List all of the indices that belong to a table, - * does not count: - * * UNIQUE indices - * * PRIMARY keys - */ - function sql_list_index($table_name) - { - $index_array = array(); - - if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') - { - $sql = "EXEC sp_statistics '$table_name'"; - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - if ($row['TYPE'] == 3) - { - $index_array[] = $row['INDEX_NAME']; - } - } - $this->db->sql_freeresult($result); - } - else - { - switch ($this->sql_layer) - { - case 'firebird': - $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name - FROM RDB\$INDICES - WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "' - AND RDB\$UNIQUE_FLAG IS NULL - AND RDB\$FOREIGN_KEY IS NULL"; - $col = 'index_name'; - break; - - case 'postgres': - $sql = "SELECT ic.relname as index_name - FROM pg_class bc, pg_class ic, pg_index i - WHERE (bc.oid = i.indrelid) - AND (ic.oid = i.indexrelid) - AND (bc.relname = '" . $table_name . "') - AND (i.indisunique != 't') - AND (i.indisprimary != 't')"; - $col = 'index_name'; - break; - - case 'mysql_40': - case 'mysql_41': - $sql = 'SHOW KEYS - FROM ' . $table_name; - $col = 'Key_name'; - break; - - case 'oracle': - $sql = "SELECT index_name - FROM user_indexes - WHERE table_name = '" . strtoupper($table_name) . "' - AND generated = 'N' - AND uniqueness = 'NONUNIQUE'"; - $col = 'index_name'; - break; - - case 'sqlite': - $sql = "PRAGMA index_info('" . $table_name . "');"; - $col = 'name'; - break; - } - - $result = $this->db->sql_query($sql); - while ($row = $this->db->sql_fetchrow($result)) - { - if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique']) - { - continue; - } - - switch ($this->sql_layer) - { - case 'firebird': - case 'oracle': - case 'postgres': - case 'sqlite': - $row[$col] = substr($row[$col], strlen($table_name) + 1); - break; - } - - $index_array[] = $row[$col]; - } - $this->db->sql_freeresult($result); - } - - return array_map('strtolower', $index_array); - } - - /** - * Change column type (not name!) - */ - function sql_column_change($table_name, $column_name, $column_data, $inline = false) - { - $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); - $statements = array(); - - switch ($this->sql_layer) - { - case 'firebird': - // Change type... - if (!empty($column_data['column_type_sql_default'])) - { - $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type']; - $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" SET DEFAULT ' . ' ' . $column_data['column_type_sql_default']; - } - else - { - // TODO: try to change pkey without removing trigger, generator or constraints. ATM this query may fail. - $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type']; - } - break; - - case 'mssql': - case 'mssqlnative': - $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql']; - - if (!empty($column_data['default'])) - { - $sql = "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(25)) AS mssql_version"; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - // Using TRANSACT-SQL for this statement because we do not want to have colliding data if statements are executed at a later stage - if ($row['mssql_version'][0] == '8') // SQL Server 2000 - { - $statements[] = "DECLARE @drop_default_name VARCHAR(100), @cmd VARCHAR(1000) - SET @drop_default_name = - (SELECT so.name FROM sysobjects so - JOIN sysconstraints sc ON so.id = sc.constid - WHERE object_name(so.parent_obj) = '{$table_name}' - AND so.xtype = 'D' - AND sc.colid = (SELECT colid FROM syscolumns - WHERE id = object_id('{$table_name}') - AND name = '{$column_name}')) - IF @drop_default_name <> '' - BEGIN - SET @cmd = 'ALTER TABLE [{$table_name}] DROP CONSTRAINT [' + @drop_default_name + ']' - EXEC(@cmd) - END - SET @cmd = 'ALTER TABLE [{$table_name}] ADD CONSTRAINT [DF_{$table_name}_{$column_name}_1] {$column_data['default']} FOR [{$column_name}]' - EXEC(@cmd)"; - } - else - { - $statements[] = "DECLARE @drop_default_name VARCHAR(100), @cmd VARCHAR(1000) - SET @drop_default_name = - (SELECT dobj.name FROM sys.columns col - LEFT OUTER JOIN sys.objects dobj ON (dobj.object_id = col.default_object_id AND dobj.type = 'D') - WHERE col.object_id = object_id('{$table_name}') - AND col.name = '{$column_name}' - AND dobj.name IS NOT NULL) - IF @drop_default_name <> '' - BEGIN - SET @cmd = 'ALTER TABLE [{$table_name}] DROP CONSTRAINT [' + @drop_default_name + ']' - EXEC(@cmd) - END - SET @cmd = 'ALTER TABLE [{$table_name}] ADD CONSTRAINT [DF_{$table_name}_{$column_name}_1] {$column_data['default']} FOR [{$column_name}]' - EXEC(@cmd)"; - } - } - break; - - case 'mysql_40': - case 'mysql_41': - $statements[] = 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_name . '` `' . $column_name . '` ' . $column_data['column_type_sql']; - break; - - case 'oracle': - $statements[] = 'ALTER TABLE ' . $table_name . ' MODIFY ' . $column_name . ' ' . $column_data['column_type_sql']; - break; - - case 'postgres': - $sql = 'ALTER TABLE ' . $table_name . ' '; - - $sql_array = array(); - $sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type']; - - if (isset($column_data['null'])) - { - if ($column_data['null'] == 'NOT NULL') - { - $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL'; - } - else if ($column_data['null'] == 'NULL') - { - $sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL'; - } - } - - if (isset($column_data['default'])) - { - $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default']; - } - - // we don't want to double up on constraints if we change different number data types - if (isset($column_data['constraint'])) - { - $constraint_sql = "SELECT consrc as constraint_data - FROM pg_constraint, pg_class bc - WHERE conrelid = bc.oid - AND bc.relname = '{$table_name}' - AND NOT EXISTS ( - SELECT * - FROM pg_constraint as c, pg_inherits as i - WHERE i.inhrelid = pg_constraint.conrelid - AND c.conname = pg_constraint.conname - AND c.consrc = pg_constraint.consrc - AND c.conrelid = i.inhparent - )"; - - $constraint_exists = false; - - $result = $this->db->sql_query($constraint_sql); - while ($row = $this->db->sql_fetchrow($result)) - { - if (trim($row['constraint_data']) == trim($column_data['constraint'])) - { - $constraint_exists = true; - break; - } - } - $this->db->sql_freeresult($result); - - if (!$constraint_exists) - { - $sql_array[] = 'ADD ' . $column_data['constraint']; - } - } - - $sql .= implode(', ', $sql_array); - - $statements[] = $sql; - break; - - case 'sqlite': - - if ($inline && $this->return_statements) - { - return $column_name . ' ' . $column_data['column_type_sql']; - } - - $sql = "SELECT sql - FROM sqlite_master - WHERE type = 'table' - AND name = '{$table_name}' - ORDER BY type DESC, name;"; - $result = $this->db->sql_query($sql); - - if (!$result) - { - break; - } - - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - $statements[] = 'begin'; - - // Create a temp table and populate it, destroy the existing one - $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); - $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; - $statements[] = 'DROP TABLE ' . $table_name; - - preg_match('#\((.*)\)#s', $row['sql'], $matches); - - $new_table_cols = trim($matches[1]); - $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols); - $column_list = array(); - - foreach ($old_table_cols as $key => $declaration) - { - $entities = preg_split('#\s+#', trim($declaration)); - $column_list[] = $entities[0]; - if ($entities[0] == $column_name) - { - $old_table_cols[$key] = $column_name . ' ' . $column_data['column_type_sql']; - } - } - - $columns = implode(',', $column_list); - - // create a new table and fill it up. destroy the temp one - $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $old_table_cols) . ');'; - $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; - $statements[] = 'DROP TABLE ' . $table_name . '_temp'; - - $statements[] = 'commit'; - - break; - } - - return $this->_sql_run_sql($statements); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php deleted file mode 100644 index 30d2870938..0000000000 --- a/phpBB/includes/db/dbal.php +++ /dev/null @@ -1,1000 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Database Abstraction Layer -* @package dbal -*/ -class dbal -{ - var $db_connect_id; - var $query_result; - var $return_on_error = false; - var $transaction = false; - var $sql_time = 0; - var $num_queries = array(); - var $open_queries = array(); - - var $curtime = 0; - var $query_hold = ''; - var $html_hold = ''; - var $sql_report = ''; - - var $persistency = false; - var $user = ''; - var $server = ''; - var $dbname = ''; - - // Set to true if error triggered - var $sql_error_triggered = false; - - // Holding the last sql query on sql error - var $sql_error_sql = ''; - // Holding the error information - only populated if sql_error_triggered is set - var $sql_error_returned = array(); - - // Holding transaction count - var $transactions = 0; - - // Supports multi inserts? - var $multi_insert = false; - - /** - * Current sql layer - */ - var $sql_layer = ''; - - /** - * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions - */ - var $any_char; - var $one_char; - - /** - * Exact version of the DBAL, directly queried - */ - var $sql_server_version = false; - - /** - * Constructor - */ - function dbal() - { - $this->num_queries = array( - 'cached' => 0, - 'normal' => 0, - 'total' => 0, - ); - - // Fill default sql layer based on the class being called. - // This can be changed by the specified layer itself later if needed. - $this->sql_layer = substr(get_class($this), 5); - - // Do not change this please! This variable is used to easy the use of it - and is hardcoded. - $this->any_char = chr(0) . '%'; - $this->one_char = chr(0) . '_'; - } - - /** - * return on error or display error message - */ - function sql_return_on_error($fail = false) - { - $this->sql_error_triggered = false; - $this->sql_error_sql = ''; - - $this->return_on_error = $fail; - } - - /** - * Return number of sql queries and cached sql queries used - */ - function sql_num_queries($cached = false) - { - return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal']; - } - - /** - * Add to query count - */ - function sql_add_num_queries($cached = false) - { - $this->num_queries['cached'] += ($cached !== false) ? 1 : 0; - $this->num_queries['normal'] += ($cached !== false) ? 0 : 1; - $this->num_queries['total'] += 1; - } - - /** - * DBAL garbage collection, close sql connection - */ - function sql_close() - { - if (!$this->db_connect_id) - { - return false; - } - - if ($this->transaction) - { - do - { - $this->sql_transaction('commit'); - } - while ($this->transaction); - } - - foreach ($this->open_queries as $query_id) - { - $this->sql_freeresult($query_id); - } - - // Connection closed correctly. Set db_connect_id to false to prevent errors - if ($result = $this->_sql_close()) - { - $this->db_connect_id = false; - } - - return $result; - } - - /** - * Build LIMIT query - * Doing some validation here. - */ - function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - if (empty($query)) - { - return false; - } - - // Never use a negative total or offset - $total = ($total < 0) ? 0 : $total; - $offset = ($offset < 0) ? 0 : $offset; - - return $this->_sql_query_limit($query, $total, $offset, $cache_ttl); - } - - /** - * Fetch all rows - */ - function sql_fetchrowset($query_id = false) - { - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id !== false) - { - $result = array(); - while ($row = $this->sql_fetchrow($query_id)) - { - $result[] = $row; - } - - return $result; - } - - return false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - if ($query_id === false) - { - return false; - } - - $this->sql_freeresult($query_id); - $query_id = $this->sql_query($this->last_query_text); - - if ($query_id === false) - { - return false; - } - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if ($query_id !== false) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return (isset($row[$field])) ? $row[$field] : false; - } - - return false; - } - - /** - * Correctly adjust LIKE expression for special characters - * Some DBMS are handling them in a different way - * - * @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char - * @return string LIKE expression including the keyword! - */ - function sql_like_expression($expression) - { - $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); - $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); - - return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); - } - - /** - * Returns whether results of a query need to be buffered to run a transaction while iterating over them. - * - * @return bool Whether buffering is required. - */ - function sql_buffer_nested_transactions() - { - return false; - } - - /** - * SQL Transaction - * @access private - */ - function sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - // If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit) - if ($this->transaction) - { - $this->transactions++; - return true; - } - - $result = $this->_sql_transaction('begin'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = true; - break; - - case 'commit': - // If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions - if ($this->transaction && $this->transactions) - { - $this->transactions--; - return true; - } - - // Check if there is a transaction (no transaction can happen if there was an error, with a combined rollback and error returning enabled) - // This implies we have transaction always set for autocommit db's - if (!$this->transaction) - { - return false; - } - - $result = $this->_sql_transaction('commit'); - - if (!$result) - { - $this->sql_error(); - } - - $this->transaction = false; - $this->transactions = 0; - break; - - case 'rollback': - $result = $this->_sql_transaction('rollback'); - $this->transaction = false; - $this->transactions = 0; - break; - - default: - $result = $this->_sql_transaction($status); - break; - } - - return $result; - } - - /** - * Build sql statement from array for insert/update/select statements - * - * Idea for this from Ikonboard - * Possible query values: INSERT, INSERT_SELECT, UPDATE, SELECT - * - */ - function sql_build_array($query, $assoc_ary = false) - { - if (!is_array($assoc_ary)) - { - return false; - } - - $fields = $values = array(); - - if ($query == 'INSERT' || $query == 'INSERT_SELECT') - { - foreach ($assoc_ary as $key => $var) - { - $fields[] = $key; - - if (is_array($var) && is_string($var[0])) - { - // This is used for INSERT_SELECT(s) - $values[] = $var[0]; - } - else - { - $values[] = $this->_sql_validate_value($var); - } - } - - $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' '; - } - else if ($query == 'MULTI_INSERT') - { - trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR); - } - else if ($query == 'UPDATE' || $query == 'SELECT') - { - $values = array(); - foreach ($assoc_ary as $key => $var) - { - $values[] = "$key = " . $this->_sql_validate_value($var); - } - $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values); - } - - return $query; - } - - /** - * Build IN or NOT IN sql comparison string, uses <> or = on single element - * arrays to improve comparison speed - * - * @access public - * @param string $field name of the sql column that shall be compared - * @param array $array array of values that are allowed (IN) or not allowed (NOT IN) - * @param bool $negate true for NOT IN (), false for IN () (default) - * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false. - */ - function sql_in_set($field, $array, $negate = false, $allow_empty_set = false) - { - if (!sizeof($array)) - { - if (!$allow_empty_set) - { - // Print the backtrace to help identifying the location of the problematic code - $this->sql_error('No values specified for SQL IN comparison'); - } - else - { - // NOT IN () actually means everything so use a tautology - if ($negate) - { - return '1=1'; - } - // IN () actually means nothing so use a contradiction - else - { - return '1=0'; - } - } - } - - if (!is_array($array)) - { - $array = array($array); - } - - if (sizeof($array) == 1) - { - @reset($array); - $var = current($array); - - return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); - } - else - { - return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; - } - } - - /** - * Run binary AND operator on DB column. - * Results in sql statement: "{$column_name} & (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the AND operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - */ - function sql_bit_and($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_and')) - { - return $this->_sql_bit_and($column_name, $bit, $compare); - } - - return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * Run binary OR operator on DB column. - * Results in sql statement: "{$column_name} | (1 << {$bit}) {$compare}" - * - * @param string $column_name The column name to use - * @param int $bit The value to use for the OR operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 - * @param string $compare Any custom SQL code after the check (for example "= 0") - */ - function sql_bit_or($column_name, $bit, $compare = '') - { - if (method_exists($this, '_sql_bit_or')) - { - return $this->_sql_bit_or($column_name, $bit, $compare); - } - - return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); - } - - /** - * Run LOWER() on DB column of type text (i.e. neither varchar nor char). - * - * @param string $column_name The column name to use - * - * @return string A SQL statement like "LOWER($column_name)" - */ - function sql_lower_text($column_name) - { - return "LOWER($column_name)"; - } - - /** - * Run more than one insert statement. - * - * @param string $table table name to run the statements on - * @param array &$sql_ary multi-dimensional array holding the statement data. - * - * @return bool false if no statements were executed. - * @access public - */ - function sql_multi_insert($table, &$sql_ary) - { - if (!sizeof($sql_ary)) - { - return false; - } - - if ($this->multi_insert) - { - $ary = array(); - foreach ($sql_ary as $id => $_sql_ary) - { - // If by accident the sql array is only one-dimensional we build a normal insert statement - if (!is_array($_sql_ary)) - { - return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); - } - - $values = array(); - foreach ($_sql_ary as $key => $var) - { - $values[] = $this->_sql_validate_value($var); - } - $ary[] = '(' . implode(', ', $values) . ')'; - } - - return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); - } - else - { - foreach ($sql_ary as $ary) - { - if (!is_array($ary)) - { - return false; - } - - $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); - - if (!$result) - { - return false; - } - } - } - - return true; - } - - /** - * Function for validating values - * @access private - */ - function _sql_validate_value($var) - { - if (is_null($var)) - { - return 'NULL'; - } - else if (is_string($var)) - { - return "'" . $this->sql_escape($var) . "'"; - } - else - { - return (is_bool($var)) ? intval($var) : $var; - } - } - - /** - * Build sql statement from array for select and select distinct statements - * - * Possible query values: SELECT, SELECT_DISTINCT - */ - function sql_build_query($query, $array) - { - $sql = ''; - switch ($query) - { - case 'SELECT': - case 'SELECT_DISTINCT'; - - $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM '; - - // Build table array. We also build an alias array for later checks. - $table_array = $aliases = array(); - $used_multi_alias = false; - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - $used_multi_alias = true; - - foreach ($alias as $multi_alias) - { - $table_array[] = $table_name . ' ' . $multi_alias; - $aliases[] = $multi_alias; - } - } - else - { - $table_array[] = $table_name . ' ' . $alias; - $aliases[] = $alias; - } - } - - // We run the following code to determine if we need to re-order the table array. ;) - // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison. - // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is. - if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false) - { - // Take first LEFT JOIN - $join = current($array['LEFT_JOIN']); - - // Determine the table used there (even if there are more than one used, we only want to have one - preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches); - - // If there is a first join match, we need to make sure the table order is correct - if (!empty($matches[1])) - { - $first_join_match = trim($matches[1]); - $table_array = $last = array(); - - foreach ($array['FROM'] as $table_name => $alias) - { - if (is_array($alias)) - { - foreach ($alias as $multi_alias) - { - ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias; - } - } - else - { - ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias; - } - } - - $table_array = array_merge($table_array, $last); - } - } - - $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array)); - - if (!empty($array['LEFT_JOIN'])) - { - foreach ($array['LEFT_JOIN'] as $join) - { - $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')'; - } - } - - if (!empty($array['WHERE'])) - { - $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']); - } - - if (!empty($array['GROUP_BY'])) - { - $sql .= ' GROUP BY ' . $array['GROUP_BY']; - } - - if (!empty($array['ORDER_BY'])) - { - $sql .= ' ORDER BY ' . $array['ORDER_BY']; - } - - break; - } - - return $sql; - } - - /** - * display sql error page - */ - function sql_error($sql = '') - { - global $auth, $user, $config; - - // Set var to retrieve errored status - $this->sql_error_triggered = true; - $this->sql_error_sql = $sql; - - $this->sql_error_returned = $this->_sql_error(); - - if (!$this->return_on_error) - { - $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]<br /><br />' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']'; - - // Show complete SQL error and path to administrators only - // Additionally show complete error on installation or if extended debug mode is enabled - // The DEBUG_EXTRA constant is for development only! - if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG_EXTRA')) - { - $message .= ($sql) ? '<br /><br />SQL<br /><br />' . htmlspecialchars($sql) : ''; - } - else - { - // If error occurs in initiating the session we need to use a pre-defined language string - // This could happen if the connection could not be established for example (then we are not able to grab the default language) - if (!isset($user->lang['SQL_ERROR_OCCURRED'])) - { - $message .= '<br /><br />An sql error occurred while fetching this page. Please contact an administrator if this problem persists.'; - } - else - { - if (!empty($config['board_contact'])) - { - $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'); - } - else - { - $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', ''); - } - } - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - if (strlen($message) > 1024) - { - // We need to define $msg_long_text here to circumvent text stripping. - global $msg_long_text; - $msg_long_text = $message; - - trigger_error(false, E_USER_ERROR); - } - - trigger_error($message, E_USER_ERROR); - } - - if ($this->transaction) - { - $this->sql_transaction('rollback'); - } - - return $this->sql_error_returned; - } - - /** - * Explain queries - */ - function sql_report($mode, $query = '') - { - global $cache, $starttime, $phpbb_root_path, $user; - - if (empty($_REQUEST['explain'])) - { - return false; - } - - if (!$query && $this->query_hold != '') - { - $query = $this->query_hold; - } - - switch ($mode) - { - case 'display': - if (!empty($cache)) - { - $cache->unload(); - } - $this->sql_close(); - - $mtime = explode(' ', microtime()); - $totaltime = $mtime[0] + $mtime[1] - $starttime; - - echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr"> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> - <meta http-equiv="Content-Style-Type" content="text/css" /> - <meta http-equiv="imagetoolbar" content="no" /> - <title>SQL Report</title> - <link href="' . $phpbb_root_path . 'adm/style/admin.css" rel="stylesheet" type="text/css" media="screen" /> - </head> - <body id="errorpage"> - <div id="wrap"> - <div id="page-header"> - <a href="' . build_url('explain') . '">Return to previous page</a> - </div> - <div id="page-body"> - <div id="acp"> - <div class="panel"> - <span class="corners-top"><span></span></span> - <div id="content"> - <h1>SQL Report</h1> - <br /> - <p><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></p> - - <p>Time spent on ' . $this->sql_layer . ' queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></p> - - <br /><br /> - ' . $this->sql_report . ' - </div> - <span class="corners-bottom"><span></span></span> - </div> - </div> - </div> - <div id="page-footer"> - Powered by <a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Group - </div> - </div> - </body> - </html>'; - - exit_handler(); - - break; - - case 'stop': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $this->sql_report .= ' - - <table cellspacing="1"> - <thead> - <tr> - <th>Query #' . $this->num_queries['total'] . '</th> - </tr> - </thead> - <tbody> - <tr> - <td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td> - </tr> - </tbody> - </table> - - ' . $this->html_hold . ' - - <p style="text-align: center;"> - '; - - if ($this->query_result) - { - if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)) - { - $this->sql_report .= 'Affected rows: <b>' . $this->sql_affectedrows($this->query_result) . '</b> | '; - } - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $this->curtime) . 's</b>'; - } - else - { - $error = $this->sql_error(); - $this->sql_report .= '<b style="color: red">FAILED</b> - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); - } - - $this->sql_report .= '</p><br /><br />'; - - $this->sql_time += $endtime - $this->curtime; - break; - - case 'start': - $this->query_hold = $query; - $this->html_hold = ''; - - $this->_sql_report($mode, $query); - - $this->curtime = explode(' ', microtime()); - $this->curtime = $this->curtime[0] + $this->curtime[1]; - - break; - - case 'add_select_row': - - $html_table = func_get_arg(2); - $row = func_get_arg(3); - - if (!$html_table && sizeof($row)) - { - $html_table = true; - $this->html_hold .= '<table cellspacing="1"><tr>'; - - foreach (array_keys($row) as $val) - { - $this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '</th>'; - } - $this->html_hold .= '</tr>'; - } - $this->html_hold .= '<tr>'; - - $class = 'row1'; - foreach (array_values($row) as $val) - { - $class = ($class == 'row1') ? 'row2' : 'row1'; - $this->html_hold .= '<td class="' . $class . '">' . (($val) ? $val : ' ') . '</td>'; - } - $this->html_hold .= '</tr>'; - - return $html_table; - - break; - - case 'fromcache': - - $this->_sql_report($mode, $query); - - break; - - case 'record_fromcache': - - $endtime = func_get_arg(2); - $splittime = func_get_arg(3); - - $time_cache = $endtime - $this->curtime; - $time_db = $splittime - $endtime; - $color = ($time_db > $time_cache) ? 'green' : 'red'; - - $this->sql_report .= '<table cellspacing="1"><thead><tr><th>Query results obtained from the cache</th></tr></thead><tbody><tr>'; - $this->sql_report .= '<td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></tbody></table>'; - $this->sql_report .= '<p style="text-align: center;">'; - $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p><br /><br />'; - - // Pad the start time to not interfere with page timing - $starttime += $time_db; - - break; - - default: - - $this->_sql_report($mode, $query); - - break; - } - - return true; - } - - /** - * Gets the estimated number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Number of rows in $table_name. - * Prefixed with ~ if estimated (otherwise exact). - * - * @access public - */ - function get_estimated_row_count($table_name) - { - return $this->get_row_count($table_name); - } - - /** - * Gets the exact number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Exact number of rows in $table_name. - * - * @access public - */ - function get_row_count($table_name) - { - $sql = 'SELECT COUNT(*) AS rows_total - FROM ' . $this->sql_escape($table_name); - $result = $this->sql_query($sql); - $rows_total = $this->sql_fetchfield('rows_total'); - $this->sql_freeresult($result); - - return $rows_total; - } -} - -/** -* This variable holds the class name to use later -*/ -$sql_db = (!empty($dbms)) ? 'dbal_' . basename($dbms) : 'dbal'; - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php deleted file mode 100644 index 7072c58ac0..0000000000 --- a/phpBB/includes/db/firebird.php +++ /dev/null @@ -1,526 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -/** -* Firebird/Interbase Database Abstraction Layer -* Minimum Requirement is Firebird 2.1 -* @package dbal -*/ -class dbal_firebird extends dbal -{ - var $last_query_text = ''; - var $service_handle = false; - var $affected_rows = 0; - var $connect_error = ''; - - /** - * Connect to server - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $this->persistency = $persistency; - $this->user = $sqluser; - $this->server = $sqlserver . (($port) ? ':' . $port : ''); - $this->dbname = str_replace('\\', '/', $database); - - // There are three possibilities to connect to an interbase db - if (!$this->server) - { - $use_database = $this->dbname; - } - else if (strpos($this->server, '//') === 0) - { - $use_database = $this->server . $this->dbname; - } - else - { - $use_database = $this->server . ':' . $this->dbname; - } - - if ($this->persistency) - { - if (!function_exists('ibase_pconnect')) - { - $this->connect_error = 'ibase_pconnect function does not exist, is interbase extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ibase_pconnect($use_database, $this->user, $sqlpassword, false, false, 3); - } - else - { - if (!function_exists('ibase_connect')) - { - $this->connect_error = 'ibase_connect function does not exist, is interbase extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ibase_connect($use_database, $this->user, $sqlpassword, false, false, 3); - } - - // Do not call ibase_service_attach if connection failed, - // otherwise error message from ibase_(p)connect call will be clobbered. - if ($this->db_connect_id && function_exists('ibase_service_attach') && $this->server) - { - $this->service_handle = @ibase_service_attach($this->server, $this->user, $sqlpassword); - } - else - { - $this->service_handle = false; - } - - return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); - } - - /** - * Version information about used database - * @param bool $raw if true, only return the fetched sql_server_version - * @param bool $use_cache forced to false for Interbase - * @return string sql server version - */ - function sql_server_info($raw = false, $use_cache = true) - { - /** - * force $use_cache false. I didn't research why the caching code there is no caching code - * but I assume its because the IB extension provides a direct method to access it - * without a query. - */ - - $use_cache = false; - - if ($this->service_handle !== false && function_exists('ibase_server_info')) - { - return @ibase_server_info($this->service_handle, IBASE_SVC_SERVER_VERSION); - } - - return ($raw) ? '2.1' : 'Firebird/Interbase'; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return true; - break; - - case 'commit': - return @ibase_commit(); - break; - - case 'rollback': - return @ibase_rollback(); - break; - } - - return true; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - $array = array(); - // We overcome Firebird's 32767 char limit by binding vars - if (strlen($query) > 32767) - { - if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/s', $query, $regs)) - { - if (strlen($regs[3]) > 32767) - { - preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER); - - $inserts = $vals[0]; - unset($vals); - - foreach ($inserts as $key => $value) - { - if (!empty($value) && $value[0] === "'" && strlen($value) > 32769) // check to see if this thing is greater than the max + 'x2 - { - $inserts[$key] = '?'; - $array[] = str_replace("''", "'", substr($value, 1, -1)); - } - } - - $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')'; - } - } - else if (preg_match('/^(UPDATE ([\\w_]++)\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|\\d+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data)) - { - if (strlen($data[3]) > 32767) - { - $update = $data[1]; - $where = $data[4]; - preg_match_all('/(\\w++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[3], $temp, PREG_SET_ORDER); - unset($data); - - $cols = array(); - foreach ($temp as $value) - { - if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 32769) // check to see if this thing is greater than the max + 'x2 - { - $array[] = str_replace("''", "'", substr($value[2], 1, -1)); - $cols[] = $value[1] . '=?'; - } - else - { - $cols[] = $value[1] . '=' . $value[2]; - } - } - - $query = $update . implode(', ', $cols) . ' ' . $where; - unset($cols); - } - } - } - - if (!function_exists('ibase_affected_rows') && (preg_match('/^UPDATE ([\w_]++)\s+SET [\w_]++\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\s*[\w_]++\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+\s+(WHERE.*)?$/s', $query, $regs) || preg_match('/^DELETE FROM ([\w_]++)\s*(WHERE\s*.*)?$/s', $query, $regs))) - { - $affected_sql = 'SELECT COUNT(*) as num_rows_affected FROM ' . $regs[1]; - if (!empty($regs[2])) - { - $affected_sql .= ' ' . $regs[2]; - } - - if (!($temp_q_id = @ibase_query($this->db_connect_id, $affected_sql))) - { - return false; - } - - $temp_result = @ibase_fetch_assoc($temp_q_id); - @ibase_free_result($temp_q_id); - - $this->affected_rows = ($temp_result) ? $temp_result['NUM_ROWS_AFFECTED'] : false; - } - - if (sizeof($array)) - { - $p_query = @ibase_prepare($this->db_connect_id, $query); - array_unshift($array, $p_query); - $this->query_result = call_user_func_array('ibase_execute', $array); - unset($array); - - if ($this->query_result === false) - { - $this->sql_error($query); - } - } - else if (($this->query_result = @ibase_query($this->db_connect_id, $query)) === false) - { - $this->sql_error($query); - } - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if (!$this->transaction) - { - if (function_exists('ibase_commit_ret')) - { - @ibase_commit_ret(); - } - else - { - // way cooler than ibase_commit_ret :D - @ibase_query('COMMIT RETAIN;'); - } - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0 && $this->query_result) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - $query = 'SELECT FIRST ' . $total . ((!empty($offset)) ? ' SKIP ' . $offset : '') . substr($query, 6); - - return $this->sql_query($query, $cache_ttl); - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - // PHP 5+ function - if (function_exists('ibase_affected_rows')) - { - return ($this->db_connect_id) ? @ibase_affected_rows($this->db_connect_id) : false; - } - else - { - return $this->affected_rows; - } - } - - /** - * Fetch current row - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - if ($query_id === false) - { - return false; - } - - $row = array(); - $cur_row = @ibase_fetch_object($query_id, IBASE_TEXT); - - if (!$cur_row) - { - return false; - } - - foreach (get_object_vars($cur_row) as $key => $value) - { - $row[strtolower($key)] = (is_string($value)) ? trim(str_replace(array("\\0", "\\n"), array("\0", "\n"), $value)) : $value; - } - - return (sizeof($row)) ? $row : false; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - $query_id = $this->query_result; - - if ($query_id !== false && $this->last_query_text != '') - { - if ($this->query_result && preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#i', $this->last_query_text, $tablename)) - { - $sql = 'SELECT GEN_ID(' . $tablename[1] . '_gen, 0) AS new_id FROM RDB$DATABASE'; - - if (!($temp_q_id = @ibase_query($this->db_connect_id, $sql))) - { - return false; - } - - $temp_result = @ibase_fetch_assoc($temp_q_id); - @ibase_free_result($temp_q_id); - - return ($temp_result) ? $temp_result['NEW_ID'] : false; - } - } - - return false; - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - if (isset($this->open_queries[(int) $query_id])) - { - unset($this->open_queries[(int) $query_id]); - return @ibase_free_result($query_id); - } - - return false; - } - - /** - * Escape string used in sql query - */ - function sql_escape($msg) - { - return str_replace(array("'", "\0"), array("''", ''), $msg); - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression . " ESCAPE '\\'"; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - return $data; - } - - function _sql_bit_and($column_name, $bit, $compare = '') - { - return 'BIN_AND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); - } - - function _sql_bit_or($column_name, $bit, $compare = '') - { - return 'BIN_OR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - // Need special handling here because ibase_errmsg returns - // connection errors, however if the interbase extension - // is not installed then ibase_errmsg does not exist and - // we cannot call it. - if (function_exists('ibase_errmsg')) - { - $msg = @ibase_errmsg(); - if (!$msg) - { - $msg = $this->connect_error; - } - } - else - { - $msg = $this->connect_error; - } - return array( - 'message' => $msg, - 'code' => (@function_exists('ibase_errcode') ? @ibase_errcode() : '') - ); - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - if ($this->service_handle !== false) - { - @ibase_service_detach($this->service_handle); - } - - return @ibase_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @ibase_query($this->db_connect_id, $query); - while ($void = @ibase_fetch_object($result, IBASE_TEXT)) - { - // Take the time spent on parsing rows into account - } - @ibase_free_result($result); - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/index.htm b/phpBB/includes/db/index.htm deleted file mode 100644 index ee1f723a7d..0000000000 --- a/phpBB/includes/db/index.htm +++ /dev/null @@ -1,10 +0,0 @@ -<html> -<head> -<title></title> -<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> -</head> - -<body bgcolor="#FFFFFF" text="#000000"> - -</body> -</html> diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php deleted file mode 100644 index 2dd95c2508..0000000000 --- a/phpBB/includes/db/mssql.php +++ /dev/null @@ -1,476 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -/** -* MSSQL Database Abstraction Layer -* Minimum Requirement is MSSQL 2000+ -* @package dbal -*/ -class dbal_mssql extends dbal -{ - var $connect_error = ''; - - /** - * Connect to server - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - if (!function_exists('mssql_connect')) - { - $this->connect_error = 'mssql_connect function does not exist, is mssql extension installed?'; - return $this->sql_error(''); - } - - $this->persistency = $persistency; - $this->user = $sqluser; - $this->dbname = $database; - - $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; - $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); - - @ini_set('mssql.charset', 'UTF-8'); - @ini_set('mssql.textlimit', 2147483647); - @ini_set('mssql.textsize', 2147483647); - - if (version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.1', '>='))) - { - $this->db_connect_id = ($this->persistency) ? @mssql_pconnect($this->server, $this->user, $sqlpassword, $new_link) : @mssql_connect($this->server, $this->user, $sqlpassword, $new_link); - } - else - { - $this->db_connect_id = ($this->persistency) ? @mssql_pconnect($this->server, $this->user, $sqlpassword) : @mssql_connect($this->server, $this->user, $sqlpassword); - } - - if ($this->db_connect_id && $this->dbname != '') - { - if (!@mssql_select_db($this->dbname, $this->db_connect_id)) - { - @mssql_close($this->db_connect_id); - return false; - } - } - - return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); - } - - /** - * Version information about used database - * @param bool $raw if true, only return the fetched sql_server_version - * @param bool $use_cache If true, it is safe to retrieve the value from the cache - * @return string sql server version - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false) - { - $result_id = @mssql_query("SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')", $this->db_connect_id); - - $row = false; - if ($result_id) - { - $row = @mssql_fetch_assoc($result_id); - @mssql_free_result($result_id); - } - - $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0; - - if (!empty($cache) && $use_cache) - { - $cache->put('mssql_version', $this->sql_server_version); - } - } - - if ($raw) - { - return $this->sql_server_version; - } - - return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL'; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @mssql_query('BEGIN TRANSACTION', $this->db_connect_id); - break; - - case 'commit': - return @mssql_query('COMMIT TRANSACTION', $this->db_connect_id); - break; - - case 'rollback': - return @mssql_query('ROLLBACK TRANSACTION', $this->db_connect_id); - break; - } - - return true; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - if (($this->query_result = @mssql_query($query, $this->db_connect_id)) === false) - { - $this->sql_error($query); - } - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0 && $this->query_result) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows) - if ($total) - { - // We need to grab the total number of rows + the offset number of rows to get the correct result - if (strpos($query, 'SELECT DISTINCT') === 0) - { - $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15); - } - else - { - $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6); - } - } - - $result = $this->sql_query($query, $cache_ttl); - - // Seek by $offset rows - if ($offset) - { - $this->sql_rowseek($offset, $result); - } - - return $result; - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @mssql_rows_affected($this->db_connect_id) : false; - } - - /** - * Fetch current row - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - if ($query_id === false) - { - return false; - } - - $row = @mssql_fetch_assoc($query_id); - - // I hope i am able to remove this later... hopefully only a PHP or MSSQL bug - if ($row) - { - foreach ($row as $key => $value) - { - $row[$key] = ($value === ' ' || $value === NULL) ? '' : $value; - } - } - - return $row; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - return ($query_id !== false) ? @mssql_data_seek($query_id, $rownum) : false; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - $result_id = @mssql_query('SELECT SCOPE_IDENTITY()', $this->db_connect_id); - if ($result_id) - { - if ($row = @mssql_fetch_assoc($result_id)) - { - @mssql_free_result($result_id); - return $row['computed']; - } - @mssql_free_result($result_id); - } - - return false; - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - if (isset($this->open_queries[$query_id])) - { - unset($this->open_queries[$query_id]); - return @mssql_free_result($query_id); - } - - return false; - } - - /** - * Escape string used in sql query - */ - function sql_escape($msg) - { - return str_replace(array("'", "\0"), array("''", ''), $msg); - } - - /** - * {@inheritDoc} - */ - function sql_lower_text($column_name) - { - return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))"; - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression . " ESCAPE '\\'"; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('mssql_get_last_message')) - { - $error = array( - 'message' => @mssql_get_last_message(), - 'code' => '', - ); - - // Get error code number - $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id); - if ($result_id) - { - $row = @mssql_fetch_assoc($result_id); - $error['code'] = $row['code']; - @mssql_free_result($result_id); - } - - // Get full error message if possible - $sql = 'SELECT CAST(description as varchar(255)) as message - FROM master.dbo.sysmessages - WHERE error = ' . $error['code']; - $result_id = @mssql_query($sql); - - if ($result_id) - { - $row = @mssql_fetch_assoc($result_id); - if (!empty($row['message'])) - { - $error['message'] .= '<br />' . $row['message']; - } - @mssql_free_result($result_id); - } - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - return $data; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @mssql_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - $html_table = false; - @mssql_query('SET SHOWPLAN_TEXT ON;', $this->db_connect_id); - if ($result = @mssql_query($query, $this->db_connect_id)) - { - @mssql_next_result($result); - while ($row = @mssql_fetch_row($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - @mssql_query('SET SHOWPLAN_TEXT OFF;', $this->db_connect_id); - @mssql_free_result($result); - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @mssql_query($query, $this->db_connect_id); - while ($void = @mssql_fetch_assoc($result)) - { - // Take the time spent on parsing rows into account - } - @mssql_free_result($result); - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php deleted file mode 100644 index 04501cce8b..0000000000 --- a/phpBB/includes/db/mssql_odbc.php +++ /dev/null @@ -1,422 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -/** -* Unified ODBC functions -* Unified ODBC functions support any database having ODBC driver, for example Adabas D, IBM DB2, iODBC, Solid, Sybase SQL Anywhere... -* Here we only support MSSQL Server 2000+ because of the provided schema -* -* @note number of bytes returned for returning data depends on odbc.defaultlrl php.ini setting. -* If it is limited to 4K for example only 4K of data is returned max, resulting in incomplete theme data for example. -* @note odbc.defaultbinmode may affect UTF8 characters -* -* @package dbal -*/ -class dbal_mssql_odbc extends dbal -{ - var $last_query_text = ''; - var $connect_error = ''; - - /** - * Connect to server - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $this->persistency = $persistency; - $this->user = $sqluser; - $this->dbname = $database; - - $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; - $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); - - $max_size = @ini_get('odbc.defaultlrl'); - if (!empty($max_size)) - { - $unit = strtolower(substr($max_size, -1, 1)); - $max_size = (int) $max_size; - - if ($unit == 'k') - { - $max_size = floor($max_size / 1024); - } - else if ($unit == 'g') - { - $max_size *= 1024; - } - else if (is_numeric($unit)) - { - $max_size = floor((int) ($max_size . $unit) / 1048576); - } - $max_size = max(8, $max_size) . 'M'; - - @ini_set('odbc.defaultlrl', $max_size); - } - - if ($this->persistency) - { - if (!function_exists('odbc_pconnect')) - { - $this->connect_error = 'odbc_pconnect function does not exist, is odbc extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @odbc_pconnect($this->server, $this->user, $sqlpassword); - } - else - { - if (!function_exists('odbc_connect')) - { - $this->connect_error = 'odbc_connect function does not exist, is odbc extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @odbc_connect($this->server, $this->user, $sqlpassword); - } - - return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); - } - - /** - * Version information about used database - * @param bool $raw if true, only return the fetched sql_server_version - * @param bool $use_cache If true, it is safe to retrieve the value from the cache - * @return string sql server version - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssqlodbc_version')) === false) - { - $result_id = @odbc_exec($this->db_connect_id, "SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')"); - - $row = false; - if ($result_id) - { - $row = @odbc_fetch_array($result_id); - @odbc_free_result($result_id); - } - - $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0; - - if (!empty($cache) && $use_cache) - { - $cache->put('mssqlodbc_version', $this->sql_server_version); - } - } - - if ($raw) - { - return $this->sql_server_version; - } - - return ($this->sql_server_version) ? 'MSSQL (ODBC)<br />' . $this->sql_server_version : 'MSSQL (ODBC)'; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @odbc_exec($this->db_connect_id, 'BEGIN TRANSACTION'); - break; - - case 'commit': - return @odbc_exec($this->db_connect_id, 'COMMIT TRANSACTION'); - break; - - case 'rollback': - return @odbc_exec($this->db_connect_id, 'ROLLBACK TRANSACTION'); - break; - } - - return true; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - if (($this->query_result = @odbc_exec($this->db_connect_id, $query)) === false) - { - $this->sql_error($query); - } - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0 && $this->query_result) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows) - if ($total) - { - // We need to grab the total number of rows + the offset number of rows to get the correct result - if (strpos($query, 'SELECT DISTINCT') === 0) - { - $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15); - } - else - { - $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6); - } - } - - $result = $this->sql_query($query, $cache_ttl); - - // Seek by $offset rows - if ($offset) - { - $this->sql_rowseek($offset, $result); - } - - return $result; - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @odbc_num_rows($this->query_result) : false; - } - - /** - * Fetch current row - * @note number of bytes returned depends on odbc.defaultlrl php.ini setting. If it is limited to 4K for example only 4K of data is returned max. - */ - function sql_fetchrow($query_id = false, $debug = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - return ($query_id !== false) ? @odbc_fetch_array($query_id) : false; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - $result_id = @odbc_exec($this->db_connect_id, 'SELECT @@IDENTITY'); - - if ($result_id) - { - if (@odbc_fetch_array($result_id)) - { - $id = @odbc_result($result_id, 1); - @odbc_free_result($result_id); - return $id; - } - @odbc_free_result($result_id); - } - - return false; - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - if (isset($this->open_queries[(int) $query_id])) - { - unset($this->open_queries[(int) $query_id]); - return @odbc_free_result($query_id); - } - - return false; - } - - /** - * Escape string used in sql query - */ - function sql_escape($msg) - { - return str_replace(array("'", "\0"), array("''", ''), $msg); - } - - /** - * {@inheritDoc} - */ - function sql_lower_text($column_name) - { - return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))"; - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression . " ESCAPE '\\'"; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - return $data; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('odbc_errormsg')) - { - $error = array( - 'message' => @odbc_errormsg(), - 'code' => @odbc_error(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @odbc_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @odbc_exec($this->db_connect_id, $query); - while ($void = @odbc_fetch_array($result)) - { - // Take the time spent on parsing rows into account - } - @odbc_free_result($result); - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php deleted file mode 100644 index b91372ac61..0000000000 --- a/phpBB/includes/db/mssqlnative.php +++ /dev/null @@ -1,652 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2010 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -* This is the MS SQL Server Native database abstraction layer. -* PHP mssql native driver required. -* @author Chris Pucci -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -/** - * Prior to version 1.1 the SQL Server Native PHP driver didn't support sqlsrv_num_rows, or cursor based seeking so we recall all rows into an array - * and maintain our own cursor index into that array. - */ -class result_mssqlnative -{ - public function result_mssqlnative($queryresult = false) - { - $this->m_cursor = 0; - $this->m_rows = array(); - $this->m_num_fields = sqlsrv_num_fields($queryresult); - $this->m_field_meta = sqlsrv_field_metadata($queryresult); - - while ($row = sqlsrv_fetch_array($queryresult, SQLSRV_FETCH_ASSOC)) - { - if ($row !== null) - { - foreach($row as $k => $v) - { - if (is_object($v) && method_exists($v, 'format')) - { - $row[$k] = $v->format("Y-m-d\TH:i:s\Z"); - } - } - $this->m_rows[] = $row;//read results into memory, cursors are not supported - } - } - - $this->m_row_count = sizeof($this->m_rows); - } - - private function array_to_obj($array, &$obj) - { - foreach ($array as $key => $value) - { - if (is_array($value)) - { - $obj->$key = new stdClass(); - array_to_obj($value, $obj->$key); - } - else - { - $obj->$key = $value; - } - } - return $obj; - } - - public function fetch($mode = SQLSRV_FETCH_BOTH, $object_class = 'stdClass') - { - if ($this->m_cursor >= $this->m_row_count || $this->m_row_count == 0) - { - return false; - } - - $ret = false; - $arr_num = array(); - - if ($mode == SQLSRV_FETCH_NUMERIC || $mode == SQLSRV_FETCH_BOTH) - { - foreach($this->m_rows[$this->m_cursor] as $key => $value) - { - $arr_num[] = $value; - } - } - - switch ($mode) - { - case SQLSRV_FETCH_ASSOC: - $ret = $this->m_rows[$this->m_cursor]; - break; - case SQLSRV_FETCH_NUMERIC: - $ret = $arr_num; - break; - case 'OBJECT': - $ret = $this->array_to_obj($this->m_rows[$this->m_cursor], $o = new $object_class); - break; - case SQLSRV_FETCH_BOTH: - default: - $ret = $this->m_rows[$this->m_cursor] + $arr_num; - break; - } - $this->m_cursor++; - return $ret; - } - - public function get($pos, $fld) - { - return $this->m_rows[$pos][$fld]; - } - - public function num_rows() - { - return $this->m_row_count; - } - - public function seek($iRow) - { - $this->m_cursor = min($iRow, $this->m_row_count); - } - - public function num_fields() - { - return $this->m_num_fields; - } - - public function field_name($nr) - { - $arr_keys = array_keys($this->m_rows[0]); - return $arr_keys[$nr]; - } - - public function field_type($nr) - { - $i = 0; - $int_type = -1; - $str_type = ''; - - foreach ($this->m_field_meta as $meta) - { - if ($nr == $i) - { - $int_type = $meta['Type']; - break; - } - $i++; - } - - //http://msdn.microsoft.com/en-us/library/cc296183.aspx contains type table - switch ($int_type) - { - case SQLSRV_SQLTYPE_BIGINT: $str_type = 'bigint'; break; - case SQLSRV_SQLTYPE_BINARY: $str_type = 'binary'; break; - case SQLSRV_SQLTYPE_BIT: $str_type = 'bit'; break; - case SQLSRV_SQLTYPE_CHAR: $str_type = 'char'; break; - case SQLSRV_SQLTYPE_DATETIME: $str_type = 'datetime'; break; - case SQLSRV_SQLTYPE_DECIMAL/*($precision, $scale)*/: $str_type = 'decimal'; break; - case SQLSRV_SQLTYPE_FLOAT: $str_type = 'float'; break; - case SQLSRV_SQLTYPE_IMAGE: $str_type = 'image'; break; - case SQLSRV_SQLTYPE_INT: $str_type = 'int'; break; - case SQLSRV_SQLTYPE_MONEY: $str_type = 'money'; break; - case SQLSRV_SQLTYPE_NCHAR/*($charCount)*/: $str_type = 'nchar'; break; - case SQLSRV_SQLTYPE_NUMERIC/*($precision, $scale)*/: $str_type = 'numeric'; break; - case SQLSRV_SQLTYPE_NVARCHAR/*($charCount)*/: $str_type = 'nvarchar'; break; - case SQLSRV_SQLTYPE_NTEXT: $str_type = 'ntext'; break; - case SQLSRV_SQLTYPE_REAL: $str_type = 'real'; break; - case SQLSRV_SQLTYPE_SMALLDATETIME: $str_type = 'smalldatetime'; break; - case SQLSRV_SQLTYPE_SMALLINT: $str_type = 'smallint'; break; - case SQLSRV_SQLTYPE_SMALLMONEY: $str_type = 'smallmoney'; break; - case SQLSRV_SQLTYPE_TEXT: $str_type = 'text'; break; - case SQLSRV_SQLTYPE_TIMESTAMP: $str_type = 'timestamp'; break; - case SQLSRV_SQLTYPE_TINYINT: $str_type = 'tinyint'; break; - case SQLSRV_SQLTYPE_UNIQUEIDENTIFIER: $str_type = 'uniqueidentifier'; break; - case SQLSRV_SQLTYPE_UDT: $str_type = 'UDT'; break; - case SQLSRV_SQLTYPE_VARBINARY/*($byteCount)*/: $str_type = 'varbinary'; break; - case SQLSRV_SQLTYPE_VARCHAR/*($charCount)*/: $str_type = 'varchar'; break; - case SQLSRV_SQLTYPE_XML: $str_type = 'xml'; break; - default: $str_type = $int_type; - } - return $str_type; - } - - public function free() - { - unset($this->m_rows); - return; - } -} - -/** -* @package dbal -*/ -class dbal_mssqlnative extends dbal -{ - var $m_insert_id = NULL; - var $last_query_text = ''; - var $query_options = array(); - var $connect_error = ''; - - /** - * Connect to server - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - // Test for driver support, to avoid suppressed fatal error - if (!function_exists('sqlsrv_connect')) - { - $this->connect_error = 'Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx'; - return $this->sql_error(''); - } - - //set up connection variables - $this->persistency = $persistency; - $this->user = $sqluser; - $this->dbname = $database; - $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; - $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); - - //connect to database - $this->db_connect_id = sqlsrv_connect($this->server, array( - 'Database' => $this->dbname, - 'UID' => $this->user, - 'PWD' => $sqlpassword - )); - - return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); - } - - /** - * Version information about used database - * @param bool $raw if true, only return the fetched sql_server_version - * @param bool $use_cache If true, it is safe to retrieve the value from the cache - * @return string sql server version - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false) - { - $arr_server_info = sqlsrv_server_info($this->db_connect_id); - $this->sql_server_version = $arr_server_info['SQLServerVersion']; - - if (!empty($cache) && $use_cache) - { - $cache->put('mssql_version', $this->sql_server_version); - } - } - - if ($raw) - { - return $this->sql_server_version; - } - - return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL'; - } - - /** - * {@inheritDoc} - */ - function sql_buffer_nested_transactions() - { - return true; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return sqlsrv_begin_transaction($this->db_connect_id); - break; - - case 'commit': - return sqlsrv_commit($this->db_connect_id); - break; - - case 'rollback': - return sqlsrv_rollback($this->db_connect_id); - break; - } - return true; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - if (($this->query_result = @sqlsrv_query($this->db_connect_id, $query, array(), $this->query_options)) === false) - { - $this->sql_error($query); - } - // reset options for next query - $this->query_options = array(); - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0 && $this->query_result) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // total == 0 means all results - not zero results - if ($offset == 0 && $total !== 0) - { - if (strpos($query, "SELECT") === false) - { - $query = "TOP {$total} " . $query; - } - else - { - $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query); - } - } - else if ($offset > 0) - { - $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query); - $query = 'SELECT * - FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3 - FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3'; - - if ($total > 0) - { - $query .= ' WHERE line3 BETWEEN ' . ($offset+1) . ' AND ' . ($offset + $total); - } - else - { - $query .= ' WHERE line3 > ' . $offset; - } - } - - $result = $this->sql_query($query, $cache_ttl); - - return $result; - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - return (!empty($this->query_result)) ? @sqlsrv_rows_affected($this->query_result) : false; - } - - /** - * Fetch current row - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - if ($query_id === false) - { - return false; - } - - $row = @sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC); - - if ($row) - { - foreach ($row as $key => $value) - { - $row[$key] = ($value === ' ' || $value === NULL) ? '' : $value; - } - - // remove helper values from LIMIT queries - if (isset($row['line2'])) - { - unset($row['line2'], $row['line3']); - } - } - return (sizeof($row)) ? $row : false; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - $result_id = @sqlsrv_query($this->db_connect_id, 'SELECT @@IDENTITY'); - - if ($result_id !== false) - { - $row = @sqlsrv_fetch_array($result_id); - $id = $row[0]; - @sqlsrv_free_stmt($result_id); - return $id; - } - else - { - return false; - } - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - if (isset($this->open_queries[$query_id])) - { - unset($this->open_queries[$query_id]); - return @sqlsrv_free_stmt($query_id); - } - return false; - } - - /** - * Escape string used in sql query - */ - function sql_escape($msg) - { - return str_replace(array("'", "\0"), array("''", ''), $msg); - } - - /** - * {@inheritDoc} - */ - function sql_lower_text($column_name) - { - return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))"; - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression . " ESCAPE '\\'"; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('sqlsrv_errors')) - { - $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); - $error_message = ''; - $code = 0; - - if ($errors != null) - { - foreach ($errors as $error) - { - $error_message .= "SQLSTATE: " . $error[ 'SQLSTATE'] . "\n"; - $error_message .= "code: " . $error[ 'code'] . "\n"; - $code = $error['code']; - $error_message .= "message: " . $error[ 'message'] . "\n"; - } - $this->last_error_result = $error_message; - $error = $this->last_error_result; - } - else - { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); - } - - $error = array( - 'message' => $error, - 'code' => $code, - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - return $data; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @sqlsrv_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - $html_table = false; - @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT ON;'); - if ($result = @sqlsrv_query($this->db_connect_id, $query)) - { - @sqlsrv_next_result($result); - while ($row = @sqlsrv_fetch_array($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT OFF;'); - @sqlsrv_free_stmt($result); - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @sqlsrv_query($this->db_connect_id, $query); - while ($void = @sqlsrv_fetch_array($result)) - { - // Take the time spent on parsing rows into account - } - @sqlsrv_free_stmt($result); - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } - - /** - * Utility method used to retrieve number of rows - * Emulates mysql_num_rows - * Used in acp_database.php -> write_data_mssqlnative() - * Requires a static or keyset cursor to be definde via - * mssqlnative_set_query_options() - */ - function mssqlnative_num_rows($res) - { - if ($res !== false) - { - return sqlsrv_num_rows($res); - } - else - { - return false; - } - } - - /** - * Allows setting mssqlnative specific query options passed to sqlsrv_query as 4th parameter. - */ - function mssqlnative_set_query_options($options) - { - $this->query_options = $options; - } -} - -?> diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php deleted file mode 100644 index 252cb20bd4..0000000000 --- a/phpBB/includes/db/mysql.php +++ /dev/null @@ -1,591 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -/** -* MySQL4 Database Abstraction Layer -* Compatible with: -* MySQL 3.23+ -* MySQL 4.0+ -* MySQL 4.1+ -* MySQL 5.0+ -* @package dbal -*/ -class dbal_mysql extends dbal -{ - var $multi_insert = true; - var $connect_error = ''; - - /** - * Connect to server - * @access public - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $this->persistency = $persistency; - $this->user = $sqluser; - $this->server = $sqlserver . (($port) ? ':' . $port : ''); - $this->dbname = $database; - - $this->sql_layer = 'mysql4'; - - if ($this->persistency) - { - if (!function_exists('mysql_pconnect')) - { - $this->connect_error = 'mysql_pconnect function does not exist, is mysql extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @mysql_pconnect($this->server, $this->user, $sqlpassword); - } - else - { - if (!function_exists('mysql_connect')) - { - $this->connect_error = 'mysql_connect function does not exist, is mysql extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); - } - - if ($this->db_connect_id && $this->dbname != '') - { - if (@mysql_select_db($this->dbname, $this->db_connect_id)) - { - // Determine what version we are using and if it natively supports UNICODE - if (version_compare($this->sql_server_info(true), '4.1.0', '>=')) - { - @mysql_query("SET NAMES 'utf8'", $this->db_connect_id); - - // enforce strict mode on databases that support it - if (version_compare($this->sql_server_info(true), '5.0.2', '>=')) - { - $result = @mysql_query('SELECT @@session.sql_mode AS sql_mode', $this->db_connect_id); - $row = @mysql_fetch_assoc($result); - @mysql_free_result($result); - $modes = array_map('trim', explode(',', $row['sql_mode'])); - - // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES - if (!in_array('TRADITIONAL', $modes)) - { - if (!in_array('STRICT_ALL_TABLES', $modes)) - { - $modes[] = 'STRICT_ALL_TABLES'; - } - - if (!in_array('STRICT_TRANS_TABLES', $modes)) - { - $modes[] = 'STRICT_TRANS_TABLES'; - } - } - - $mode = implode(',', $modes); - @mysql_query("SET SESSION sql_mode='{$mode}'", $this->db_connect_id); - } - } - else if (version_compare($this->sql_server_info(true), '4.0.0', '<')) - { - $this->sql_layer = 'mysql'; - } - - return $this->db_connect_id; - } - } - - return $this->sql_error(''); - } - - /** - * Version information about used database - * @param bool $raw if true, only return the fetched sql_server_version - * @param bool $use_cache If true, it is safe to retrieve the value from the cache - * @return string sql server version - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysql_version')) === false) - { - $result = @mysql_query('SELECT VERSION() AS version', $this->db_connect_id); - $row = @mysql_fetch_assoc($result); - @mysql_free_result($result); - - $this->sql_server_version = $row['version']; - - if (!empty($cache) && $use_cache) - { - $cache->put('mysql_version', $this->sql_server_version); - } - } - - return ($raw) ? $this->sql_server_version : 'MySQL ' . $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @mysql_query('BEGIN', $this->db_connect_id); - break; - - case 'commit': - return @mysql_query('COMMIT', $this->db_connect_id); - break; - - case 'rollback': - return @mysql_query('ROLLBACK', $this->db_connect_id); - break; - } - - return true; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - if (($this->query_result = @mysql_query($query, $this->db_connect_id)) === false) - { - $this->sql_error($query); - } - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0 && $this->query_result) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // if $total is set to 0 we do not want to limit the number of rows - if ($total == 0) - { - // Having a value of -1 was always a bug - $total = '18446744073709551615'; - } - - $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); - - return $this->sql_query($query, $cache_ttl); - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @mysql_affected_rows($this->db_connect_id) : false; - } - - /** - * Fetch current row - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - return ($query_id !== false) ? @mysql_fetch_assoc($query_id) : false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - return ($query_id !== false) ? @mysql_data_seek($query_id, $rownum) : false; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - return ($this->db_connect_id) ? @mysql_insert_id($this->db_connect_id) : false; - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - if (isset($this->open_queries[(int) $query_id])) - { - unset($this->open_queries[(int) $query_id]); - return @mysql_free_result($query_id); - } - - return false; - } - - /** - * Escape string used in sql query - */ - function sql_escape($msg) - { - if (!$this->db_connect_id) - { - return @mysql_real_escape_string($msg); - } - - return @mysql_real_escape_string($msg, $this->db_connect_id); - } - - /** - * Gets the estimated number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Number of rows in $table_name. - * Prefixed with ~ if estimated (otherwise exact). - * - * @access public - */ - function get_estimated_row_count($table_name) - { - $table_status = $this->get_table_status($table_name); - - if (isset($table_status['Engine'])) - { - if ($table_status['Engine'] === 'MyISAM') - { - return $table_status['Rows']; - } - else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000) - { - return '~' . $table_status['Rows']; - } - } - - return parent::get_row_count($table_name); - } - - /** - * Gets the exact number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Exact number of rows in $table_name. - * - * @access public - */ - function get_row_count($table_name) - { - $table_status = $this->get_table_status($table_name); - - if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM') - { - return $table_status['Rows']; - } - - return parent::get_row_count($table_name); - } - - /** - * Gets some information about the specified table. - * - * @param string $table_name Table name - * - * @return array - * - * @access protected - */ - function get_table_status($table_name) - { - $sql = "SHOW TABLE STATUS - LIKE '" . $this->sql_escape($table_name) . "'"; - $result = $this->sql_query($sql); - $table_status = $this->sql_fetchrow($result); - $this->sql_freeresult($result); - - return $table_status; - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - switch ($stage) - { - case 'FROM': - $data = '(' . $data . ')'; - break; - } - - return $data; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if ($this->db_connect_id) - { - $error = array( - 'message' => @mysql_error($this->db_connect_id), - 'code' => @mysql_errno($this->db_connect_id), - ); - } - else if (function_exists('mysql_error')) - { - $error = array( - 'message' => @mysql_error(), - 'code' => @mysql_errno(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @mysql_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - static $test_prof; - - // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING - if ($test_prof === null) - { - $test_prof = false; - if (version_compare($this->sql_server_info(true), '5.0.37', '>=') && version_compare($this->sql_server_info(true), '5.1', '<')) - { - $test_prof = true; - } - } - - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - // begin profiling - if ($test_prof) - { - @mysql_query('SET profiling = 1;', $this->db_connect_id); - } - - if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id)) - { - while ($row = @mysql_fetch_assoc($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - @mysql_free_result($result); - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - - if ($test_prof) - { - $html_table = false; - - // get the last profile - if ($result = @mysql_query('SHOW PROFILE ALL;', $this->db_connect_id)) - { - $this->html_hold .= '<br />'; - while ($row = @mysql_fetch_assoc($result)) - { - // make <unknown> HTML safe - if (!empty($row['Source_function'])) - { - $row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']); - } - - // remove unsupported features - foreach ($row as $key => $val) - { - if ($val === null) - { - unset($row[$key]); - } - } - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - @mysql_free_result($result); - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - - @mysql_query('SET profiling = 0;', $this->db_connect_id); - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @mysql_query($query, $this->db_connect_id); - while ($void = @mysql_fetch_assoc($result)) - { - // Take the time spent on parsing rows into account - } - @mysql_free_result($result); - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php deleted file mode 100644 index 69f1d26a40..0000000000 --- a/phpBB/includes/db/mysqli.php +++ /dev/null @@ -1,581 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -/** -* MySQLi Database Abstraction Layer -* mysqli-extension has to be compiled with: -* MySQL 4.1+ or MySQL 5.0+ -* @package dbal -*/ -class dbal_mysqli extends dbal -{ - var $multi_insert = true; - var $connect_error = ''; - - /** - * Connect to server - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false , $new_link = false) - { - if (!function_exists('mysqli_connect')) - { - $this->connect_error = 'mysqli_connect function does not exist, is mysqli extension installed?'; - return $this->sql_error(''); - } - - // Mysqli extension supports persistent connection since PHP 5.3.0 - $this->persistency = (version_compare(PHP_VERSION, '5.3.0', '>=')) ? $persistency : false; - $this->user = $sqluser; - - // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix - $this->server = ($this->persistency) ? 'p:' . (($sqlserver) ? $sqlserver : 'localhost') : $sqlserver; - - $this->dbname = $database; - $port = (!$port) ? NULL : $port; - - // If port is set and it is not numeric, most likely mysqli socket is set. - // Try to map it to the $socket parameter. - $socket = NULL; - if ($port) - { - if (is_numeric($port)) - { - $port = (int) $port; - } - else - { - $socket = $port; - $port = NULL; - } - } - - $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket); - - if ($this->db_connect_id && $this->dbname != '') - { - @mysqli_query($this->db_connect_id, "SET NAMES 'utf8'"); - - // enforce strict mode on databases that support it - if (version_compare($this->sql_server_info(true), '5.0.2', '>=')) - { - $result = @mysqli_query($this->db_connect_id, 'SELECT @@session.sql_mode AS sql_mode'); - $row = @mysqli_fetch_assoc($result); - @mysqli_free_result($result); - - $modes = array_map('trim', explode(',', $row['sql_mode'])); - - // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES - if (!in_array('TRADITIONAL', $modes)) - { - if (!in_array('STRICT_ALL_TABLES', $modes)) - { - $modes[] = 'STRICT_ALL_TABLES'; - } - - if (!in_array('STRICT_TRANS_TABLES', $modes)) - { - $modes[] = 'STRICT_TRANS_TABLES'; - } - } - - $mode = implode(',', $modes); - @mysqli_query($this->db_connect_id, "SET SESSION sql_mode='{$mode}'"); - } - return $this->db_connect_id; - } - - return $this->sql_error(''); - } - - /** - * Version information about used database - * @param bool $use_cache If true, it is safe to retrieve the value from the cache - * @return string sql server version - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false) - { - $result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version'); - $row = @mysqli_fetch_assoc($result); - @mysqli_free_result($result); - - $this->sql_server_version = $row['version']; - - if (!empty($cache) && $use_cache) - { - $cache->put('mysqli_version', $this->sql_server_version); - } - } - - return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @mysqli_autocommit($this->db_connect_id, false); - break; - - case 'commit': - $result = @mysqli_commit($this->db_connect_id); - @mysqli_autocommit($this->db_connect_id, true); - return $result; - break; - - case 'rollback': - $result = @mysqli_rollback($this->db_connect_id); - @mysqli_autocommit($this->db_connect_id, true); - return $result; - break; - } - - return true; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - if (($this->query_result = @mysqli_query($this->db_connect_id, $query)) === false) - { - $this->sql_error($query); - } - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // if $total is set to 0 we do not want to limit the number of rows - if ($total == 0) - { - // MySQL 4.1+ no longer supports -1 in limit queries - $total = '18446744073709551615'; - } - - $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); - - return $this->sql_query($query, $cache_ttl); - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @mysqli_affected_rows($this->db_connect_id) : false; - } - - /** - * Fetch current row - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - if ($query_id !== false) - { - $result = @mysqli_fetch_assoc($query_id); - return $result !== null ? $result : false; - } - - return false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - return ($query_id !== false) ? @mysqli_data_seek($query_id, $rownum) : false; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - return ($this->db_connect_id) ? @mysqli_insert_id($this->db_connect_id) : false; - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - return @mysqli_free_result($query_id); - } - - /** - * Escape string used in sql query - */ - function sql_escape($msg) - { - return @mysqli_real_escape_string($this->db_connect_id, $msg); - } - - /** - * Gets the estimated number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Number of rows in $table_name. - * Prefixed with ~ if estimated (otherwise exact). - * - * @access public - */ - function get_estimated_row_count($table_name) - { - $table_status = $this->get_table_status($table_name); - - if (isset($table_status['Engine'])) - { - if ($table_status['Engine'] === 'MyISAM') - { - return $table_status['Rows']; - } - else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000) - { - return '~' . $table_status['Rows']; - } - } - - return parent::get_row_count($table_name); - } - - /** - * Gets the exact number of rows in a specified table. - * - * @param string $table_name Table name - * - * @return string Exact number of rows in $table_name. - * - * @access public - */ - function get_row_count($table_name) - { - $table_status = $this->get_table_status($table_name); - - if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM') - { - return $table_status['Rows']; - } - - return parent::get_row_count($table_name); - } - - /** - * Gets some information about the specified table. - * - * @param string $table_name Table name - * - * @return array - * - * @access protected - */ - function get_table_status($table_name) - { - $sql = "SHOW TABLE STATUS - LIKE '" . $this->sql_escape($table_name) . "'"; - $result = $this->sql_query($sql); - $table_status = $this->sql_fetchrow($result); - $this->sql_freeresult($result); - - return $table_status; - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - switch ($stage) - { - case 'FROM': - $data = '(' . $data . ')'; - break; - } - - return $data; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if ($this->db_connect_id) - { - $error = array( - 'message' => @mysqli_error($this->db_connect_id), - 'code' => @mysqli_errno($this->db_connect_id) - ); - } - else if (function_exists('mysqli_connect_error')) - { - $error = array( - 'message' => @mysqli_connect_error(), - 'code' => @mysqli_connect_errno(), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @mysqli_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - static $test_prof; - - // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING - if ($test_prof === null) - { - $test_prof = false; - if (strpos(mysqli_get_server_info($this->db_connect_id), 'community') !== false) - { - $ver = mysqli_get_server_version($this->db_connect_id); - if ($ver >= 50037 && $ver < 50100) - { - $test_prof = true; - } - } - } - - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - // begin profiling - if ($test_prof) - { - @mysqli_query($this->db_connect_id, 'SET profiling = 1;'); - } - - if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query")) - { - while ($row = @mysqli_fetch_assoc($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - @mysqli_free_result($result); - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - - if ($test_prof) - { - $html_table = false; - - // get the last profile - if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;')) - { - $this->html_hold .= '<br />'; - while ($row = @mysqli_fetch_assoc($result)) - { - // make <unknown> HTML safe - if (!empty($row['Source_function'])) - { - $row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']); - } - - // remove unsupported features - foreach ($row as $key => $val) - { - if ($val === null) - { - unset($row[$key]); - } - } - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - @mysqli_free_result($result); - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - - @mysqli_query($this->db_connect_id, 'SET profiling = 0;'); - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @mysqli_query($this->db_connect_id, $query); - while ($void = @mysqli_fetch_assoc($result)) - { - // Take the time spent on parsing rows into account - } - @mysqli_free_result($result); - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php deleted file mode 100644 index 4a7a4ecc8c..0000000000 --- a/phpBB/includes/db/oracle.php +++ /dev/null @@ -1,808 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -/** -* Oracle Database Abstraction Layer -* @package dbal -*/ -class dbal_oracle extends dbal -{ - var $last_query_text = ''; - var $connect_error = ''; - - /** - * Connect to server - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $this->persistency = $persistency; - $this->user = $sqluser; - $this->server = $sqlserver . (($port) ? ':' . $port : ''); - $this->dbname = $database; - - $connect = $database; - - // support for "easy connect naming" - if ($sqlserver !== '' && $sqlserver !== '/') - { - if (substr($sqlserver, -1, 1) == '/') - { - $sqlserver == substr($sqlserver, 0, -1); - } - $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database; - } - - if ($new_link) - { - if (!function_exists('ocinlogon')) - { - $this->connect_error = 'ocinlogon function does not exist, is oci extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8'); - } - else if ($this->persistency) - { - if (!function_exists('ociplogon')) - { - $this->connect_error = 'ociplogon function does not exist, is oci extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8'); - } - else - { - if (!function_exists('ocilogon')) - { - $this->connect_error = 'ocilogon function does not exist, is oci extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8'); - } - - return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); - } - - /** - * Version information about used database - * @param bool $raw if true, only return the fetched sql_server_version - * @param bool $use_cache forced to false for Oracle - * @return string sql server version - */ - function sql_server_info($raw = false, $use_cache = true) - { - /** - * force $use_cache false. I didn't research why the caching code below is commented out - * but I assume its because the Oracle extension provides a direct method to access it - * without a query. - */ - - $use_cache = false; -/* - global $cache; - - if (empty($cache) || ($this->sql_server_version = $cache->get('oracle_version')) === false) - { - $result = @ociparse($this->db_connect_id, 'SELECT * FROM v$version WHERE banner LIKE \'Oracle%\''); - @ociexecute($result, OCI_DEFAULT); - @ocicommit($this->db_connect_id); - - $row = array(); - @ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS); - @ocifreestatement($result); - $this->sql_server_version = trim($row['BANNER']); - - $cache->put('oracle_version', $this->sql_server_version); - } -*/ - $this->sql_server_version = @ociserverversion($this->db_connect_id); - - return $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return true; - break; - - case 'commit': - return @ocicommit($this->db_connect_id); - break; - - case 'rollback': - return @ocirollback($this->db_connect_id); - break; - } - - return true; - } - - /** - * Oracle specific code to handle the fact that it does not compare columns properly - * @access private - */ - function _rewrite_col_compare($args) - { - if (sizeof($args) == 4) - { - if ($args[2] == '=') - { - return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))'; - } - else if ($args[2] == '<>') - { - // really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P - return '(' . $args[0] . ' OR ((' . $args[1] . ' is NULL AND ' . $args[3] . ' is NOT NULL) OR (' . $args[1] . ' is NOT NULL AND ' . $args[3] . ' is NULL)))'; - } - } - else - { - return $this->_rewrite_where($args[0]); - } - } - - /** - * Oracle specific code to handle it's lack of sanity - * @access private - */ - function _rewrite_where($where_clause) - { - preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER); - $out = ''; - foreach ($result as $val) - { - if (!isset($val[5])) - { - if ($val[4] !== "''") - { - $out .= $val[0]; - } - else - { - $out .= ' ' . $val[1] . ' ' . $val[2]; - if ($val[3] == '=') - { - $out .= ' is NULL'; - } - else if ($val[3] == '<>') - { - $out .= ' is NOT NULL'; - } - } - } - else - { - $in_clause = array(); - $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1); - $extra = false; - preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER); - $i = 0; - foreach ($sub_vals[0] as $sub_val) - { - // two things: - // 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison - // 2) This fixes the 1000 list limit that Oracle has (ORA-01795) - if ($sub_val !== "''") - { - $in_clause[(int) $i++/1000][] = $sub_val; - } - else - { - $extra = true; - } - } - if (!$extra && $i < 1000) - { - $out .= $val[0]; - } - else - { - $out .= ' ' . $val[1] . '('; - $in_array = array(); - - // constuct each IN() clause - foreach ($in_clause as $in_values) - { - $in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')'; - } - - // Join the IN() clauses against a few ORs (IN is just a nicer OR anyway) - $out .= implode(' OR ', $in_array); - - // handle the empty string case - if ($extra) - { - $out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL'; - } - $out .= ')'; - - unset($in_array, $in_clause); - } - } - } - - return $out; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - $in_transaction = false; - if (!$this->transaction) - { - $this->sql_transaction('begin'); - } - else - { - $in_transaction = true; - } - - $array = array(); - - // We overcome Oracle's 4000 char limit by binding vars - if (strlen($query) > 4000) - { - if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/sU', $query, $regs)) - { - if (strlen($regs[3]) > 4000) - { - $cols = explode(', ', $regs[2]); - - preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER); - -/* The code inside this comment block breaks clob handling, but does allow the - database restore script to work. If you want to allow no posts longer than 4KB - and/or need the db restore script, uncomment this. - - - if (sizeof($cols) !== sizeof($vals)) - { - // Try to replace some common data we know is from our restore script or from other sources - $regs[3] = str_replace("'||chr(47)||'", '/', $regs[3]); - $_vals = explode(', ', $regs[3]); - - $vals = array(); - $is_in_val = false; - $i = 0; - $string = ''; - - foreach ($_vals as $value) - { - if (strpos($value, "'") === false && !$is_in_val) - { - $vals[$i++] = $value; - continue; - } - - if (substr($value, -1) === "'") - { - $vals[$i] = $string . (($is_in_val) ? ', ' : '') . $value; - $string = ''; - $is_in_val = false; - - if ($vals[$i][0] !== "'") - { - $vals[$i] = "''" . $vals[$i]; - } - $i++; - continue; - } - else - { - $string .= (($is_in_val) ? ', ' : '') . $value; - $is_in_val = true; - } - } - - if ($string) - { - // New value if cols != value - $vals[(sizeof($cols) !== sizeof($vals)) ? $i : $i - 1] .= $string; - } - - $vals = array(0 => $vals); - } -*/ - - $inserts = $vals[0]; - unset($vals); - - foreach ($inserts as $key => $value) - { - if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2 - { - $inserts[$key] = ':' . strtoupper($cols[$key]); - $array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1)); - } - } - - $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')'; - } - } - else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER)) - { - if (strlen($data[0][2]) > 4000) - { - $update = $data[0][1]; - $where = $data[0][3]; - preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER); - unset($data); - - $cols = array(); - foreach ($temp as $value) - { - if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2 - { - $cols[] = $value[1] . '=:' . strtoupper($value[1]); - $array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1)); - } - else - { - $cols[] = $value[1] . '=' . $value[2]; - } - } - - $query = $update . implode(', ', $cols) . ' ' . $where; - unset($cols); - } - } - } - - switch (substr($query, 0, 6)) - { - case 'DELETE': - if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs)) - { - $query = $regs[1] . $this->_rewrite_where($regs[2]); - unset($regs); - } - break; - - case 'UPDATE': - if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs)) - { - $query = $regs[1] . $this->_rewrite_where($regs[2]); - unset($regs); - } - break; - - case 'SELECT': - $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query); - break; - } - - $this->query_result = @ociparse($this->db_connect_id, $query); - - foreach ($array as $key => $value) - { - @ocibindbyname($this->query_result, $key, $array[$key], -1); - } - - $success = @ociexecute($this->query_result, OCI_DEFAULT); - - if (!$success) - { - $this->sql_error($query); - $this->query_result = false; - } - else - { - if (!$in_transaction) - { - $this->sql_transaction('commit'); - } - } - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0 && $this->query_result) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset; - - return $this->sql_query($query, $cache_ttl); - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - return ($this->query_result) ? @ocirowcount($this->query_result) : false; - } - - /** - * Fetch current row - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - if ($query_id !== false) - { - $row = array(); - $result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS); - - if (!$result || !$row) - { - return false; - } - - $result_row = array(); - foreach ($row as $key => $value) - { - // Oracle treats empty strings as null - if (is_null($value)) - { - $value = ''; - } - - // OCI->CLOB? - if (is_object($value)) - { - $value = $value->load(); - } - - $result_row[strtolower($key)] = $value; - } - - return $result_row; - } - - return false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - if ($query_id === false) - { - return false; - } - - // Reset internal pointer - @ociexecute($query_id, OCI_DEFAULT); - - // We do not fetch the row for rownum == 0 because then the next resultset would be the second row - for ($i = 0; $i < $rownum; $i++) - { - if (!$this->sql_fetchrow($query_id)) - { - return false; - } - } - - return true; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - $query_id = $this->query_result; - - if ($query_id !== false && $this->last_query_text != '') - { - if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename)) - { - $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL'; - $stmt = @ociparse($this->db_connect_id, $query); - @ociexecute($stmt, OCI_DEFAULT); - - $temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS); - @ocifreestatement($stmt); - - if ($temp_result) - { - return $temp_array['CURRVAL']; - } - else - { - return false; - } - } - } - - return false; - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - if (isset($this->open_queries[(int) $query_id])) - { - unset($this->open_queries[(int) $query_id]); - return @ocifreestatement($query_id); - } - - return false; - } - - /** - * Escape string used in sql query - */ - function sql_escape($msg) - { - return str_replace(array("'", "\0"), array("''", ''), $msg); - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression . " ESCAPE '\\'"; - } - - function _sql_custom_build($stage, $data) - { - return $data; - } - - function _sql_bit_and($column_name, $bit, $compare = '') - { - return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); - } - - function _sql_bit_or($column_name, $bit, $compare = '') - { - return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('ocierror')) - { - $error = @ocierror(); - $error = (!$error) ? @ocierror($this->query_result) : $error; - $error = (!$error) ? @ocierror($this->db_connect_id) : $error; - - if ($error) - { - $this->last_error_result = $error; - } - else - { - $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); - } - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @ocilogoff($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - - $html_table = false; - - // Grab a plan table, any will do - $sql = "SELECT table_name - FROM USER_TABLES - WHERE table_name LIKE '%PLAN_TABLE%'"; - $stmt = ociparse($this->db_connect_id, $sql); - ociexecute($stmt); - $result = array(); - - if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS)) - { - $table = $result['TABLE_NAME']; - - // This is the statement_id that will allow us to track the plan - $statement_id = substr(md5($query), 0, 30); - - // Remove any stale plans - $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); - ociexecute($stmt2); - ocifreestatement($stmt2); - - // Explain the plan - $sql = "EXPLAIN PLAN - SET STATEMENT_ID = '$statement_id' - FOR $query"; - $stmt2 = ociparse($this->db_connect_id, $sql); - ociexecute($stmt2); - ocifreestatement($stmt2); - - // Get the data from the plan - $sql = "SELECT operation, options, object_name, object_type, cardinality, cost - FROM plan_table - START WITH id = 0 AND statement_id = '$statement_id' - CONNECT BY PRIOR id = parent_id - AND statement_id = '$statement_id'"; - $stmt2 = ociparse($this->db_connect_id, $sql); - ociexecute($stmt2); - - $row = array(); - while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - - ocifreestatement($stmt2); - - // Remove the plan we just made, we delete them on request anyway - $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); - ociexecute($stmt2); - ocifreestatement($stmt2); - } - - ocifreestatement($stmt); - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @ociparse($this->db_connect_id, $query); - $success = @ociexecute($result, OCI_DEFAULT); - $row = array(); - - while (@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS)) - { - // Take the time spent on parsing rows into account - } - @ocifreestatement($result); - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/postgres.php b/phpBB/includes/db/postgres.php deleted file mode 100644 index bb116e0763..0000000000 --- a/phpBB/includes/db/postgres.php +++ /dev/null @@ -1,485 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -if (!class_exists('phpbb_error_collector')) -{ - include($phpbb_root_path . 'includes/error_collector.' . $phpEx); -} - -/** -* PostgreSQL Database Abstraction Layer -* Minimum Requirement is Version 7.3+ -* @package dbal -*/ -class dbal_postgres extends dbal -{ - var $last_query_text = ''; - var $connect_error = ''; - - /** - * Connect to server - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $connect_string = ''; - - if ($sqluser) - { - $connect_string .= "user=$sqluser "; - } - - if ($sqlpassword) - { - $connect_string .= "password=$sqlpassword "; - } - - if ($sqlserver) - { - // $sqlserver can carry a port separated by : for compatibility reasons - // If $sqlserver has more than one : it's probably an IPv6 address. - // In this case we only allow passing a port via the $port variable. - if (substr_count($sqlserver, ':') === 1) - { - list($sqlserver, $port) = explode(':', $sqlserver); - } - - if ($sqlserver !== 'localhost') - { - $connect_string .= "host=$sqlserver "; - } - - if ($port) - { - $connect_string .= "port=$port "; - } - } - - $schema = ''; - - if ($database) - { - $this->dbname = $database; - if (strpos($database, '.') !== false) - { - list($database, $schema) = explode('.', $database); - } - $connect_string .= "dbname=$database"; - } - - $this->persistency = $persistency; - - if ($this->persistency) - { - if (!function_exists('pg_pconnect')) - { - $this->connect_error = 'pg_pconnect function does not exist, is pgsql extension installed?'; - return $this->sql_error(''); - } - $collector = new phpbb_error_collector; - $collector->install(); - $this->db_connect_id = (!$new_link) ? @pg_pconnect($connect_string) : @pg_pconnect($connect_string, PGSQL_CONNECT_FORCE_NEW); - } - else - { - if (!function_exists('pg_connect')) - { - $this->connect_error = 'pg_connect function does not exist, is pgsql extension installed?'; - return $this->sql_error(''); - } - $collector = new phpbb_error_collector; - $collector->install(); - $this->db_connect_id = (!$new_link) ? @pg_connect($connect_string) : @pg_connect($connect_string, PGSQL_CONNECT_FORCE_NEW); - } - - $collector->uninstall(); - - if ($this->db_connect_id) - { - if (version_compare($this->sql_server_info(true), '8.2', '>=')) - { - $this->multi_insert = true; - } - - if ($schema !== '') - { - @pg_query($this->db_connect_id, 'SET search_path TO ' . $schema); - } - return $this->db_connect_id; - } - - $this->connect_error = $collector->format_errors(); - return $this->sql_error(''); - } - - /** - * Version information about used database - * @param bool $raw if true, only return the fetched sql_server_version - * @param bool $use_cache If true, it is safe to retrieve the value from the cache - * @return string sql server version - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('pgsql_version')) === false) - { - $query_id = @pg_query($this->db_connect_id, 'SELECT VERSION() AS version'); - $row = @pg_fetch_assoc($query_id, null); - @pg_free_result($query_id); - - $this->sql_server_version = (!empty($row['version'])) ? trim(substr($row['version'], 10)) : 0; - - if (!empty($cache) && $use_cache) - { - $cache->put('pgsql_version', $this->sql_server_version); - } - } - - return ($raw) ? $this->sql_server_version : 'PostgreSQL ' . $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @pg_query($this->db_connect_id, 'BEGIN'); - break; - - case 'commit': - return @pg_query($this->db_connect_id, 'COMMIT'); - break; - - case 'rollback': - return @pg_query($this->db_connect_id, 'ROLLBACK'); - break; - } - - return true; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->last_query_text = $query; - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - if (($this->query_result = @pg_query($this->db_connect_id, $query)) === false) - { - $this->sql_error($query); - } - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0 && $this->query_result) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - return $data; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // if $total is set to 0 we do not want to limit the number of rows - if ($total == 0) - { - $total = 'ALL'; - } - - $query .= "\n LIMIT $total OFFSET $offset"; - - return $this->sql_query($query, $cache_ttl); - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - return ($this->query_result) ? @pg_affected_rows($this->query_result) : false; - } - - /** - * Fetch current row - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - return ($query_id !== false) ? @pg_fetch_assoc($query_id, null) : false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - return ($query_id !== false) ? @pg_result_seek($query_id, $rownum) : false; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - $query_id = $this->query_result; - - if ($query_id !== false && $this->last_query_text != '') - { - if (preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $this->last_query_text, $tablename)) - { - $query = "SELECT currval('" . $tablename[1] . "_seq') AS last_value"; - $temp_q_id = @pg_query($this->db_connect_id, $query); - - if (!$temp_q_id) - { - return false; - } - - $temp_result = @pg_fetch_assoc($temp_q_id, NULL); - @pg_free_result($query_id); - - return ($temp_result) ? $temp_result['last_value'] : false; - } - } - - return false; - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - if (isset($this->open_queries[(int) $query_id])) - { - unset($this->open_queries[(int) $query_id]); - return @pg_free_result($query_id); - } - - return false; - } - - /** - * Escape string used in sql query - * Note: Do not use for bytea values if we may use them at a later stage - */ - function sql_escape($msg) - { - return @pg_escape_string($msg); - } - - /** - * Build LIKE expression - * @access private - */ - function _sql_like_expression($expression) - { - return $expression; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - // pg_last_error only works when there is an established connection. - // Connection errors have to be tracked by us manually. - if ($this->db_connect_id) - { - $message = @pg_last_error($this->db_connect_id); - } - else - { - $message = $this->connect_error; - } - - return array( - 'message' => $message, - 'code' => '' - ); - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @pg_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - if ($result = @pg_query($this->db_connect_id, "EXPLAIN $explain_query")) - { - while ($row = @pg_fetch_assoc($result, NULL)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - @pg_free_result($result); - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @pg_query($this->db_connect_id, $query); - while ($void = @pg_fetch_assoc($result, NULL)) - { - // Take the time spent on parsing rows into account - } - @pg_free_result($result); - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php deleted file mode 100644 index 557b057cce..0000000000 --- a/phpBB/includes/db/sqlite.php +++ /dev/null @@ -1,370 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -/** -* Sqlite Database Abstraction Layer -* Minimum Requirement: 2.8.2+ -* @package dbal -*/ -class dbal_sqlite extends dbal -{ - var $connect_error = ''; - - /** - * Connect to server - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) - { - $this->persistency = $persistency; - $this->user = $sqluser; - $this->server = $sqlserver . (($port) ? ':' . $port : ''); - $this->dbname = $database; - - $error = ''; - if ($this->persistency) - { - if (!function_exists('sqlite_popen')) - { - $this->connect_error = 'sqlite_popen function does not exist, is sqlite extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @sqlite_popen($this->server, 0666, $error); - } - else - { - if (!function_exists('sqlite_open')) - { - $this->connect_error = 'sqlite_open function does not exist, is sqlite extension installed?'; - return $this->sql_error(''); - } - $this->db_connect_id = @sqlite_open($this->server, 0666, $error); - } - - if ($this->db_connect_id) - { - @sqlite_query('PRAGMA short_column_names = 1', $this->db_connect_id); -// @sqlite_query('PRAGMA encoding = "UTF-8"', $this->db_connect_id); - } - - return ($this->db_connect_id) ? true : array('message' => $error); - } - - /** - * Version information about used database - * @param bool $raw if true, only return the fetched sql_server_version - * @param bool $use_cache if true, it is safe to retrieve the stored value from the cache - * @return string sql server version - */ - function sql_server_info($raw = false, $use_cache = true) - { - global $cache; - - if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false) - { - $result = @sqlite_query('SELECT sqlite_version() AS version', $this->db_connect_id); - $row = @sqlite_fetch_array($result, SQLITE_ASSOC); - - $this->sql_server_version = (!empty($row['version'])) ? $row['version'] : 0; - - if (!empty($cache) && $use_cache) - { - $cache->put('sqlite_version', $this->sql_server_version); - } - } - - return ($raw) ? $this->sql_server_version : 'SQLite ' . $this->sql_server_version; - } - - /** - * SQL Transaction - * @access private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @sqlite_query('BEGIN', $this->db_connect_id); - break; - - case 'commit': - return @sqlite_query('COMMIT', $this->db_connect_id); - break; - - case 'rollback': - return @sqlite_query('ROLLBACK', $this->db_connect_id); - break; - } - - return true; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if ($this->query_result === false) - { - if (($this->query_result = @sqlite_query($query, $this->db_connect_id)) === false) - { - $this->sql_error($query); - } - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0 && $this->query_result) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return $this->query_result; - } - - /** - * Build LIMIT query - */ - function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - $this->query_result = false; - - // if $total is set to 0 we do not want to limit the number of rows - if ($total == 0) - { - $total = -1; - } - - $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); - - return $this->sql_query($query, $cache_ttl); - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @sqlite_changes($this->db_connect_id) : false; - } - - /** - * Fetch current row - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - return ($query_id !== false) ? @sqlite_fetch_array($query_id, SQLITE_ASSOC) : false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, &$query_id) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($rownum, $query_id); - } - - return ($query_id !== false) ? @sqlite_seek($query_id, $rownum) : false; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - return ($this->db_connect_id) ? @sqlite_last_insert_rowid($this->db_connect_id) : false; - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if ($query_id === false) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - return true; - } - - /** - * Escape string used in sql query - */ - function sql_escape($msg) - { - return @sqlite_escape_string($msg); - } - - /** - * Correctly adjust LIKE expression for special characters - * For SQLite an underscore is a not-known character... this may change with SQLite3 - */ - function sql_like_expression($expression) - { - // Unlike LIKE, GLOB is case sensitive (unfortunatly). SQLite users need to live with it! - // We only catch * and ? here, not the character map possible on file globbing. - $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression); - - $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression); - $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression); - - return 'GLOB \'' . $this->sql_escape($expression) . '\''; - } - - /** - * return sql error array - * @access private - */ - function _sql_error() - { - if (function_exists('sqlite_error_string')) - { - $error = array( - 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)), - 'code' => @sqlite_last_error($this->db_connect_id), - ); - } - else - { - $error = array( - 'message' => $this->connect_error, - 'code' => '', - ); - } - - return $error; - } - - /** - * Build db-specific query data - * @access private - */ - function _sql_custom_build($stage, $data) - { - return $data; - } - - /** - * Close sql connection - * @access private - */ - function _sql_close() - { - return @sqlite_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @sqlite_query($query, $this->db_connect_id); - while ($void = @sqlite_fetch_array($result, SQLITE_ASSOC)) - { - // Take the time spent on parsing rows into account - } - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/diff/diff.php b/phpBB/includes/diff/diff.php index 60af574b78..d307880c4b 100644 --- a/phpBB/includes/diff/diff.php +++ b/phpBB/includes/diff/diff.php @@ -1,10 +1,13 @@ <?php /** * -* @package diff -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -20,7 +23,7 @@ if (!defined('IN_PHPBB')) * Code from pear.php.net, Text_Diff-1.1.0 package * http://pear.php.net/package/Text_Diff/ * -* Modified by phpBB Group to meet our coding standards +* Modified by phpBB Limited to meet our coding standards * and being able to integrate into phpBB * * General API for generating and formatting diffs - the differences between @@ -43,8 +46,9 @@ class diff /** * Computes diffs between sequences of strings. * - * @param array $from_lines An array of strings. Typically these are lines from a file. - * @param array $to_lines An array of strings. + * @param array &$from_content An array of strings. Typically these are lines from a file. + * @param array &$to_content An array of strings. + * @param bool $preserve_cr If true, \r is replaced by a new line in the diff output */ function diff(&$from_content, &$to_content, $preserve_cr = true) { @@ -488,9 +492,11 @@ class diff3 extends diff /** * Computes diff between 3 sequences of strings. * - * @param array $orig The original lines to use. - * @param array $final1 The first version to compare to. - * @param array $final2 The second version to compare to. + * @param array &$orig The original lines to use. + * @param array &$final1 The first version to compare to. + * @param array &$final2 The second version to compare to. + * @param bool $preserve_cr If true, \r\n and bare \r are replaced by a new line + * in the diff output */ function diff3(&$orig, &$final1, &$final2, $preserve_cr = true) { @@ -1144,5 +1150,3 @@ class diff3_block_builder array_splice($array, sizeof($array), 0, $lines); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/diff/engine.php b/phpBB/includes/diff/engine.php index 982149457d..bc21b3b9ba 100644 --- a/phpBB/includes/diff/engine.php +++ b/phpBB/includes/diff/engine.php @@ -1,10 +1,13 @@ <?php /** * -* @package diff -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -20,7 +23,7 @@ if (!defined('IN_PHPBB')) * Code from pear.php.net, Text_Diff-1.1.0 package * http://pear.php.net/package/Text_Diff/ (native engine) * -* Modified by phpBB Group to meet our coding standards +* Modified by phpBB Limited to meet our coding standards * and being able to integrate into phpBB * * Class used internally by Text_Diff to actually compute the diffs. This @@ -550,5 +553,3 @@ class diff_engine } } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/diff/renderer.php b/phpBB/includes/diff/renderer.php index 5cb1b6ada9..6b7f07cf9c 100644 --- a/phpBB/includes/diff/renderer.php +++ b/phpBB/includes/diff/renderer.php @@ -1,10 +1,13 @@ <?php /** * -* @package diff -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -20,7 +23,7 @@ if (!defined('IN_PHPBB')) * Code from pear.php.net, Text_Diff-1.1.0 package * http://pear.php.net/package/Text_Diff/ * -* Modified by phpBB Group to meet our coding standards +* Modified by phpBB Limited to meet our coding standards * and being able to integrate into phpBB * * A class to render Diffs in different formats. @@ -856,5 +859,3 @@ class diff_renderer_side_by_side extends diff_renderer } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/error_collector.php b/phpBB/includes/error_collector.php deleted file mode 100644 index 3c0a89a1f3..0000000000 --- a/phpBB/includes/error_collector.php +++ /dev/null @@ -1,63 +0,0 @@ -<?php -/** -* -* @package phpBB -* @version $Id$ -* @copyright (c) 2011 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -class phpbb_error_collector -{ - var $errors; - - function phpbb_error_collector() - { - $this->errors = array(); - } - - function install() - { - set_error_handler(array(&$this, 'error_handler')); - } - - function uninstall() - { - restore_error_handler(); - } - - function error_handler($errno, $msg_text, $errfile, $errline) - { - $this->errors[] = array($errno, $msg_text, $errfile, $errline); - } - - function format_errors() - { - $text = ''; - foreach ($this->errors as $error) - { - if (!empty($text)) - { - $text .= "<br />\n"; - } - - list($errno, $msg_text, $errfile, $errline) = $error; - - // Prevent leakage of local path to phpBB install - $errfile = phpbb_filter_root_path($errfile); - - $text .= "Errno $errno: $msg_text at $errfile line $errline"; - } - - return $text; - } -} diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index f2bc63cf23..e00231c360 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -17,123 +20,113 @@ if (!defined('IN_PHPBB')) } // Common global functions - /** -* set_var +* Load the autoloaders added by the extensions. * -* Set variable, used by {@link request_var the request_var function} -* -* @access private +* @param string $phpbb_root_path Path to the phpbb root directory. */ -function set_var(&$result, $var, $type, $multibyte = false) +function phpbb_load_extensions_autoloaders($phpbb_root_path) { - settype($var, $type); - $result = $var; + $iterator = new \RecursiveIteratorIterator( + new \phpbb\recursive_dot_prefix_filter_iterator( + new \RecursiveDirectoryIterator( + $phpbb_root_path . 'ext/', + \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS + ) + ), + \RecursiveIteratorIterator::SELF_FIRST + ); + $iterator->setMaxDepth(2); - if ($type == 'string') + foreach ($iterator as $file_info) { - $result = trim(htmlspecialchars(str_replace(array("\r\n", "\r", "\0"), array("\n", "\n", ''), $result), ENT_COMPAT, 'UTF-8')); - - if (!empty($result)) + if ($file_info->getFilename() === 'vendor' && $iterator->getDepth() === 2) { - // Make sure multibyte characters are wellformed - if ($multibyte) + $filename = $file_info->getRealPath() . '/autoload.php'; + if (file_exists($filename)) { - if (!preg_match('/^./u', $result)) - { - $result = ''; - } - } - else - { - // no multibyte, allow only ASCII (0-127) - $result = preg_replace('/[\x80-\xFF]/', '?', $result); + require $filename; } } - - $result = (STRIP) ? stripslashes($result) : $result; } } /** -* request_var +* Casts a variable to the given type. * -* Used to get passed variable +* @deprecated */ -function request_var($var_name, $default, $multibyte = false, $cookie = false) +function set_var(&$result, $var, $type, $multibyte = false) { - if (!$cookie && isset($_COOKIE[$var_name])) - { - if (!isset($_GET[$var_name]) && !isset($_POST[$var_name])) - { - return (is_array($default)) ? array() : $default; - } - $_REQUEST[$var_name] = isset($_POST[$var_name]) ? $_POST[$var_name] : $_GET[$var_name]; - } + // no need for dependency injection here, if you have the object, call the method yourself! + $type_cast_helper = new \phpbb\request\type_cast_helper(); + $type_cast_helper->set_var($result, $var, $type, $multibyte); +} - $super_global = ($cookie) ? '_COOKIE' : '_REQUEST'; - if (!isset($GLOBALS[$super_global][$var_name]) || is_array($GLOBALS[$super_global][$var_name]) != is_array($default)) - { - return (is_array($default)) ? array() : $default; - } +/** +* Wrapper function of \phpbb\request\request::variable which exists for backwards compatability. +* See {@link \phpbb\request\request_interface::variable \phpbb\request\request_interface::variable} for +* documentation of this function's use. +* +* @deprecated +* @param mixed $var_name The form variable's name from which data shall be retrieved. +* If the value is an array this may be an array of indizes which will give +* direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a") +* then specifying array("var", 1) as the name will return "a". +* If you pass an instance of {@link \phpbb\request\request_interface phpbb_request_interface} +* as this parameter it will overwrite the current request class instance. If you do +* not do so, it will create its own instance (but leave superglobals enabled). +* @param mixed $default A default value that is returned if the variable was not set. +* This function will always return a value of the same type as the default. +* @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters +* Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks +* @param bool $cookie This param is mapped to \phpbb\request\request_interface::COOKIE as the last param for +* \phpbb\request\request_interface::variable for backwards compatability reasons. +* @param \phpbb\request\request_interface|null|false If an instance of \phpbb\request\request_interface is given the instance is stored in +* a static variable and used for all further calls where this parameters is null. Until +* the function is called with an instance it automatically creates a new \phpbb\request\request +* instance on every call. By passing false this per-call instantiation can be restored +* after having passed in a \phpbb\request\request_interface instance. +* +* @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the +* the same as that of $default. If the variable is not set $default is returned. +*/ +function request_var($var_name, $default, $multibyte = false, $cookie = false, $request = null) +{ + // This is all just an ugly hack to add "Dependency Injection" to a function + // the only real code is the function call which maps this function to a method. + static $static_request = null; - $var = $GLOBALS[$super_global][$var_name]; - if (!is_array($default)) - { - $type = gettype($default); - } - else + if ($request instanceof \phpbb\request\request_interface) { - list($key_type, $type) = each($default); - $type = gettype($type); - $key_type = gettype($key_type); - if ($type == 'array') + $static_request = $request; + + if (empty($var_name)) { - reset($default); - $default = current($default); - list($sub_key_type, $sub_type) = each($default); - $sub_type = gettype($sub_type); - $sub_type = ($sub_type == 'array') ? 'NULL' : $sub_type; - $sub_key_type = gettype($sub_key_type); + return; } } - - if (is_array($var)) + else if ($request === false) { - $_var = $var; - $var = array(); + $static_request = null; - foreach ($_var as $k => $v) + if (empty($var_name)) { - set_var($k, $k, $key_type); - if ($type == 'array' && is_array($v)) - { - foreach ($v as $_k => $_v) - { - if (is_array($_v)) - { - $_v = null; - } - set_var($_k, $_k, $sub_key_type, $multibyte); - set_var($var[$k][$_k], $_v, $sub_type, $multibyte); - } - } - else - { - if ($type == 'array' || is_array($v)) - { - $v = null; - } - set_var($var[$k], $v, $type, $multibyte); - } + return; } } - else + + $tmp_request = $static_request; + + // no request class set, create a temporary one ourselves to keep backwards compatability + if ($tmp_request === null) { - set_var($var, $var, $type, $multibyte); + // false param: enable super globals, so the created request class does not + // make super globals inaccessible everywhere outside this function. + $tmp_request = new \phpbb\request\request(new \phpbb\request\type_cast_helper(), false); } - return $var; + return $tmp_request->variable($var_name, $default, $multibyte, ($cookie) ? \phpbb\request\request_interface::COOKIE : \phpbb\request\request_interface::REQUEST); } /** @@ -149,31 +142,24 @@ function request_var($var_name, $default, $multibyte = false, $cookie = false) * efficiently cached. * * @return null +* +* @deprecated */ -function set_config($config_name, $config_value, $is_dynamic = false) +function set_config($config_name, $config_value, $is_dynamic = false, \phpbb\config\config $set_config = null) { - global $db, $cache, $config; + static $config = null; - $sql = 'UPDATE ' . CONFIG_TABLE . " - SET config_value = '" . $db->sql_escape($config_value) . "' - WHERE config_name = '" . $db->sql_escape($config_name) . "'"; - $db->sql_query($sql); - - if (!$db->sql_affectedrows() && !isset($config[$config_name])) + if ($set_config !== null) { - $sql = 'INSERT INTO ' . CONFIG_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'config_name' => $config_name, - 'config_value' => $config_value, - 'is_dynamic' => ($is_dynamic) ? 1 : 0)); - $db->sql_query($sql); - } - - $config[$config_name] = $config_value; + $config = $set_config; - if (!$is_dynamic) - { - $cache->destroy('config'); + if (empty($config_name)) + { + return; + } } + + $config->set($config_name, $config_value, !$is_dynamic); } /** @@ -186,35 +172,24 @@ function set_config($config_name, $config_value, $is_dynamic = false) * efficiently cached. * * @return null +* +* @deprecated */ -function set_config_count($config_name, $increment, $is_dynamic = false) +function set_config_count($config_name, $increment, $is_dynamic = false, \phpbb\config\config $set_config = null) { - global $db, $cache; + static $config = null; - switch ($db->sql_layer) + if ($set_config !== null) { - case 'firebird': - // Precision must be from 1 to 18 - $sql_update = 'CAST(CAST(config_value as DECIMAL(18, 0)) + ' . (int) $increment . ' as VARCHAR(255))'; - break; - - case 'postgres': - // Need to cast to text first for PostgreSQL 7.x - $sql_update = 'CAST(CAST(config_value::text as DECIMAL(255, 0)) + ' . (int) $increment . ' as VARCHAR(255))'; - break; + $config = $set_config; - // MySQL, SQlite, mssql, mssql_odbc, oracle - default: - $sql_update = 'config_value + ' . (int) $increment; - break; + if (empty($config_name)) + { + return; + } } - $db->sql_query('UPDATE ' . CONFIG_TABLE . ' SET config_value = ' . $sql_update . " WHERE config_name = '" . $db->sql_escape($config_name) . "'"); - - if (!$is_dynamic) - { - $cache->destroy('config'); - } + $config->increment($config_name, $increment, !$is_dynamic); } /** @@ -314,7 +289,6 @@ function phpbb_gmgetdate($time = false) * @param array $allowed_units only allow these units (data array indexes) * * @return mixed data array if $string_only is false -* @author bantu */ function get_formatted_filesize($value, $string_only = true, $allowed_units = false) { @@ -428,219 +402,6 @@ function still_on_time($extra_time = 15) } /** -* -* @version Version 0.1 / slightly modified for phpBB 3.0.x (using $H$ as hash type identifier) -* -* Portable PHP password hashing framework. -* -* Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in -* the public domain. -* -* There's absolutely no warranty. -* -* The homepage URL for this framework is: -* -* http://www.openwall.com/phpass/ -* -* Please be sure to update the Version line if you edit this file in any way. -* It is suggested that you leave the main version number intact, but indicate -* your project name (after the slash) and add your own revision information. -* -* Please do not change the "private" password hashing method implemented in -* here, thereby making your hashes incompatible. However, if you must, please -* change the hash type identifier (the "$P$") to something different. -* -* Obviously, since this code is in the public domain, the above are not -* requirements (there can be none), but merely suggestions. -* -* -* Hash the password -*/ -function phpbb_hash($password) -{ - $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - - $random_state = unique_id(); - $random = ''; - $count = 6; - - if (($fh = @fopen('/dev/urandom', 'rb'))) - { - $random = fread($fh, $count); - fclose($fh); - } - - if (strlen($random) < $count) - { - $random = ''; - - for ($i = 0; $i < $count; $i += 16) - { - $random_state = md5(unique_id() . $random_state); - $random .= pack('H*', md5($random_state)); - } - $random = substr($random, 0, $count); - } - - $hash = _hash_crypt_private($password, _hash_gensalt_private($random, $itoa64), $itoa64); - - if (strlen($hash) == 34) - { - return $hash; - } - - return md5($password); -} - -/** -* Check for correct password -* -* @param string $password The password in plain text -* @param string $hash The stored password hash -* -* @return bool Returns true if the password is correct, false if not. -*/ -function phpbb_check_hash($password, $hash) -{ - if (strlen($password) > 4096) - { - // If the password is too huge, we will simply reject it - // and not let the server try to hash it. - return false; - } - - $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - if (strlen($hash) == 34) - { - return (_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false; - } - - return (md5($password) === $hash) ? true : false; -} - -/** -* Generate salt for hash generation -*/ -function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6) -{ - if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) - { - $iteration_count_log2 = 8; - } - - $output = '$H$'; - $output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)]; - $output .= _hash_encode64($input, 6, $itoa64); - - return $output; -} - -/** -* Encode hash -*/ -function _hash_encode64($input, $count, &$itoa64) -{ - $output = ''; - $i = 0; - - do - { - $value = ord($input[$i++]); - $output .= $itoa64[$value & 0x3f]; - - if ($i < $count) - { - $value |= ord($input[$i]) << 8; - } - - $output .= $itoa64[($value >> 6) & 0x3f]; - - if ($i++ >= $count) - { - break; - } - - if ($i < $count) - { - $value |= ord($input[$i]) << 16; - } - - $output .= $itoa64[($value >> 12) & 0x3f]; - - if ($i++ >= $count) - { - break; - } - - $output .= $itoa64[($value >> 18) & 0x3f]; - } - while ($i < $count); - - return $output; -} - -/** -* The crypt function/replacement -*/ -function _hash_crypt_private($password, $setting, &$itoa64) -{ - $output = '*'; - - // Check for correct hash - if (substr($setting, 0, 3) != '$H$' && substr($setting, 0, 3) != '$P$') - { - return $output; - } - - $count_log2 = strpos($itoa64, $setting[3]); - - if ($count_log2 < 7 || $count_log2 > 30) - { - return $output; - } - - $count = 1 << $count_log2; - $salt = substr($setting, 4, 8); - - if (strlen($salt) != 8) - { - return $output; - } - - /** - * We're kind of forced to use MD5 here since it's the only - * cryptographic primitive available in all versions of PHP - * currently in use. To implement our own low-level crypto - * in PHP would result in much worse performance and - * consequently in lower iteration counts and hashes that are - * quicker to crack (by non-PHP code). - */ - if (PHP_VERSION >= 5) - { - $hash = md5($salt . $password, true); - do - { - $hash = md5($hash . $password, true); - } - while (--$count); - } - else - { - $hash = pack('H*', md5($salt . $password)); - do - { - $hash = pack('H*', md5($hash . $password)); - } - while (--$count); - } - - $output = substr($setting, 0, 12); - $output .= _hash_encode64($hash, 16, $itoa64); - - return $output; -} - -/** * Hashes an email address to a big integer * * @param string $email Email address @@ -701,7 +462,6 @@ function phpbb_version_compare($version1, $version2, $operator = null) * @param int $perms Permissions to set * * @return bool true on success, otherwise false -* @author faw, phpBB Group */ function phpbb_chmod($filename, $perms = CHMOD_READ) { @@ -915,102 +675,13 @@ function phpbb_is_writable($file) } } -// Compatibility functions - -if (!function_exists('array_combine')) -{ - /** - * A wrapper for the PHP5 function array_combine() - * @param array $keys contains keys for the resulting array - * @param array $values contains values for the resulting array - * - * @return Returns an array by using the values from the keys array as keys and the - * values from the values array as the corresponding values. Returns false if the - * number of elements for each array isn't equal or if the arrays are empty. - */ - function array_combine($keys, $values) - { - $keys = array_values($keys); - $values = array_values($values); - - $n = sizeof($keys); - $m = sizeof($values); - if (!$n || !$m || ($n != $m)) - { - return false; - } - - $combined = array(); - for ($i = 0; $i < $n; $i++) - { - $combined[$keys[$i]] = $values[$i]; - } - return $combined; - } -} - -if (!function_exists('str_split')) -{ - /** - * A wrapper for the PHP5 function str_split() - * @param array $string contains the string to be converted - * @param array $split_length contains the length of each chunk - * - * @return Converts a string to an array. If the optional split_length parameter is specified, - * the returned array will be broken down into chunks with each being split_length in length, - * otherwise each chunk will be one character in length. FALSE is returned if split_length is - * less than 1. If the split_length length exceeds the length of string, the entire string is - * returned as the first (and only) array element. - */ - function str_split($string, $split_length = 1) - { - if ($split_length < 1) - { - return false; - } - else if ($split_length >= strlen($string)) - { - return array($string); - } - else - { - preg_match_all('#.{1,' . $split_length . '}#s', $string, $matches); - return $matches[0]; - } - } -} - -if (!function_exists('stripos')) -{ - /** - * A wrapper for the PHP5 function stripos - * Find position of first occurrence of a case-insensitive string - * - * @param string $haystack is the string to search in - * @param string $needle is the string to search for - * - * @return mixed Returns the numeric position of the first occurrence of needle in the haystack string. Unlike strpos(), stripos() is case-insensitive. - * Note that the needle may be a string of one or more characters. - * If needle is not found, stripos() will return boolean FALSE. - */ - function stripos($haystack, $needle) - { - if (preg_match('#' . preg_quote($needle, '#') . '#i', $haystack, $m)) - { - return strpos($haystack, $m[0]); - } - - return false; - } -} - /** * Checks if a path ($path) is absolute or relative * * @param string $path Path to check absoluteness of * @return boolean */ -function is_absolute($path) +function phpbb_is_absolute($path) { return (isset($path[0]) && $path[0] == '/' || preg_match('#^[a-z]:[/\\\]#i', $path)) ? true : false; } @@ -1023,6 +694,8 @@ function is_absolute($path) */ function phpbb_own_realpath($path) { + global $request; + // Now to perform funky shizzle // Switch to use UNIX slashes @@ -1030,7 +703,7 @@ function phpbb_own_realpath($path) $path_prefix = ''; // Determine what sort of path we have - if (is_absolute($path)) + if (phpbb_is_absolute($path)) { $absolute = true; @@ -1066,11 +739,12 @@ function phpbb_own_realpath($path) $path_prefix = ''; } } - else if (isset($_SERVER['SCRIPT_FILENAME']) && !empty($_SERVER['SCRIPT_FILENAME'])) + else if ($request->server('SCRIPT_FILENAME')) { // Warning: If chdir() has been used this will lie! // Warning: This has some problems sometime (CLI can create them easily) - $path = str_replace(DIRECTORY_SEPARATOR, '/', dirname($_SERVER['SCRIPT_FILENAME'])) . '/' . $path; + $filename = htmlspecialchars_decode($request->server('SCRIPT_FILENAME')); + $path = str_replace(DIRECTORY_SEPARATOR, '/', dirname($filename)) . '/' . $path; $absolute = true; $path_prefix = ''; } @@ -1209,48 +883,6 @@ else } } -/** -* Eliminates useless . and .. components from specified path. -* -* @param string $path Path to clean -* @return string Cleaned path -*/ -function phpbb_clean_path($path) -{ - $exploded = explode('/', $path); - $filtered = array(); - foreach ($exploded as $part) - { - if ($part === '.' && !empty($filtered)) - { - continue; - } - - if ($part === '..' && !empty($filtered) && $filtered[sizeof($filtered) - 1] !== '..') - { - array_pop($filtered); - } - else - { - $filtered[] = $part; - } - } - $path = implode('/', $filtered); - return $path; -} - -if (!function_exists('htmlspecialchars_decode')) -{ - /** - * A wrapper for htmlspecialchars_decode - * @ignore - */ - function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT) - { - return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style))); - } -} - // functions used for building option fields /** @@ -1302,30 +934,203 @@ function style_select($default = '', $all = false) } /** -* Pick a timezone +* Format the timezone offset with hours and minutes +* +* @param int $tz_offset Timezone offset in seconds +* @param bool $show_null Whether null offsets should be shown +* @return string Normalized offset string: -7200 => -02:00 +* 16200 => +04:30 */ -function tz_select($default = '', $truncate = false) +function phpbb_format_timezone_offset($tz_offset, $show_null = false) { - global $user; + $sign = ($tz_offset < 0) ? '-' : '+'; + $time_offset = abs($tz_offset); - $tz_select = ''; - foreach ($user->lang['tz_zones'] as $offset => $zone) + if ($time_offset == 0 && $show_null == false) { - if ($truncate) + return ''; + } + + $offset_seconds = $time_offset % 3600; + $offset_minutes = $offset_seconds / 60; + $offset_hours = ($time_offset - $offset_seconds) / 3600; + + $offset_string = sprintf("%s%02d:%02d", $sign, $offset_hours, $offset_minutes); + return $offset_string; +} + +/** +* Compares two time zone labels. +* Arranges them in increasing order by timezone offset. +* Places UTC before other timezones in the same offset. +*/ +function phpbb_tz_select_compare($a, $b) +{ + $a_sign = $a[3]; + $b_sign = $b[3]; + if ($a_sign != $b_sign) + { + return $a_sign == '-' ? -1 : 1; + } + + $a_offset = substr($a, 4, 5); + $b_offset = substr($b, 4, 5); + if ($a_offset == $b_offset) + { + $a_name = substr($a, 12); + $b_name = substr($b, 12); + if ($a_name == $b_name) + { + return 0; + } + else if ($a_name == 'UTC') { - $zone_trunc = truncate_string($zone, 50, 255, false, '...'); + return -1; + } + else if ($b_name == 'UTC') + { + return 1; } else { - $zone_trunc = $zone; + return $a_name < $b_name ? -1 : 1; + } + } + else + { + if ($a_sign == '-') + { + return $a_offset > $b_offset ? -1 : 1; + } + else + { + return $a_offset < $b_offset ? -1 : 1; + } + } +} + +/** +* Return list of timezone identifiers +* We also add the selected timezone if we can create an object with it. +* DateTimeZone::listIdentifiers seems to not add all identifiers to the list, +* because some are only kept for backward compatible reasons. If the user has +* a deprecated value, we add it here, so it can still be kept. Once the user +* changed his value, there is no way back to deprecated values. +* +* @param string $selected_timezone Additional timezone that shall +* be added to the list of identiers +* @return array DateTimeZone::listIdentifiers and additional +* selected_timezone if it is a valid timezone. +*/ +function phpbb_get_timezone_identifiers($selected_timezone) +{ + $timezones = DateTimeZone::listIdentifiers(); + + if (!in_array($selected_timezone, $timezones)) + { + try + { + // Add valid timezones that are currently selected but not returned + // by DateTimeZone::listIdentifiers + $validate_timezone = new DateTimeZone($selected_timezone); + $timezones[] = $selected_timezone; + } + catch (\Exception $e) + { + } + } + + return $timezones; +} + +/** +* Options to pick a timezone and date/time +* +* @param \phpbb\template\template $template phpBB template object +* @param \phpbb\user $user Object of the current user +* @param string $default A timezone to select +* @param boolean $truncate Shall we truncate the options text +* +* @return array Returns an array containing the options for the time selector. +*/ +function phpbb_timezone_select($template, $user, $default = '', $truncate = false) +{ + static $timezones; + + $default_offset = ''; + if (!isset($timezones)) + { + $unsorted_timezones = phpbb_get_timezone_identifiers($default); + + $timezones = array(); + foreach ($unsorted_timezones as $timezone) + { + $tz = new DateTimeZone($timezone); + $dt = $user->create_datetime('now', $tz); + $offset = $dt->getOffset(); + $current_time = $dt->format($user->lang['DATETIME_FORMAT'], true); + $offset_string = phpbb_format_timezone_offset($offset, true); + $timezones['UTC' . $offset_string . ' - ' . $timezone] = array( + 'tz' => $timezone, + 'offset' => $offset_string, + 'current' => $current_time, + ); + if ($timezone === $default) + { + $default_offset = 'UTC' . $offset_string; + } } + unset($unsorted_timezones); - if (is_numeric($offset)) + uksort($timezones, 'phpbb_tz_select_compare'); + } + + $tz_select = $opt_group = ''; + + foreach ($timezones as $key => $timezone) + { + if ($opt_group != $timezone['offset']) + { + // Generate tz_select for backwards compatibility + $tz_select .= ($opt_group) ? '</optgroup>' : ''; + $tz_select .= '<optgroup label="' . $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $timezone['current']) . '">'; + $opt_group = $timezone['offset']; + $template->assign_block_vars('timezone_select', array( + 'LABEL' => $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $timezone['current']), + 'VALUE' => $key . ' - ' . $timezone['current'], + )); + + $selected = (!empty($default_offset) && strpos($key, $default_offset) !== false) ? ' selected="selected"' : ''; + $template->assign_block_vars('timezone_date', array( + 'VALUE' => $key . ' - ' . $timezone['current'], + 'SELECTED' => !empty($selected), + 'TITLE' => $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $timezone['current']), + )); + } + + $label = $timezone['tz']; + if (isset($user->lang['timezones'][$label])) + { + $label = $user->lang['timezones'][$label]; + } + $title = $user->lang(array('timezones', 'UTC_OFFSET_CURRENT'), $timezone['offset'], $label); + + if ($truncate) { - $selected = ($offset == $default) ? ' selected="selected"' : ''; - $tz_select .= '<option title="' . $zone . '" value="' . $offset . '"' . $selected . '>' . $zone_trunc . '</option>'; + $label = truncate_string($label, 50, 255, false, '...'); } + + // Also generate timezone_select for backwards compatibility + $selected = ($timezone['tz'] === $default) ? ' selected="selected"' : ''; + $tz_select .= '<option title="' . $title . '" value="' . $timezone['tz'] . '"' . $selected . '>' . $label . '</option>'; + $template->assign_block_vars('timezone_select.timezone_options', array( + 'TITLE' => $title, + 'VALUE' => $timezone['tz'], + 'SELECTED' => !empty($selected), + 'LABEL' => $label, + )); } + $tz_select .= '</optgroup>'; return $tz_select; } @@ -1336,41 +1141,110 @@ function tz_select($default = '', $truncate = false) * Marks a topic/forum as read * Marks a topic as posted to * +* @param string $mode (all, topics, topic, post) +* @param int|bool $forum_id Used in all, topics, and topic mode +* @param int|bool $topic_id Used in topic and post mode +* @param int $post_time 0 means current time(), otherwise to set a specific mark time * @param int $user_id can only be used with $mode == 'post' */ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0) { global $db, $user, $config; + global $request, $phpbb_container, $phpbb_dispatcher; + + $post_time = ($post_time === 0 || $post_time > time()) ? time() : (int) $post_time; + + $should_markread = true; + + /** + * This event is used for performing actions directly before marking forums, + * topics or posts as read. + * + * It is also possible to prevent the marking. For that, the $should_markread parameter + * should be set to FALSE. + * + * @event core.markread_before + * @var string mode Variable containing marking mode value + * @var mixed forum_id Variable containing forum id, or false + * @var mixed topic_id Variable containing topic id, or false + * @var int post_time Variable containing post time + * @var int user_id Variable containing the user id + * @var bool should_markread Flag indicating if the markread should be done or not. + * @since 3.1.4-RC1 + */ + $vars = array( + 'mode', + 'forum_id', + 'topic_id', + 'post_time', + 'user_id', + 'should_markread', + ); + extract($phpbb_dispatcher->trigger_event('core.markread_before', compact($vars))); + + if (!$should_markread) + { + return; + } if ($mode == 'all') { if ($forum_id === false || !sizeof($forum_id)) { + // Mark all forums read (index page) + + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + // Mark all topic notifications read for this user + $phpbb_notifications->mark_notifications_read(array( + 'notification.type.topic', + 'notification.type.quote', + 'notification.type.bookmark', + 'notification.type.post', + 'notification.type.approve_topic', + 'notification.type.approve_post', + ), false, $user->data['user_id'], $post_time); + if ($config['load_db_lastread'] && $user->data['is_registered']) { // Mark all forums read (index page) - $db->sql_query('DELETE FROM ' . TOPICS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']}"); - $db->sql_query('DELETE FROM ' . FORUMS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']}"); - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}"); + $tables = array(TOPICS_TRACK_TABLE, FORUMS_TRACK_TABLE); + foreach ($tables as $table) + { + $sql = 'DELETE FROM ' . $table . " + WHERE user_id = {$user->data['user_id']} + AND mark_time < $post_time"; + $db->sql_query($sql); + } + + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_lastmark = $post_time + WHERE user_id = {$user->data['user_id']} + AND user_lastmark < $post_time"; + $db->sql_query($sql); } else if ($config['load_anon_lastread'] || $user->data['is_registered']) { - $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : ''; + $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); unset($tracking_topics['tf']); unset($tracking_topics['t']); unset($tracking_topics['f']); - $tracking_topics['l'] = base_convert(time() - $config['board_startdate'], 10, 36); + $tracking_topics['l'] = base_convert($post_time - $config['board_startdate'], 10, 36); - $user->set_cookie('track', tracking_serialize($tracking_topics), time() + 31536000); - $_COOKIE[$config['cookie_name'] . '_track'] = (STRIP) ? addslashes(tracking_serialize($tracking_topics)) : tracking_serialize($tracking_topics); + $user->set_cookie('track', tracking_serialize($tracking_topics), $post_time + 31536000); + $request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking_topics), \phpbb\request\request_interface::COOKIE); unset($tracking_topics); if ($user->data['is_registered']) { - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . time() . " WHERE user_id = {$user->data['user_id']}"); + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_lastmark = $post_time + WHERE user_id = {$user->data['user_id']} + AND user_lastmark < $post_time"; + $db->sql_query($sql); } } } @@ -1385,6 +1259,32 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ $forum_id = array($forum_id); } + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + $phpbb_notifications->mark_notifications_read_by_parent(array( + 'notification.type.topic', + 'notification.type.approve_topic', + ), $forum_id, $user->data['user_id'], $post_time); + + // Mark all post/quote notifications read for this user in this forum + $topic_ids = array(); + $sql = 'SELECT topic_id + FROM ' . TOPICS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $forum_id); + $result = $db->sql_query($sql); + while ($row = $db->sql_fetchrow($result)) + { + $topic_ids[] = $row['topic_id']; + } + $db->sql_freeresult($result); + + $phpbb_notifications->mark_notifications_read_by_parent(array( + 'notification.type.quote', + 'notification.type.bookmark', + 'notification.type.post', + 'notification.type.approve_post', + ), $topic_ids, $user->data['user_id'], $post_time); + // Add 0 to forums array to mark global announcements correctly // $forum_id[] = 0; @@ -1392,6 +1292,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ { $sql = 'DELETE FROM ' . TOPICS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']} + AND mark_time < $post_time AND " . $db->sql_in_set('forum_id', $forum_id); $db->sql_query($sql); @@ -1410,9 +1311,10 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ if (sizeof($sql_update)) { - $sql = 'UPDATE ' . FORUMS_TRACK_TABLE . ' - SET mark_time = ' . time() . " + $sql = 'UPDATE ' . FORUMS_TRACK_TABLE . " + SET mark_time = $post_time WHERE user_id = {$user->data['user_id']} + AND mark_time < $post_time AND " . $db->sql_in_set('forum_id', $sql_update); $db->sql_query($sql); } @@ -1425,7 +1327,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ $sql_ary[] = array( 'user_id' => (int) $user->data['user_id'], 'forum_id' => (int) $f_id, - 'mark_time' => time() + 'mark_time' => $post_time, ); } @@ -1434,7 +1336,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ } else if ($config['load_anon_lastread'] || $user->data['is_registered']) { - $tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : ''; + $tracking = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); $tracking = ($tracking) ? tracking_unserialize($tracking) : array(); foreach ($forum_id as $f_id) @@ -1456,7 +1358,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ unset($tracking['f'][$f_id]); } - $tracking['f'][$f_id] = base_convert(time() - $config['board_startdate'], 10, 36); + $tracking['f'][$f_id] = base_convert($post_time - $config['board_startdate'], 10, 36); } if (isset($tracking['tf']) && empty($tracking['tf'])) @@ -1464,8 +1366,8 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ unset($tracking['tf']); } - $user->set_cookie('track', tracking_serialize($tracking), time() + 31536000); - $_COOKIE[$config['cookie_name'] . '_track'] = (STRIP) ? addslashes(tracking_serialize($tracking)) : tracking_serialize($tracking); + $user->set_cookie('track', tracking_serialize($tracking), $post_time + 31536000); + $request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking), \phpbb\request\request_interface::COOKIE); unset($tracking); } @@ -1479,11 +1381,27 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ return; } + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + // Mark post notifications read for this user in this topic + $phpbb_notifications->mark_notifications_read(array( + 'notification.type.topic', + 'notification.type.approve_topic', + ), $topic_id, $user->data['user_id'], $post_time); + + $phpbb_notifications->mark_notifications_read_by_parent(array( + 'notification.type.quote', + 'notification.type.bookmark', + 'notification.type.post', + 'notification.type.approve_post', + ), $topic_id, $user->data['user_id'], $post_time); + if ($config['load_db_lastread'] && $user->data['is_registered']) { - $sql = 'UPDATE ' . TOPICS_TRACK_TABLE . ' - SET mark_time = ' . (($post_time) ? $post_time : time()) . " + $sql = 'UPDATE ' . TOPICS_TRACK_TABLE . " + SET mark_time = $post_time WHERE user_id = {$user->data['user_id']} + AND mark_time < $post_time AND topic_id = $topic_id"; $db->sql_query($sql); @@ -1496,7 +1414,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ 'user_id' => (int) $user->data['user_id'], 'topic_id' => (int) $topic_id, 'forum_id' => (int) $forum_id, - 'mark_time' => ($post_time) ? (int) $post_time : time(), + 'mark_time' => $post_time, ); $db->sql_query('INSERT INTO ' . TOPICS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); @@ -1506,7 +1424,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ } else if ($config['load_anon_lastread'] || $user->data['is_registered']) { - $tracking = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : ''; + $tracking = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); $tracking = ($tracking) ? tracking_unserialize($tracking) : array(); $topic_id36 = base_convert($topic_id, 10, 36); @@ -1516,12 +1434,11 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ $tracking['tf'][$forum_id][$topic_id36] = true; } - $post_time = ($post_time) ? $post_time : time(); $tracking['t'][$topic_id36] = base_convert($post_time - $config['board_startdate'], 10, 36); // If the cookie grows larger than 10000 characters we will remove the smallest value // This can result in old topics being unread - but most of the time it should be accurate... - if (isset($_COOKIE[$config['cookie_name'] . '_track']) && strlen($_COOKIE[$config['cookie_name'] . '_track']) > 10000) + if (strlen($request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE)) > 10000) { //echo 'Cookie grown too large' . print_r($tracking, true); @@ -1552,7 +1469,12 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ if ($user->data['is_registered']) { $user->data['user_lastmark'] = intval(base_convert(max($time_keys) + $config['board_startdate'], 36, 10)); - $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_lastmark = ' . $user->data['user_lastmark'] . " WHERE user_id = {$user->data['user_id']}"); + + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_lastmark = $post_time + WHERE user_id = {$user->data['user_id']} + AND mark_time < $post_time"; + $db->sql_query($sql); } else { @@ -1560,8 +1482,8 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ } } - $user->set_cookie('track', tracking_serialize($tracking), time() + 31536000); - $_COOKIE[$config['cookie_name'] . '_track'] = (STRIP) ? addslashes(tracking_serialize($tracking)) : tracking_serialize($tracking); + $user->set_cookie('track', tracking_serialize($tracking), $post_time + 31536000); + $request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking), \phpbb\request\request_interface::COOKIE); } return; @@ -1582,7 +1504,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ $sql_ary = array( 'user_id' => (int) $use_user_id, 'topic_id' => (int) $topic_id, - 'topic_posted' => 1 + 'topic_posted' => 1, ); $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); @@ -1622,35 +1544,6 @@ function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $ { $mark_time = array(); - // Get global announcement info - if ($global_announce_list && sizeof($global_announce_list)) - { - if (!isset($forum_mark_time[0])) - { - global $db; - - $sql = 'SELECT mark_time - FROM ' . FORUMS_TRACK_TABLE . " - WHERE user_id = {$user->data['user_id']} - AND forum_id = 0"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $mark_time[0] = $row['mark_time']; - } - } - else - { - if ($forum_mark_time[0] !== false) - { - $mark_time[0] = $forum_mark_time[0]; - } - } - } - if (!empty($forum_mark_time[$forum_id]) && $forum_mark_time[$forum_id] !== false) { $mark_time[$forum_id] = $forum_mark_time[$forum_id]; @@ -1660,14 +1553,7 @@ function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $ foreach ($topic_ids as $topic_id) { - if ($global_announce_list && isset($global_announce_list[$topic_id])) - { - $last_read[$topic_id] = (isset($mark_time[0])) ? $mark_time[0] : $user_lastmark; - } - else - { - $last_read[$topic_id] = $user_lastmark; - } + $last_read[$topic_id] = $user_lastmark; } } @@ -1679,7 +1565,7 @@ function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $ */ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_list = false) { - global $config, $user; + global $config, $user, $request; $last_read = array(); @@ -1711,8 +1597,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis $sql = 'SELECT forum_id, mark_time FROM ' . FORUMS_TRACK_TABLE . " WHERE user_id = {$user->data['user_id']} - AND forum_id " . - (($global_announce_list && sizeof($global_announce_list)) ? "IN (0, $forum_id)" : "= $forum_id"); + AND forum_id = $forum_id"; $result = $db->sql_query($sql); $mark_time = array(); @@ -1726,14 +1611,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis foreach ($topic_ids as $topic_id) { - if ($global_announce_list && isset($global_announce_list[$topic_id])) - { - $last_read[$topic_id] = (isset($mark_time[0])) ? $mark_time[0] : $user_lastmark; - } - else - { - $last_read[$topic_id] = $user_lastmark; - } + $last_read[$topic_id] = $user_lastmark; } } } @@ -1743,7 +1621,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis if (!isset($tracking_topics) || !sizeof($tracking_topics)) { - $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : ''; + $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); } @@ -1771,13 +1649,6 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis if (sizeof($topic_ids)) { $mark_time = array(); - if ($global_announce_list && sizeof($global_announce_list)) - { - if (isset($tracking_topics['f'][0])) - { - $mark_time[0] = base_convert($tracking_topics['f'][0], 36, 10) + $config['board_startdate']; - } - } if (isset($tracking_topics['f'][$forum_id])) { @@ -1788,14 +1659,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis foreach ($topic_ids as $topic_id) { - if ($global_announce_list && isset($global_announce_list[$topic_id])) - { - $last_read[$topic_id] = (isset($mark_time[0])) ? $mark_time[0] : $user_lastmark; - } - else - { - $last_read[$topic_id] = $user_lastmark; - } + $last_read[$topic_id] = $user_lastmark; } } } @@ -1817,6 +1681,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $sql_limit = 1001, $sql_limit_offset = 0) { global $config, $db, $user; + global $phpbb_dispatcher; $user_id = ($user_id === false) ? (int) $user->data['user_id'] : (int) $user_id; @@ -1825,7 +1690,7 @@ function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $s if (empty($sql_sort)) { - $sql_sort = 'ORDER BY t.topic_last_post_time DESC'; + $sql_sort = 'ORDER BY t.topic_last_post_time DESC, t.topic_last_post_id DESC'; } if ($config['load_db_lastread'] && $user->data['is_registered']) @@ -1860,6 +1725,24 @@ function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $s $sql_sort", ); + /** + * Change SQL query for fetching unread topics data + * + * @event core.get_unread_topics_modify_sql + * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, LEFT_JOIN, WHERE + * @var int last_mark User's last_mark time + * @var string sql_extra Extra WHERE SQL statement + * @var string sql_sort ORDER BY SQL sorting statement + * @since 3.1.4-RC1 + */ + $vars = array( + 'sql_array', + 'last_mark', + 'sql_extra', + 'sql_sort', + ); + extract($phpbb_dispatcher->trigger_event('core.get_unread_topics_modify_sql', compact($vars))); + $sql = $db->sql_build_query('SELECT', $sql_array); $result = $db->sql_query_limit($sql, $sql_limit, $sql_limit_offset); @@ -1943,7 +1826,7 @@ function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $s */ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time = false, $mark_time_forum = false) { - global $db, $tracking_topics, $user, $config, $auth; + global $db, $tracking_topics, $user, $config, $auth, $request, $phpbb_container; // Determine the users last forum mark time if not given. if ($mark_time_forum === false) @@ -1954,7 +1837,7 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti } else if ($config['load_anon_lastread'] || $user->data['is_registered']) { - $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : ''; + $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); if (!$user->data['is_registered']) @@ -1968,7 +1851,7 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti // Handle update of unapproved topics info. // Only update for moderators having m_approve permission for the forum. - $sql_update_unapproved = ($auth->acl_get('m_approve', $forum_id)) ? '': 'AND t.topic_approved = 1'; + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); // Check the forum for any left unread topics. // If there are none, we mark the forum as read. @@ -1988,8 +1871,8 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti AND tt.user_id = ' . $user->data['user_id'] . ') WHERE t.forum_id = ' . $forum_id . ' AND t.topic_last_post_time > ' . $mark_time_forum . ' - AND t.topic_moved_id = 0 ' . - $sql_update_unapproved . ' + AND t.topic_moved_id = 0 + AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.') . ' AND (tt.topic_id IS NULL OR tt.mark_time < t.topic_last_post_time)'; $result = $db->sql_query_limit($sql, 1); @@ -2013,8 +1896,8 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti FROM ' . TOPICS_TABLE . ' t WHERE t.forum_id = ' . $forum_id . ' AND t.topic_last_post_time > ' . $mark_time_forum . ' - AND t.topic_moved_id = 0 ' . - $sql_update_unapproved; + AND t.topic_moved_id = 0 + AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.'); $result = $db->sql_query($sql); $check_forum = $tracking_topics['tf'][$forum_id]; @@ -2168,111 +2051,6 @@ function tracking_unserialize($string, $max_depth = 3) return $level; } -// Pagination functions - -/** -* Pagination routine, generates page number sequence -* tpl_prefix is for using different pagination blocks at one page -*/ -function generate_pagination($base_url, $num_items, $per_page, $start_item, $add_prevnext_text = false, $tpl_prefix = '') -{ - global $template, $user; - - // Make sure $per_page is a valid value - $per_page = ($per_page <= 0) ? 1 : $per_page; - - $seperator = '<span class="page-sep">' . $user->lang['COMMA_SEPARATOR'] . '</span>'; - $total_pages = ceil($num_items / $per_page); - - if ($total_pages == 1 || !$num_items) - { - return false; - } - - $on_page = floor($start_item / $per_page) + 1; - $url_delim = (strpos($base_url, '?') === false) ? '?' : ((strpos($base_url, '?') === strlen($base_url) - 1) ? '' : '&'); - - $page_string = ($on_page == 1) ? '<strong>1</strong>' : '<a href="' . $base_url . '">1</a>'; - - if ($total_pages > 5) - { - $start_cnt = min(max(1, $on_page - 4), $total_pages - 5); - $end_cnt = max(min($total_pages, $on_page + 4), 6); - - $page_string .= ($start_cnt > 1) ? '<span class="page-dots"> ... </span>' : $seperator; - - for ($i = $start_cnt + 1; $i < $end_cnt; $i++) - { - $page_string .= ($i == $on_page) ? '<strong>' . $i . '</strong>' : '<a href="' . $base_url . "{$url_delim}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>'; - if ($i < $end_cnt - 1) - { - $page_string .= $seperator; - } - } - - $page_string .= ($end_cnt < $total_pages) ? '<span class="page-dots"> ... </span>' : $seperator; - } - else - { - $page_string .= $seperator; - - for ($i = 2; $i < $total_pages; $i++) - { - $page_string .= ($i == $on_page) ? '<strong>' . $i . '</strong>' : '<a href="' . $base_url . "{$url_delim}start=" . (($i - 1) * $per_page) . '">' . $i . '</a>'; - if ($i < $total_pages) - { - $page_string .= $seperator; - } - } - } - - $page_string .= ($on_page == $total_pages) ? '<strong>' . $total_pages . '</strong>' : '<a href="' . $base_url . "{$url_delim}start=" . (($total_pages - 1) * $per_page) . '">' . $total_pages . '</a>'; - - if ($add_prevnext_text) - { - if ($on_page != 1) - { - $page_string = '<a href="' . $base_url . "{$url_delim}start=" . (($on_page - 2) * $per_page) . '">' . $user->lang['PREVIOUS'] . '</a> ' . $page_string; - } - - if ($on_page != $total_pages) - { - $page_string .= ' <a href="' . $base_url . "{$url_delim}start=" . ($on_page * $per_page) . '">' . $user->lang['NEXT'] . '</a>'; - } - } - - $template->assign_vars(array( - $tpl_prefix . 'BASE_URL' => $base_url, - 'A_' . $tpl_prefix . 'BASE_URL' => addslashes($base_url), - $tpl_prefix . 'PER_PAGE' => $per_page, - - $tpl_prefix . 'PREVIOUS_PAGE' => ($on_page == 1) ? '' : $base_url . "{$url_delim}start=" . (($on_page - 2) * $per_page), - $tpl_prefix . 'NEXT_PAGE' => ($on_page == $total_pages) ? '' : $base_url . "{$url_delim}start=" . ($on_page * $per_page), - $tpl_prefix . 'TOTAL_PAGES' => $total_pages, - )); - - return $page_string; -} - -/** -* Return current page (pagination) -*/ -function on_page($num_items, $per_page, $start) -{ - global $template, $user; - - // Make sure $per_page is a valid value - $per_page = ($per_page <= 0) ? 1 : $per_page; - - $on_page = floor($start / $per_page) + 1; - - $template->assign_vars(array( - 'ON_PAGE' => $on_page) - ); - - return sprintf($user->lang['PAGE_OF'], $on_page, max(ceil($num_items / $per_page), 1)); -} - // Server functions (building urls, redirecting...) /** @@ -2283,6 +2061,9 @@ function on_page($num_items, $per_page, $start) * @param mixed $params String or array of additional url parameters * @param bool $is_amp Is url using & (true) or & (false) * @param string $session_id Possibility to use a custom session id instead of the global one +* @param bool $is_route Is url generated by a route. +* +* @return string The corrected url. * * Examples: * <code> @@ -2293,9 +2074,10 @@ function on_page($num_items, $per_page, $start) * </code> * */ -function append_sid($url, $params = false, $is_amp = true, $session_id = false) +function append_sid($url, $params = false, $is_amp = true, $session_id = false, $is_route = false) { - global $_SID, $_EXTRA_URL, $phpbb_hook; + global $_SID, $_EXTRA_URL, $phpbb_hook, $phpbb_path_helper; + global $phpbb_dispatcher; if ($params === '' || (is_array($params) && empty($params))) { @@ -2303,6 +2085,46 @@ function append_sid($url, $params = false, $is_amp = true, $session_id = false) $params = false; } + // Update the root path with the correct relative web path + if (!$is_route && $phpbb_path_helper instanceof \phpbb\path_helper) + { + $url = $phpbb_path_helper->update_web_root_path($url); + } + + $append_sid_overwrite = false; + + /** + * This event can either supplement or override the append_sid() function + * + * To override this function, the event must set $append_sid_overwrite to + * the new URL value, which will be returned following the event + * + * @event core.append_sid + * @var string url The url the session id needs + * to be appended to (can have + * params) + * @var mixed params String or array of additional + * url parameters + * @var bool is_amp Is url using & (true) or + * & (false) + * @var bool|string session_id Possibility to use a custom + * session id (string) instead of + * the global one (false) + * @var bool|string append_sid_overwrite Overwrite function (string + * URL) or not (false) + * @var bool is_route Is url generated by a route. + * @since 3.1.0-a1 + */ + $vars = array('url', 'params', 'is_amp', 'session_id', 'append_sid_overwrite', 'is_route'); + extract($phpbb_dispatcher->trigger_event('core.append_sid', compact($vars))); + + if ($append_sid_overwrite) + { + return $append_sid_overwrite; + } + + // The following hook remains for backwards compatibility, though use of + // the event above is preferred. // Developers using the hook function need to globalise the $_SID and $_EXTRA_URL on their own and also handle it appropriately. // They could mimic most of what is within this function if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__, $url, $params, $is_amp, $session_id)) @@ -2404,10 +2226,10 @@ function append_sid($url, $params = false, $is_amp = true, $session_id = false) */ function generate_board_url($without_script_path = false) { - global $config, $user; + global $config, $user, $request; $server_name = $user->host; - $server_port = (!empty($_SERVER['SERVER_PORT'])) ? (int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT'); + $server_port = $request->server('SERVER_PORT', 0); // Forcing server vars is the only way to specify/override the protocol if ($config['force_server_vars'] || !$server_name) @@ -2423,7 +2245,7 @@ function generate_board_url($without_script_path = false) else { // Do not rely on cookie_secure, users seem to think that it means a secured cookie instead of an encrypted connection - $cookie_secure = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 1 : 0; + $cookie_secure = $request->is_secure() ? 1 : 0; $url = (($cookie_secure) ? 'https://' : 'http://') . $server_name; $script_path = $user->page['root_script_path']; @@ -2462,7 +2284,7 @@ function generate_board_url($without_script_path = false) */ function redirect($url, $return = false, $disable_cd_check = false) { - global $db, $cache, $config, $user, $phpbb_root_path; + global $db, $cache, $config, $user, $phpbb_root_path, $phpbb_filesystem, $phpbb_path_helper, $phpEx, $phpbb_dispatcher; $failover_flag = false; @@ -2471,11 +2293,6 @@ function redirect($url, $return = false, $disable_cd_check = false) $user->add_lang('common'); } - if (!$return) - { - garbage_collection(); - } - // Make sure no &'s are in, this will break the redirect $url = str_replace('&', '&', $url); @@ -2505,90 +2322,40 @@ function redirect($url, $return = false, $disable_cd_check = false) // Relative uri $pathinfo = pathinfo($url); - if (!$disable_cd_check && !file_exists($pathinfo['dirname'] . '/')) + // Is the uri pointing to the current directory? + if ($pathinfo['dirname'] == '.') { - $url = str_replace('../', '', $url); - $pathinfo = pathinfo($url); + $url = str_replace('./', '', $url); - if (!file_exists($pathinfo['dirname'] . '/')) + // Strip / from the beginning + if ($url && substr($url, 0, 1) == '/') { - // fallback to "last known user page" - // at least this way we know the user does not leave the phpBB root - $url = generate_board_url() . '/' . $user->page['page']; - $failover_flag = true; + $url = substr($url, 1); } } - if (!$failover_flag) - { - // Is the uri pointing to the current directory? - if ($pathinfo['dirname'] == '.') - { - $url = str_replace('./', '', $url); - - // Strip / from the beginning - if ($url && substr($url, 0, 1) == '/') - { - $url = substr($url, 1); - } - - if ($user->page['page_dir']) - { - $url = generate_board_url() . '/' . $user->page['page_dir'] . '/' . $url; - } - else - { - $url = generate_board_url() . '/' . $url; - } - } - else - { - // Used ./ before, but $phpbb_root_path is working better with urls within another root path - $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($phpbb_root_path))); - $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($pathinfo['dirname']))); - $intersection = array_intersect_assoc($root_dirs, $page_dirs); - - $root_dirs = array_diff_assoc($root_dirs, $intersection); - $page_dirs = array_diff_assoc($page_dirs, $intersection); - - $dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs); - - // Strip / from the end - if ($dir && substr($dir, -1, 1) == '/') - { - $dir = substr($dir, 0, -1); - } - - // Strip / from the beginning - if ($dir && substr($dir, 0, 1) == '/') - { - $dir = substr($dir, 1); - } - - $url = str_replace($pathinfo['dirname'] . '/', '', $url); + $url = $phpbb_path_helper->remove_web_root_path($url); - // Strip / from the beginning - if (substr($url, 0, 1) == '/') - { - $url = substr($url, 1); - } - - $url = (!empty($dir) ? $dir . '/' : '') . $url; - $url = generate_board_url() . '/' . $url; - } + if ($user->page['page_dir']) + { + $url = $user->page['page_dir'] . '/' . $url; } + + $url = generate_board_url() . '/' . $url; } - // Make sure we don't redirect to external URLs + // Clean URL and check if we go outside the forum directory + $url = $phpbb_path_helper->clean_url($url); + if (!$disable_cd_check && strpos($url, generate_board_url(true) . '/') !== 0) { - trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR); + trigger_error('INSECURE_REDIRECT', E_USER_ERROR); } // Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2 if (strpos(urldecode($url), "\n") !== false || strpos(urldecode($url), "\r") !== false || strpos($url, ';') !== false) { - trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR); + trigger_error('INSECURE_REDIRECT', E_USER_ERROR); } // Now, also check the protocol and for a valid url the last time... @@ -2597,23 +2364,39 @@ function redirect($url, $return = false, $disable_cd_check = false) if ($url_parts === false || empty($url_parts['scheme']) || !in_array($url_parts['scheme'], $allowed_protocols)) { - trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR); + trigger_error('INSECURE_REDIRECT', E_USER_ERROR); } + /** + * Execute code and/or overwrite redirect() + * + * @event core.functions.redirect + * @var string url The url + * @var bool return If true, do not redirect but return the sanitized URL. + * @var bool disable_cd_check If true, redirect() will redirect to an external domain. If false, the redirect point to the boards url if it does not match the current domain. + * @since 3.1.0-RC3 + */ + $vars = array('url', 'return', 'disable_cd_check'); + extract($phpbb_dispatcher->trigger_event('core.functions.redirect', compact($vars))); + if ($return) { return $url; } + else + { + garbage_collection(); + } // Redirect via an HTML form for PITA webservers if (@preg_match('#Microsoft|WebSTAR|Xitami#', getenv('SERVER_SOFTWARE'))) { header('Refresh: 0; URL=' . $url); - echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'; - echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="' . $user->lang['DIRECTION'] . '" lang="' . $user->lang['USER_LANG'] . '" xml:lang="' . $user->lang['USER_LANG'] . '">'; + echo '<!DOCTYPE html>'; + echo '<html dir="' . $user->lang['DIRECTION'] . '" lang="' . $user->lang['USER_LANG'] . '">'; echo '<head>'; - echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />'; + echo '<meta charset="utf-8">'; echo '<meta http-equiv="refresh" content="0; url=' . str_replace('&', '&', $url) . '" />'; echo '<title>' . $user->lang['REDIRECT'] . '</title>'; echo '</head>'; @@ -2663,77 +2446,23 @@ function reapply_sid($url) */ function build_url($strip_vars = false) { - global $user, $phpbb_root_path; + global $config, $user, $phpbb_path_helper; + + $page = $phpbb_path_helper->get_valid_page($user->page['page'], $config['enable_mod_rewrite']); // Append SID - $redirect = append_sid($user->page['page'], false, false); + $redirect = append_sid($page, false, false); - // Add delimiter if not there... - if (strpos($redirect, '?') === false) + if ($strip_vars !== false) { - $redirect .= '?'; + $redirect = $phpbb_path_helper->strip_url_params($redirect, $strip_vars, false); } - - // Strip vars... - if ($strip_vars !== false && strpos($redirect, '?') !== false) - { - if (!is_array($strip_vars)) - { - $strip_vars = array($strip_vars); - } - - $query = $_query = array(); - - $args = substr($redirect, strpos($redirect, '?') + 1); - $args = ($args) ? explode('&', $args) : array(); - $redirect = substr($redirect, 0, strpos($redirect, '?')); - - foreach ($args as $argument) - { - $arguments = explode('=', $argument); - $key = $arguments[0]; - unset($arguments[0]); - - if ($key === '') - { - continue; - } - - $query[$key] = implode('=', $arguments); - } - - // Strip the vars off - foreach ($strip_vars as $strip) - { - if (isset($query[$strip])) - { - unset($query[$strip]); - } - } - - // Glue the remaining parts together... already urlencoded - foreach ($query as $key => $value) - { - $_query[] = $key . '=' . $value; - } - $query = implode('&', $_query); - - $redirect .= ($query) ? '?' . $query : ''; - } - - // We need to be cautious here. - // On some situations, the redirect path is an absolute URL, sometimes a relative path - // For a relative path, let's prefix it with $phpbb_root_path to point to the correct location, - // else we use the URL directly. - $url_parts = @parse_url($redirect); - - // URL - if ($url_parts !== false && !empty($url_parts['scheme']) && !empty($url_parts['host'])) + else { - return str_replace('&', '&', $redirect); + $redirect = str_replace('&', '&', $redirect); } - return $phpbb_root_path . str_replace('&', '&', $redirect); + return $redirect . ((strpos($redirect, '?') === false) ? '?' : ''); } /** @@ -2746,15 +2475,25 @@ function build_url($strip_vars = false) */ function meta_refresh($time, $url, $disable_cd_check = false) { - global $template; + global $template, $refresh_data, $request; $url = redirect($url, true, $disable_cd_check); - $url = str_replace('&', '&', $url); + if ($request->is_ajax()) + { + $refresh_data = array( + 'time' => $time, + 'url' => $url, + ); + } + else + { + // For XHTML compatibility we change back & to & + $url = str_replace('&', '&', $url); - // For XHTML compatibility we change back & to & - $template->assign_vars(array( - 'META' => '<meta http-equiv="refresh" content="' . $time . '; url=' . $url . '" />') - ); + $template->assign_vars(array( + 'META' => '<meta http-equiv="refresh" content="' . $time . '; url=' . $url . '" />') + ); + } return $url; } @@ -2788,18 +2527,41 @@ function send_status_line($code, $message) } else { - if (!empty($_SERVER['SERVER_PROTOCOL'])) - { - $version = $_SERVER['SERVER_PROTOCOL']; - } - else - { - $version = 'HTTP/1.0'; - } + $version = phpbb_request_http_version(); header("$version $code $message", true, $code); } } +/** +* Returns the HTTP version used in the current request. +* +* Handles the case of being called before $request is present, +* in which case it falls back to the $_SERVER superglobal. +* +* @return string HTTP version +*/ +function phpbb_request_http_version() +{ + global $request; + + $version = ''; + if ($request && $request->server('SERVER_PROTOCOL')) + { + $version = $request->server('SERVER_PROTOCOL'); + } + else if (isset($_SERVER['SERVER_PROTOCOL'])) + { + $version = $_SERVER['SERVER_PROTOCOL']; + } + + if (!empty($version) && is_string($version) && preg_match('#^HTTP/[0-9]\.[0-9]$#', $version)) + { + return $version; + } + + return 'HTTP/1.0'; +} + //Form validation @@ -2839,7 +2601,7 @@ function check_link_hash($token, $link_name) */ function add_form_key($form_name) { - global $config, $template, $user; + global $config, $template, $user, $phpbb_dispatcher; $now = time(); $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : ''; @@ -2850,21 +2612,44 @@ function add_form_key($form_name) 'form_token' => $token, )); + /** + * Perform additional actions on creation of the form token + * + * @event core.add_form_key + * @var string form_name The form name + * @var int now Current time timestamp + * @var string s_fields Generated hidden fields + * @var string token Form token + * @var string token_sid User session ID + * + * @since 3.1.0-RC3 + */ + $vars = array( + 'form_name', + 'now', + 's_fields', + 'token', + 'token_sid', + ); + extract($phpbb_dispatcher->trigger_event('core.add_form_key', compact($vars))); + $template->assign_vars(array( 'S_FORM_TOKEN' => $s_fields, )); } /** -* Check the form key. Required for all altering actions not secured by confirm_box -* @param string $form_name The name of the form; has to match the name used in add_form_key, otherwise no restrictions apply -* @param int $timespan The maximum acceptable age for a submitted form in seconds. Defaults to the config setting. -* @param string $return_page The address for the return link -* @param bool $trigger If true, the function will triger an error when encountering an invalid form -*/ -function check_form_key($form_name, $timespan = false, $return_page = '', $trigger = false) + * Check the form key. Required for all altering actions not secured by confirm_box + * + * @param string $form_name The name of the form; has to match the name used + * in add_form_key, otherwise no restrictions apply + * @param int $timespan The maximum acceptable age for a submitted form + * in seconds. Defaults to the config setting. + * @return bool True, if the form key was valid, false otherwise + */ +function check_form_key($form_name, $timespan = false) { - global $config, $user; + global $config, $request, $user; if ($timespan === false) { @@ -2872,10 +2657,10 @@ function check_form_key($form_name, $timespan = false, $return_page = '', $trigg $timespan = ($config['form_token_lifetime'] == -1) ? -1 : max(30, $config['form_token_lifetime']); } - if (isset($_POST['creation_time']) && isset($_POST['form_token'])) + if ($request->is_set_post('creation_time') && $request->is_set_post('form_token')) { - $creation_time = abs(request_var('creation_time', 0)); - $token = request_var('form_token', ''); + $creation_time = abs($request->variable('creation_time', 0)); + $token = $request->variable('form_token', ''); $diff = time() - $creation_time; @@ -2892,11 +2677,6 @@ function check_form_key($form_name, $timespan = false, $return_page = '', $trigg } } - if ($trigger) - { - trigger_error($user->lang['FORM_INVALID'] . $return_page); - } - return false; } @@ -2915,23 +2695,15 @@ function check_form_key($form_name, $timespan = false, $return_page = '', $trigg */ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_body.html', $u_action = '') { - global $user, $template, $db; - global $phpEx, $phpbb_root_path; + global $user, $template, $db, $request; + global $config, $phpbb_path_helper; if (isset($_POST['cancel'])) { return false; } - $confirm = false; - if (isset($_POST['confirm'])) - { - // language frontier - if ($_POST['confirm'] === $user->lang['YES']) - { - $confirm = true; - } - } + $confirm = ($user->lang['YES'] === $request->variable('confirm', '', true, \phpbb\request\request_interface::POST)); if ($check && $confirm) { @@ -2971,7 +2743,7 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo } else { - page_header(((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]), false); + page_header((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]); } $template->set_filenames(array( @@ -2986,8 +2758,8 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo } // re-add sid / transform & to & for user->page (user->page is always using &) - $use_page = ($u_action) ? $phpbb_root_path . $u_action : $phpbb_root_path . str_replace('&', '&', $user->page['page']); - $u_action = reapply_sid($use_page); + $use_page = ($u_action) ? $u_action : str_replace('&', '&', $user->page['page']); + $u_action = reapply_sid($phpbb_path_helper->get_valid_page($use_page, $config['enable_mod_rewrite'])); $u_action .= ((strpos($u_action, '?') === false) ? '?' : '&') . 'confirm_key=' . $confirm_key; $template->assign_vars(array( @@ -2996,13 +2768,29 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo 'YES_VALUE' => $user->lang['YES'], 'S_CONFIRM_ACTION' => $u_action, - 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields) - ); + 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields, + 'S_AJAX_REQUEST' => $request->is_ajax(), + )); $sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "' WHERE user_id = " . $user->data['user_id']; $db->sql_query($sql); + if ($request->is_ajax()) + { + $u_action .= '&confirm_uid=' . $user->data['user_id'] . '&sess=' . $user->session_id . '&sid=' . $user->session_id; + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'MESSAGE_BODY' => $template->assign_display('body'), + 'MESSAGE_TITLE' => (!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title], + 'MESSAGE_TEXT' => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'], + + 'YES_VALUE' => $user->lang['YES'], + 'S_CONFIRM_ACTION' => str_replace('&', '&', $u_action), //inefficient, rewrite whole function + 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields + )); + } + if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin']) { adm_page_footer(); @@ -3019,11 +2807,7 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = false, $s_display = true) { global $db, $user, $template, $auth, $phpEx, $phpbb_root_path, $config; - - if (!class_exists('phpbb_captcha_factory')) - { - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - } + global $request, $phpbb_container, $phpbb_dispatcher; $err = ''; @@ -3045,7 +2829,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa trigger_error('NO_AUTH_ADMIN'); } - if (isset($_POST['login'])) + if ($request->is_set_post('login') || ($request->is_set('login') && $request->variable('login', '') == 'external')) { // Get credential if ($admin) @@ -3061,16 +2845,16 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa trigger_error('NO_AUTH_ADMIN'); } - $password = request_var('password_' . $credential, '', true); + $password = $request->untrimmed_variable('password_' . $credential, '', true); } else { - $password = request_var('password', '', true); + $password = $request->untrimmed_variable('password', '', true); } $username = request_var('username', '', true); - $autologin = (!empty($_POST['autologin'])) ? true : false; - $viewonline = (!empty($_POST['viewonline'])) ? 0 : 1; + $autologin = $request->is_set_post('autologin'); + $viewonline = (int) !$request->is_set_post('viewonline'); $admin = ($admin) ? 1 : 0; $viewonline = ($admin) ? $user->data['session_viewonline'] : $viewonline; @@ -3108,8 +2892,18 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa if ($result['status'] == LOGIN_SUCCESS) { $redirect = request_var('redirect', "{$phpbb_root_path}index.$phpEx"); - $message = ($l_success) ? $l_success : $user->lang['LOGIN_REDIRECT']; - $l_redirect = ($admin) ? $user->lang['PROCEED_TO_ACP'] : (($redirect === "{$phpbb_root_path}index.$phpEx" || $redirect === "index.$phpEx") ? $user->lang['RETURN_INDEX'] : $user->lang['RETURN_PAGE']); + + /** + * This event allows an extension to modify the redirection when a user successfully logs in + * + * @event core.login_box_redirect + * @var string redirect Redirect string + * @var boolean admin Is admin? + * @var bool return If true, do not redirect but return the sanitized URL. + * @since 3.1.0-RC5 + */ + $vars = array('redirect', 'admin', 'return'); + extract($phpbb_dispatcher->trigger_event('core.login_box_redirect', compact($vars))); // append/replace SID (may change during the session for AOL users) $redirect = reapply_sid($redirect); @@ -3120,8 +2914,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa return; } - $redirect = meta_refresh(3, $redirect); - trigger_error($message . '<br /><br />' . sprintf($l_redirect, '<a href="' . $redirect . '">', '</a>')); + redirect($redirect); } // Something failed, determine what... @@ -3133,28 +2926,26 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa // Special cases... determine switch ($result['status']) { + case LOGIN_ERROR_PASSWORD_CONVERT: + $err = sprintf( + $user->lang[$result['error_msg']], + ($config['email_enable']) ? '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') . '">' : '', + ($config['email_enable']) ? '</a>' : '', + '<a href="' . phpbb_get_board_contact_link($config, $phpbb_root_path, $phpEx) . '">', + '</a>' + ); + break; + case LOGIN_ERROR_ATTEMPTS: - $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); $captcha->init(CONFIRM_LOGIN); // $captcha->reset(); $template->assign_vars(array( 'CAPTCHA_TEMPLATE' => $captcha->get_template(), )); - - $err = $user->lang[$result['error_msg']]; - break; - - case LOGIN_ERROR_PASSWORD_CONVERT: - $err = sprintf( - $user->lang[$result['error_msg']], - ($config['email_enable']) ? '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') . '">' : '', - ($config['email_enable']) ? '</a>' : '', - ($config['board_contact']) ? '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">' : '', - ($config['board_contact']) ? '</a>' : '' - ); - break; + // no break; // Username, password, etc... default: @@ -3163,11 +2954,24 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa // Assign admin contact to some error messages if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' || $result['error_msg'] == 'LOGIN_ERROR_PASSWORD') { - $err = (!$config['board_contact']) ? sprintf($user->lang[$result['error_msg']], '', '') : sprintf($user->lang[$result['error_msg']], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'); + $err = sprintf($user->lang[$result['error_msg']], '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin') . '">', '</a>'); } break; } + + /** + * This event allows an extension to process when a user fails a login attempt + * + * @event core.login_box_failed + * @var array result Login result data + * @var string username User name used to login + * @var string password Password used to login + * @var string err Error message + * @since 3.1.3-RC1 + */ + $vars = array('result', 'username', 'password', 'err'); + extract($phpbb_dispatcher->trigger_event('core.login_box_failed', compact($vars))); } // Assign credential for username/password pair @@ -3187,6 +2991,30 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa $s_hidden_fields['credential'] = $credential; } + $provider_collection = $phpbb_container->get('auth.provider_collection'); + $auth_provider = $provider_collection->get_provider(); + + $auth_provider_data = $auth_provider->get_login_data(); + if ($auth_provider_data) + { + if (isset($auth_provider_data['VARS'])) + { + $template->assign_vars($auth_provider_data['VARS']); + } + + if (isset($auth_provider_data['BLOCK_VAR_NAME'])) + { + foreach ($auth_provider_data['BLOCK_VARS'] as $block_vars) + { + $template->assign_block_vars($auth_provider_data['BLOCK_VAR_NAME'], $block_vars); + } + } + + $template->assign_vars(array( + 'PROVIDER_TEMPLATE_FILE' => $auth_provider_data['TEMPLATE_FILE'], + )); + } + $s_hidden_fields = build_hidden_fields($s_hidden_fields); $template->assign_vars(array( @@ -3208,7 +3036,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa 'PASSWORD_CREDENTIAL' => ($admin) ? 'password_' . $credential : 'password', )); - page_header($user->lang['LOGIN'], false); + page_header($user->lang['LOGIN']); $template->set_filenames(array( 'body' => 'login_body.html') @@ -3223,9 +3051,9 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa */ function login_forum_box($forum_data) { - global $db, $config, $user, $template, $phpEx; + global $db, $phpbb_container, $request, $template, $user, $phpbb_dispatcher; - $password = request_var('password', '', true); + $password = $request->variable('password', '', true); $sql = 'SELECT forum_id FROM ' . FORUMS_ACCESS_TABLE . ' @@ -3266,7 +3094,9 @@ function login_forum_box($forum_data) } $db->sql_freeresult($result); - if (phpbb_check_hash($password, $forum_data['forum_password'])) + $passwords_manager = $phpbb_container->get('passwords.manager'); + + if ($passwords_manager->check($password, $forum_data['forum_password'])) { $sql_ary = array( 'forum_id' => (int) $forum_data['forum_id'], @@ -3282,7 +3112,18 @@ function login_forum_box($forum_data) $template->assign_var('LOGIN_ERROR', $user->lang['WRONG_PASSWORD']); } - page_header($user->lang['LOGIN'], false); + /** + * Performing additional actions, load additional data on forum login + * + * @event core.login_forum_box + * @var array forum_data Array with forum data + * @var string password Password entered + * @since 3.1.0-RC3 + */ + $vars = array('forum_data', 'password'); + extract($phpbb_dispatcher->trigger_event('core.login_forum_box', compact($vars))); + + page_header($user->lang['LOGIN']); $template->assign_vars(array( 'FORUM_NAME' => isset($forum_data['forum_name']) ? $forum_data['forum_name'] : '', @@ -3399,79 +3240,59 @@ function parse_cfg_file($filename, $lines = false) $parsed_items[$key] = $value; } - - if (isset($parsed_items['inherit_from']) && isset($parsed_items['name']) && $parsed_items['inherit_from'] == $parsed_items['name']) + + if (isset($parsed_items['parent']) && isset($parsed_items['name']) && $parsed_items['parent'] == $parsed_items['name']) { - unset($parsed_items['inherit_from']); + unset($parsed_items['parent']); } return $parsed_items; } /** -* Add log event +* Add log entry +* +* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved +* @param int $forum_id Mode 'mod' ONLY: forum id of the related item, NOT INCLUDED otherwise +* @param int $topic_id Mode 'mod' ONLY: topic id of the related item, NOT INCLUDED otherwise +* @param int $reportee_id Mode 'user' ONLY: user id of the reportee, NOT INCLUDED otherwise +* @param string $log_operation Name of the operation +* @param array $additional_data More arguments can be added, depending on the log_type +* +* @return int|bool Returns the log_id, if the entry was added to the database, false otherwise. +* +* @deprecated Use $phpbb_log->add() instead */ function add_log() { - global $db, $user; - - // In phpBB 3.1.x i want to have logging in a class to be able to control it - // For now, we need a quite hakish approach to circumvent logging for some actions - // @todo implement cleanly - if (!empty($GLOBALS['skip_add_log'])) - { - return false; - } + global $phpbb_log, $user; $args = func_get_args(); + $mode = array_shift($args); - $mode = array_shift($args); - $reportee_id = ($mode == 'user') ? intval(array_shift($args)) : ''; - $forum_id = ($mode == 'mod') ? intval(array_shift($args)) : ''; - $topic_id = ($mode == 'mod') ? intval(array_shift($args)) : ''; - $action = array_shift($args); - $data = (!sizeof($args)) ? '' : serialize($args); - - $sql_ary = array( - 'user_id' => (empty($user->data)) ? ANONYMOUS : $user->data['user_id'], - 'log_ip' => $user->ip, - 'log_time' => time(), - 'log_operation' => $action, - 'log_data' => $data, - ); - + // This looks kind of dirty, but add_log has some additional data before the log_operation + $additional_data = array(); switch ($mode) { case 'admin': - $sql_ary['log_type'] = LOG_ADMIN; + case 'critical': break; - case 'mod': - $sql_ary += array( - 'log_type' => LOG_MOD, - 'forum_id' => $forum_id, - 'topic_id' => $topic_id - ); + $additional_data['forum_id'] = array_shift($args); + $additional_data['topic_id'] = array_shift($args); break; - case 'user': - $sql_ary += array( - 'log_type' => LOG_USERS, - 'reportee_id' => $reportee_id - ); - break; - - case 'critical': - $sql_ary['log_type'] = LOG_CRITICAL; + $additional_data['reportee_id'] = array_shift($args); break; - - default: - return false; } - $db->sql_query('INSERT INTO ' . LOG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); + $log_operation = array_shift($args); + $additional_data = array_merge($additional_data, $args); + + $user_id = (empty($user->data)) ? ANONYMOUS : $user->data['user_id']; + $user_ip = (empty($user->ip)) ? '' : $user->ip; - return $db->sql_nextid(); + return $phpbb_log->add($mode, $user_id, $user_ip, $log_operation, time(), $additional_data); } /** @@ -3530,7 +3351,7 @@ function get_preg_expression($mode) case 'email': // Regex written by James Watts and Francisco Jose Martin Moreno // http://fightingforalostcause.net/misc/2006/compare-email-regex.php - return '([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&)+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)'; + return '((?:[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&)+)@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)'; break; case 'bbcode_htm': @@ -3556,28 +3377,43 @@ function get_preg_expression($mode) break; case 'url': + // generated with regex_idn.php file in the develop folder + return "[a-z][a-z\d+\-.]*:/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?"; + break; + case 'url_inline': - $inline = ($mode == 'url') ? ')' : ''; - $scheme = ($mode == 'url') ? '[a-z\d+\-.]' : '[a-z\d+]'; // avoid automatic parsing of "word" in "last word.http://..." - // generated with regex generation file in the develop folder - return "[a-z]$scheme*:/{2}(?:(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?"; + // generated with regex_idn.php file in the develop folder + return "[a-z][a-z\d+]*:/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?"; break; case 'www_url': + // generated with regex_idn.php file in the develop folder + return "www\.(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?"; + break; + case 'www_url_inline': - $inline = ($mode == 'www_url') ? ')' : ''; - return "www\.(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?"; + // generated with regex_idn.php file in the develop folder + return "www\.(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?"; break; case 'relative_url': + // generated with regex_idn.php file in the develop folder + return "(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?"; + break; + case 'relative_url_inline': - $inline = ($mode == 'relative_url') ? ')' : ''; - return "(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~!$&'($inline*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[a-z0-9\-._~!$&'($inline*+,;=:@/?|]+|%[\dA-F]{2})*)?"; + // generated with regex_idn.php file in the develop folder + return "(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?"; break; case 'table_prefix': return '#^[a-zA-Z][a-zA-Z0-9_]*$#'; break; + + // Matches the predecing dot + case 'path_remove_dot_trailing_slash': + return '#^(?:(\.)?)+(?:(.+)?)+(?:([\\/\\\])$)#'; + break; } return ''; @@ -3594,18 +3430,10 @@ function get_preg_expression($mode) */ function get_censor_preg_expression($word, $use_unicode = true) { - static $unicode_support = null; - - // Check whether PHP version supports unicode properties - if (is_null($unicode_support)) - { - $unicode_support = ((version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) && @preg_match('/\p{L}/u', 'a') !== false) ? true : false; - } - // Unescape the asterisk to simplify further conversions $word = str_replace('\*', '*', preg_quote($word, '#')); - if ($use_unicode && $unicode_support) + if ($use_unicode && phpbb_pcre_utf8_support()) { // Replace asterisk(s) inside the pattern, at the start and at the end of it with regexes $word = preg_replace(array('#(?<=[\p{Nd}\p{L}_])\*+(?=[\p{Nd}\p{L}_])#iu', '#^\*+#', '#\*+$#'), array('([\x20]*?|[\p{Nd}\p{L}_-]*?)', '[\p{Nd}\p{L}_-]*?', '[\p{Nd}\p{L}_-]*?'), $word); @@ -3657,6 +3485,182 @@ function short_ipv6($ip, $length) } /** +* Normalises an internet protocol address, +* also checks whether the specified address is valid. +* +* IPv4 addresses are returned 'as is'. +* +* IPv6 addresses are normalised according to +* A Recommendation for IPv6 Address Text Representation +* http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07 +* +* @param string $address IP address +* +* @return mixed false if specified address is not valid, +* string otherwise +*/ +function phpbb_ip_normalise($address) +{ + $address = trim($address); + + if (empty($address) || !is_string($address)) + { + return false; + } + + if (preg_match(get_preg_expression('ipv4'), $address)) + { + return $address; + } + + return phpbb_inet_ntop(phpbb_inet_pton($address)); +} + +/** +* Wrapper for inet_ntop() +* +* Converts a packed internet address to a human readable representation +* inet_ntop() is supported by PHP since 5.1.0, since 5.3.0 also on Windows. +* +* @param string $in_addr A 32bit IPv4, or 128bit IPv6 address. +* +* @return mixed false on failure, +* string otherwise +*/ +function phpbb_inet_ntop($in_addr) +{ + $in_addr = bin2hex($in_addr); + + switch (strlen($in_addr)) + { + case 8: + return implode('.', array_map('hexdec', str_split($in_addr, 2))); + + case 32: + if (substr($in_addr, 0, 24) === '00000000000000000000ffff') + { + return phpbb_inet_ntop(pack('H*', substr($in_addr, 24))); + } + + $parts = str_split($in_addr, 4); + $parts = preg_replace('/^0+(?!$)/', '', $parts); + $ret = implode(':', $parts); + + $matches = array(); + preg_match_all('/(?<=:|^)(?::?0){2,}/', $ret, $matches, PREG_OFFSET_CAPTURE); + $matches = $matches[0]; + + if (empty($matches)) + { + return $ret; + } + + $longest_match = ''; + $longest_match_offset = 0; + foreach ($matches as $match) + { + if (strlen($match[0]) > strlen($longest_match)) + { + $longest_match = $match[0]; + $longest_match_offset = $match[1]; + } + } + + $ret = substr_replace($ret, '', $longest_match_offset, strlen($longest_match)); + + if ($longest_match_offset == strlen($ret)) + { + $ret .= ':'; + } + + if ($longest_match_offset == 0) + { + $ret = ':' . $ret; + } + + return $ret; + + default: + return false; + } +} + +/** +* Wrapper for inet_pton() +* +* Converts a human readable IP address to its packed in_addr representation +* inet_pton() is supported by PHP since 5.1.0, since 5.3.0 also on Windows. +* +* @param string $address A human readable IPv4 or IPv6 address. +* +* @return mixed false if address is invalid, +* in_addr representation of the given address otherwise (string) +*/ +function phpbb_inet_pton($address) +{ + $ret = ''; + if (preg_match(get_preg_expression('ipv4'), $address)) + { + foreach (explode('.', $address) as $part) + { + $ret .= ($part <= 0xF ? '0' : '') . dechex($part); + } + + return pack('H*', $ret); + } + + if (preg_match(get_preg_expression('ipv6'), $address)) + { + $parts = explode(':', $address); + $missing_parts = 8 - sizeof($parts) + 1; + + if (substr($address, 0, 2) === '::') + { + ++$missing_parts; + } + + if (substr($address, -2) === '::') + { + ++$missing_parts; + } + + $embedded_ipv4 = false; + $last_part = end($parts); + + if (preg_match(get_preg_expression('ipv4'), $last_part)) + { + $parts[sizeof($parts) - 1] = ''; + $last_part = phpbb_inet_pton($last_part); + $embedded_ipv4 = true; + --$missing_parts; + } + + foreach ($parts as $i => $part) + { + if (strlen($part)) + { + $ret .= str_pad($part, 4, '0', STR_PAD_LEFT); + } + else if ($i && $i < sizeof($parts) - 1) + { + $ret .= str_repeat('0000', $missing_parts); + } + } + + $ret = pack('H*', $ret); + + if ($embedded_ipv4) + { + $ret .= $last_part; + } + + return $ret; + } + + return false; +} + +/** * Wrapper for php's checkdnsrr function. * * @param string $host Fully-Qualified Domain Name @@ -3670,8 +3674,6 @@ function short_ipv6($ip, $length) * * Since null can also be returned, you probably want to compare the result * with === true or === false, -* -* @author bantu */ function phpbb_checkdnsrr($host, $type = 'MX') { @@ -3853,11 +3855,11 @@ function phpbb_checkdnsrr($host, $type = 'MX') // Handler, header and footer /** -* Error and message handler, call with trigger_error if reqd +* Error and message handler, call with trigger_error if read */ function msg_handler($errno, $msg_text, $errfile, $errline) { - global $cache, $db, $auth, $template, $config, $user; + global $cache, $db, $auth, $template, $config, $user, $request; global $phpEx, $phpbb_root_path, $msg_title, $msg_long_text; // Do not display notices if we suppress them via @ @@ -3942,12 +3944,22 @@ function msg_handler($errno, $msg_text, $errfile, $errline) $log_text .= '<br /><br />BACKTRACE<br />' . $backtrace; } - if (defined('IN_INSTALL') || defined('DEBUG_EXTRA') || isset($auth) && $auth->acl_get('a_')) + if (defined('IN_INSTALL') || defined('DEBUG') || isset($auth) && $auth->acl_get('a_')) { $msg_text = $log_text; + + // If this is defined there already was some output + // So let's not break it + if (defined('IN_DB_UPDATE')) + { + echo '<div class="errorbox">' . $msg_text . '</div>'; + + $db->sql_return_on_error(true); + phpbb_end_update($cache, $config); + } } - if ((defined('DEBUG') || defined('IN_CRON') || defined('IMAGE_OUTPUT')) && isset($db)) + if ((defined('IN_CRON') || defined('IMAGE_OUTPUT')) && isset($db)) { // let's avoid loops $db->sql_return_on_error(true); @@ -3962,10 +3974,10 @@ function msg_handler($errno, $msg_text, $errfile, $errline) // Try to not call the adm page data... - echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'; - echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">'; + echo '<!DOCTYPE html>'; + echo '<html dir="ltr">'; echo '<head>'; - echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />'; + echo '<meta charset="utf-8">'; echo '<title>' . $msg_title . '</title>'; echo '<style type="text/css">' . "\n" . '/* <![CDATA[ */' . "\n"; echo '* { margin: 0; padding: 0; } html { font-size: 100%; height: 100%; margin-bottom: 1px; background-color: #E4EDF0; } body { font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; color: #536482; background: #E4EDF0; font-size: 62.5%; margin: 0; } '; @@ -3995,7 +4007,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) echo ' </div>'; echo ' </div>'; echo ' <div id="page-footer">'; - echo ' Powered by <a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Group'; + echo ' Powered by <a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Limited'; echo ' </div>'; echo '</div>'; echo '</body>'; @@ -4041,7 +4053,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) } else { - page_header($msg_title, false); + page_header($msg_title); } } @@ -4056,6 +4068,20 @@ function msg_handler($errno, $msg_text, $errfile, $errline) 'S_USER_NOTICE' => ($errno == E_USER_NOTICE) ? true : false) ); + if ($request->is_ajax()) + { + global $refresh_data; + + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'MESSAGE_TITLE' => $msg_title, + 'MESSAGE_TEXT' => $msg_text, + 'S_USER_WARNING' => ($errno == E_USER_WARNING) ? true : false, + 'S_USER_NOTICE' => ($errno == E_USER_NOTICE) ? true : false, + 'REFRESH_DATA' => (!empty($refresh_data)) ? $refresh_data : null + )); + } + // We do not want the cron script to be called on error messages define('IN_CRON', true); @@ -4127,7 +4153,7 @@ function obtain_guest_count($item_id = 0, $item = 'forum') // Get number of online guests - if ($db->sql_layer === 'sqlite') + if ($db->get_sql_layer() === 'sqlite' || $db->get_sql_layer() === 'sqlite3') { $sql = 'SELECT COUNT(session_ip) as num_guests FROM ( @@ -4225,9 +4251,10 @@ function obtain_users_online($item_id = 0, $item = 'forum') */ function obtain_users_online_string($online_users, $item_id = 0, $item = 'forum') { - global $config, $db, $user, $auth; + global $config, $db, $user, $auth, $phpbb_dispatcher; - $user_online_link = $online_userlist = ''; + $guests_online = $hidden_online = $l_online_users = $online_userlist = $visible_online = ''; + $user_online_link = $rowset = array(); // Need caps version of $item for language-strings $item_caps = strtoupper($item); @@ -4237,9 +4264,28 @@ function obtain_users_online_string($online_users, $item_id = 0, $item = 'forum' FROM ' . USERS_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $online_users['online_users']) . ' ORDER BY username_clean ASC'; + + /** + * Modify SQL query to obtain online users data + * + * @event core.obtain_users_online_string_sql + * @var array online_users Array with online users data + * from obtain_users_online() + * @var int item_id Restrict online users to item id + * @var string item Restrict online users to a certain + * session item, e.g. forum for + * session_forum_id + * @var string sql SQL query to obtain users online data + * @since 3.1.4-RC1 + */ + $vars = array('online_users', 'item_id', 'item', 'sql'); + extract($phpbb_dispatcher->trigger_event('core.obtain_users_online_string_sql', compact($vars))); + $result = $db->sql_query($sql); + $rowset = $db->sql_fetchrowset($result); + $db->sql_freeresult($result); - while ($row = $db->sql_fetchrow($result)) + foreach ($rowset as $row) { // User is logged in and therefore not a guest if ($row['user_id'] != ANONYMOUS) @@ -4251,13 +4297,12 @@ function obtain_users_online_string($online_users, $item_id = 0, $item = 'forum' if (!isset($online_users['hidden_users'][$row['user_id']]) || $auth->acl_get('u_viewonline')) { - $user_online_link = get_username_string(($row['user_type'] <> USER_IGNORE) ? 'full' : 'no_profile', $row['user_id'], $row['username'], $row['user_colour']); - $online_userlist .= ($online_userlist != '') ? ', ' . $user_online_link : $user_online_link; + $user_online_link[$row['user_id']] = get_username_string(($row['user_type'] <> USER_IGNORE) ? 'full' : 'no_profile', $row['user_id'], $row['username'], $row['user_colour']); } } } - $db->sql_freeresult($result); } + $online_userlist = implode(', ', $user_online_link); if (!$online_userlist) { @@ -4270,58 +4315,52 @@ function obtain_users_online_string($online_users, $item_id = 0, $item = 'forum' } else if ($config['load_online_guests']) { - $l_online = ($online_users['guests_online'] === 1) ? $user->lang['BROWSING_' . $item_caps . '_GUEST'] : $user->lang['BROWSING_' . $item_caps . '_GUESTS']; - $online_userlist = sprintf($l_online, $online_userlist, $online_users['guests_online']); + $online_userlist = $user->lang('BROWSING_' . $item_caps . '_GUESTS', $online_users['guests_online'], $online_userlist); } else { $online_userlist = sprintf($user->lang['BROWSING_' . $item_caps], $online_userlist); } // Build online listing - $vars_online = array( - 'ONLINE' => array('total_online', 'l_t_user_s', 0), - 'REG' => array('visible_online', 'l_r_user_s', !$config['load_online_guests']), - 'HIDDEN' => array('hidden_online', 'l_h_user_s', $config['load_online_guests']), - 'GUEST' => array('guests_online', 'l_g_user_s', 0) - ); + $visible_online = $user->lang('REG_USERS_TOTAL', (int) $online_users['visible_online']); + $hidden_online = $user->lang('HIDDEN_USERS_TOTAL', (int) $online_users['hidden_online']); - foreach ($vars_online as $l_prefix => $var_ary) + if ($config['load_online_guests']) { - if ($var_ary[2]) - { - $l_suffix = '_AND'; - } - else - { - $l_suffix = ''; - } - switch ($online_users[$var_ary[0]]) - { - case 0: - ${$var_ary[1]} = $user->lang[$l_prefix . '_USERS_ZERO_TOTAL' . $l_suffix]; - break; - - case 1: - ${$var_ary[1]} = $user->lang[$l_prefix . '_USER_TOTAL' . $l_suffix]; - break; - - default: - ${$var_ary[1]} = $user->lang[$l_prefix . '_USERS_TOTAL' . $l_suffix]; - break; - } + $guests_online = $user->lang('GUEST_USERS_TOTAL', (int) $online_users['guests_online']); + $l_online_users = $user->lang('ONLINE_USERS_TOTAL_GUESTS', (int) $online_users['total_online'], $visible_online, $hidden_online, $guests_online); } - unset($vars_online); - - $l_online_users = sprintf($l_t_user_s, $online_users['total_online']); - $l_online_users .= sprintf($l_r_user_s, $online_users['visible_online']); - $l_online_users .= sprintf($l_h_user_s, $online_users['hidden_online']); - - if ($config['load_online_guests']) + else { - $l_online_users .= sprintf($l_g_user_s, $online_users['guests_online']); + $l_online_users = $user->lang('ONLINE_USERS_TOTAL', (int) $online_users['total_online'], $visible_online, $hidden_online); } - + /** + * Modify online userlist data + * + * @event core.obtain_users_online_string_modify + * @var array online_users Array with online users data + * from obtain_users_online() + * @var int item_id Restrict online users to item id + * @var string item Restrict online users to a certain + * session item, e.g. forum for + * session_forum_id + * @var array rowset Array with online users data + * @var array user_online_link Array with online users items (usernames) + * @var string online_userlist String containing users online list + * @var string l_online_users String with total online users count info + * @since 3.1.4-RC1 + */ + $vars = array( + 'online_users', + 'item_id', + 'item', + 'rowset', + 'user_online_link', + 'online_userlist', + 'l_online_users', + ); + extract($phpbb_dispatcher->trigger_event('core.obtain_users_online_string_modify', compact($vars))); return array( 'online_userlist' => $online_userlist, @@ -4365,6 +4404,178 @@ function phpbb_optionset($bit, $set, $data) } /** +* Determine which plural form we should use. +* For some languages this is not as simple as for English. +* +* @param $rule int ID of the plural rule we want to use, see http://wiki.phpbb.com/Plural_Rules#Plural_Rules +* @param $number int|float The number we want to get the plural case for. Float numbers are floored. +* @return int The plural-case we need to use for the number plural-rule combination +*/ +function phpbb_get_plural_form($rule, $number) +{ + $number = (int) $number; + + if ($rule > 15 || $rule < 0) + { + trigger_error('INVALID_PLURAL_RULE'); + } + + /** + * The following plural rules are based on a list published by the Mozilla Developer Network + * https://developer.mozilla.org/en/Localization_and_Plurals + */ + switch ($rule) + { + case 0: + /** + * Families: Asian (Chinese, Japanese, Korean, Vietnamese), Persian, Turkic/Altaic (Turkish), Thai, Lao + * 1 - everything: 0, 1, 2, ... + */ + return 1; + + case 1: + /** + * Families: Germanic (Danish, Dutch, English, Faroese, Frisian, German, Norwegian, Swedish), Finno-Ugric (Estonian, Finnish, Hungarian), Language isolate (Basque), Latin/Greek (Greek), Semitic (Hebrew), Romanic (Italian, Portuguese, Spanish, Catalan) + * 1 - 1 + * 2 - everything else: 0, 2, 3, ... + */ + return ($number == 1) ? 1 : 2; + + case 2: + /** + * Families: Romanic (French, Brazilian Portuguese) + * 1 - 0, 1 + * 2 - everything else: 2, 3, ... + */ + return (($number == 0) || ($number == 1)) ? 1 : 2; + + case 3: + /** + * Families: Baltic (Latvian) + * 1 - 0 + * 2 - ends in 1, not 11: 1, 21, ... 101, 121, ... + * 3 - everything else: 2, 3, ... 10, 11, 12, ... 20, 22, ... + */ + return ($number == 0) ? 1 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 2 : 3); + + case 4: + /** + * Families: Celtic (Scottish Gaelic) + * 1 - is 1 or 11: 1, 11 + * 2 - is 2 or 12: 2, 12 + * 3 - others between 3 and 19: 3, 4, ... 10, 13, ... 18, 19 + * 4 - everything else: 0, 20, 21, ... + */ + return ($number == 1 || $number == 11) ? 1 : (($number == 2 || $number == 12) ? 2 : (($number >= 3 && $number <= 19) ? 3 : 4)); + + case 5: + /** + * Families: Romanic (Romanian) + * 1 - 1 + * 2 - is 0 or ends in 01-19: 0, 2, 3, ... 19, 101, 102, ... 119, 201, ... + * 3 - everything else: 20, 21, ... + */ + return ($number == 1) ? 1 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 2 : 3); + + case 6: + /** + * Families: Baltic (Lithuanian) + * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ... + * 2 - ends in 0 or ends in 10-20: 0, 10, 11, 12, ... 19, 20, 30, 40, ... + * 3 - everything else: 2, 3, ... 8, 9, 22, 23, ... 29, 32, 33, ... + */ + return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 < 2) || (($number % 100 >= 10) && ($number % 100 < 20))) ? 2 : 3); + + case 7: + /** + * Families: Slavic (Croatian, Serbian, Russian, Ukrainian) + * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ... + * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ... + * 3 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 26, ... + */ + return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 2 : 3); + + case 8: + /** + * Families: Slavic (Slovak, Czech) + * 1 - 1 + * 2 - 2, 3, 4 + * 3 - everything else: 0, 5, 6, 7, ... + */ + return ($number == 1) ? 1 : ((($number >= 2) && ($number <= 4)) ? 2 : 3); + + case 9: + /** + * Families: Slavic (Polish) + * 1 - 1 + * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ... 104, 122, ... + * 3 - everything else: 0, 5, 6, ... 11, 12, 13, 14, 15, ... 20, 21, 25, ... + */ + return ($number == 1) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 2 : 3); + + case 10: + /** + * Families: Slavic (Slovenian, Sorbian) + * 1 - ends in 01: 1, 101, 201, ... + * 2 - ends in 02: 2, 102, 202, ... + * 3 - ends in 03-04: 3, 4, 103, 104, 203, 204, ... + * 4 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, ... + */ + return ($number % 100 == 1) ? 1 : (($number % 100 == 2) ? 2 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 3 : 4)); + + case 11: + /** + * Families: Celtic (Irish Gaeilge) + * 1 - 1 + * 2 - 2 + * 3 - is 3-6: 3, 4, 5, 6 + * 4 - is 7-10: 7, 8, 9, 10 + * 5 - everything else: 0, 11, 12, ... + */ + return ($number == 1) ? 1 : (($number == 2) ? 2 : (($number >= 3 && $number <= 6) ? 3 : (($number >= 7 && $number <= 10) ? 4 : 5))); + + case 12: + /** + * Families: Semitic (Arabic) + * 1 - 1 + * 2 - 2 + * 3 - ends in 03-10: 3, 4, ... 10, 103, 104, ... 110, 203, 204, ... + * 4 - ends in 11-99: 11, ... 99, 111, 112, ... + * 5 - everything else: 100, 101, 102, 200, 201, 202, ... + * 6 - 0 + */ + return ($number == 1) ? 1 : (($number == 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : (($number != 0) ? 5 : 6)))); + + case 13: + /** + * Families: Semitic (Maltese) + * 1 - 1 + * 2 - is 0 or ends in 01-10: 0, 2, 3, ... 9, 10, 101, 102, ... + * 3 - ends in 11-19: 11, 12, ... 18, 19, 111, 112, ... + * 4 - everything else: 20, 21, ... + */ + return ($number == 1) ? 1 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 2 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 3 : 4)); + + case 14: + /** + * Families: Slavic (Macedonian) + * 1 - ends in 1: 1, 11, 21, ... + * 2 - ends in 2: 2, 12, 22, ... + * 3 - everything else: 0, 3, 4, ... 10, 13, 14, ... 20, 23, ... + */ + return ($number % 10 == 1) ? 1 : (($number % 10 == 2) ? 2 : 3); + + case 15: + /** + * Families: Icelandic + * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, 131, ... + * 2 - everything else: 0, 2, 3, ... 10, 11, 12, ... 20, 22, ... + */ + return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2; + } +} + +/** * Login using http authenticate. * * @param array $param Parameter array, see $param_defaults array. @@ -4373,7 +4584,7 @@ function phpbb_optionset($bit, $set, $data) */ function phpbb_http_login($param) { - global $auth, $user; + global $auth, $user, $request; global $config; $param_defaults = array( @@ -4413,9 +4624,9 @@ function phpbb_http_login($param) $username = null; foreach ($username_keys as $k) { - if (isset($_SERVER[$k])) + if ($request->is_set($k, \phpbb\request\request_interface::SERVER)) { - $username = $_SERVER[$k]; + $username = htmlspecialchars_decode($request->server($k)); break; } } @@ -4423,9 +4634,9 @@ function phpbb_http_login($param) $password = null; foreach ($password_keys as $k) { - if (isset($_SERVER[$k])) + if ($request->is_set($k, \phpbb\request\request_interface::SERVER)) { - $password = $_SERVER[$k]; + $password = htmlspecialchars_decode($request->server($k)); break; } } @@ -4468,11 +4679,193 @@ function phpbb_http_login($param) } /** +* Escapes and quotes a string for use as an HTML/XML attribute value. +* +* This is a port of Python xml.sax.saxutils quoteattr. +* +* The function will attempt to choose a quote character in such a way as to +* avoid escaping quotes in the string. If this is not possible the string will +* be wrapped in double quotes and double quotes will be escaped. +* +* @param string $data The string to be escaped +* @param array $entities Associative array of additional entities to be escaped +* @return string Escaped and quoted string +*/ +function phpbb_quoteattr($data, $entities = null) +{ + $data = str_replace('&', '&', $data); + $data = str_replace('>', '>', $data); + $data = str_replace('<', '<', $data); + + $data = str_replace("\n", ' ', $data); + $data = str_replace("\r", ' ', $data); + $data = str_replace("\t", '	', $data); + + if (!empty($entities)) + { + $data = str_replace(array_keys($entities), array_values($entities), $data); + } + + if (strpos($data, '"') !== false) + { + if (strpos($data, "'") !== false) + { + $data = '"' . str_replace('"', '"', $data) . '"'; + } + else + { + $data = "'" . $data . "'"; + } + } + else + { + $data = '"' . $data . '"'; + } + + return $data; +} + +/** +* Converts query string (GET) parameters in request into hidden fields. +* +* Useful for forwarding GET parameters when submitting forms with GET method. +* +* It is possible to omit some of the GET parameters, which is useful if +* they are specified in the form being submitted. +* +* sid is always omitted. +* +* @param \phpbb\request\request $request Request object +* @param array $exclude A list of variable names that should not be forwarded +* @return string HTML with hidden fields +*/ +function phpbb_build_hidden_fields_for_query_params($request, $exclude = null) +{ + $names = $request->variable_names(\phpbb\request\request_interface::GET); + $hidden = ''; + foreach ($names as $name) + { + // Sessions are dealt with elsewhere, omit sid always + if ($name == 'sid') + { + continue; + } + + // Omit any additional parameters requested + if (!empty($exclude) && in_array($name, $exclude)) + { + continue; + } + + $escaped_name = phpbb_quoteattr($name); + + // Note: we might retrieve the variable from POST or cookies + // here. To avoid exposing cookies, skip variables that are + // overwritten somewhere other than GET entirely. + $value = $request->variable($name, '', true); + $get_value = $request->variable($name, '', true, \phpbb\request\request_interface::GET); + if ($value === $get_value) + { + $escaped_value = phpbb_quoteattr($value); + $hidden .= "<input type='hidden' name=$escaped_name value=$escaped_value />"; + } + } + return $hidden; +} + +/** +* Get user avatar +* +* @param array $user_row Row from the users table +* @param string $alt Optional language string for alt tag within image, can be a language key or text +* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP +* +* @return string Avatar html +*/ +function phpbb_get_user_avatar($user_row, $alt = 'USER_AVATAR', $ignore_config = false) +{ + $row = \phpbb\avatar\manager::clean_row($user_row, 'user'); + return phpbb_get_avatar($row, $alt, $ignore_config); +} + +/** +* Get group avatar +* +* @param array $group_row Row from the groups table +* @param string $alt Optional language string for alt tag within image, can be a language key or text +* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP +* +* @return string Avatar html +*/ +function phpbb_get_group_avatar($user_row, $alt = 'GROUP_AVATAR', $ignore_config = false) +{ + $row = \phpbb\avatar\manager::clean_row($user_row, 'group'); + return phpbb_get_avatar($row, $alt, $ignore_config); +} + +/** +* Get avatar +* +* @param array $row Row cleaned by \phpbb\avatar\manager::clean_row +* @param string $alt Optional language string for alt tag within image, can be a language key or text +* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP +* +* @return string Avatar html +*/ +function phpbb_get_avatar($row, $alt, $ignore_config = false) +{ + global $user, $config, $cache, $phpbb_root_path, $phpEx; + global $request; + global $phpbb_container; + + if (!$config['allow_avatar'] && !$ignore_config) + { + return ''; + } + + $avatar_data = array( + 'src' => $row['avatar'], + 'width' => $row['avatar_width'], + 'height' => $row['avatar_height'], + ); + + $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); + $driver = $phpbb_avatar_manager->get_driver($row['avatar_type'], $ignore_config); + $html = ''; + + if ($driver) + { + $html = $driver->get_custom_html($user, $row, $alt); + if (!empty($html)) + { + return $html; + } + + $avatar_data = $driver->get_data($row, $ignore_config); + } + else + { + $avatar_data['src'] = ''; + } + + if (!empty($avatar_data['src'])) + { + $html = '<img src="' . $avatar_data['src'] . '" ' . + ($avatar_data['width'] ? ('width="' . $avatar_data['width'] . '" ') : '') . + ($avatar_data['height'] ? ('height="' . $avatar_data['height'] . '" ') : '') . + 'alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />'; + } + + return $html; +} + +/** * Generate page header */ -function page_header($page_title = '', $display_online_list = true, $item_id = 0, $item = 'forum') +function page_header($page_title = '', $display_online_list = false, $item_id = 0, $item = 'forum') { global $db, $config, $template, $SID, $_SID, $_EXTRA_URL, $user, $auth, $phpEx, $phpbb_root_path; + global $phpbb_dispatcher, $request, $phpbb_container, $phpbb_admin_path; if (defined('HEADER_INC')) { @@ -4481,6 +4874,31 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 define('HEADER_INC', true); + // A listener can set this variable to `true` when it overrides this function + $page_header_override = false; + + /** + * Execute code and/or overwrite page_header() + * + * @event core.page_header + * @var string page_title Page title + * @var bool display_online_list Do we display online users list + * @var string item Restrict online users to a certain + * session item, e.g. forum for + * session_forum_id + * @var int item_id Restrict online users to item id + * @var bool page_header_override Shall we return instead of running + * the rest of page_header() + * @since 3.1.0-a1 + */ + $vars = array('page_title', 'display_online_list', 'item_id', 'item', 'page_header_override'); + extract($phpbb_dispatcher->trigger_event('core.page_header', compact($vars))); + + if ($page_header_override) + { + return; + } + // gzip_compression if ($config['gzip_compress']) { @@ -4508,7 +4926,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 if ($user->data['user_id'] != ANONYMOUS) { $u_login_logout = append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout', true, $user->session_id); - $l_login_logout = sprintf($user->lang['LOGOUT_USER'], $user->data['username']); + $l_login_logout = $user->lang['LOGOUT']; } else { @@ -4543,23 +4961,18 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 set_config('record_online_date', time(), true); } - $l_online_record = sprintf($user->lang['RECORD_ONLINE_USERS'], $config['record_online_users'], $user->format_date($config['record_online_date'], false, true)); + $l_online_record = $user->lang('RECORD_ONLINE_USERS', (int) $config['record_online_users'], $user->format_date($config['record_online_date'], false, true)); - $l_online_time = ($config['load_online_time'] == 1) ? 'VIEW_ONLINE_TIME' : 'VIEW_ONLINE_TIMES'; - $l_online_time = sprintf($user->lang[$l_online_time], $config['load_online_time']); + $l_online_time = $user->lang('VIEW_ONLINE_TIMES', (int) $config['load_online_time']); } - $l_privmsgs_text = $l_privmsgs_text_unread = ''; $s_privmsg_new = false; - // Obtain number of new private messages if user is logged in + // Check for new private messages if user is logged in if (!empty($user->data['is_registered'])) { if ($user->data['user_new_privmsg']) { - $l_message_new = ($user->data['user_new_privmsg'] == 1) ? $user->lang['NEW_PM'] : $user->lang['NEW_PMS']; - $l_privmsgs_text = sprintf($l_message_new, $user->data['user_new_privmsg']); - if (!$user->data['user_last_privmsg'] || $user->data['user_last_privmsg'] > $user->data['session_last_visit']) { $sql = 'UPDATE ' . USERS_TABLE . ' @@ -4576,17 +4989,8 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 } else { - $l_privmsgs_text = $user->lang['NO_NEW_PM']; $s_privmsg_new = false; } - - $l_privmsgs_text_unread = ''; - - if ($user->data['user_unread_privmsg'] && $user->data['user_unread_privmsg'] != $user->data['user_new_privmsg']) - { - $l_message_unread = ($user->data['user_unread_privmsg'] == 1) ? $user->lang['UNREAD_PM'] : $user->lang['UNREAD_PMS']; - $l_privmsgs_text_unread = sprintf($l_message_unread, $user->data['user_unread_privmsg']); - } } $forum_id = request_var('f', 0); @@ -4607,10 +5011,12 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 // Determine board url - we may need it later $board_url = generate_board_url() . '/'; - $web_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? $board_url : $phpbb_root_path; - - // Which timezone? - $tz = ($user->data['user_id'] != ANONYMOUS) ? strval(doubleval($user->data['user_timezone'])) : strval(doubleval($config['board_timezone'])); + // This path is sent with the base template paths in the assign_vars() + // call below. We need to correct it in case we are accessing from a + // controller because the web paths will be incorrect otherwise. + $phpbb_path_helper = $phpbb_container->get('path_helper'); + $corrected_path = $phpbb_path_helper->get_web_root_path(); + $web_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? $board_url : $corrected_path; // Send a proper content-language to the output $user_lang = $user->lang['USER_LANG']; @@ -4634,6 +5040,33 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 } } + $dt = $user->create_datetime(); + $timezone_offset = $user->lang(array('timezones', 'UTC_OFFSET'), phpbb_format_timezone_offset($dt->getOffset())); + $timezone_name = $user->timezone->getName(); + if (isset($user->lang['timezones'][$timezone_name])) + { + $timezone_name = $user->lang['timezones'][$timezone_name]; + } + + // Output the notifications + $notifications = false; + if ($config['load_notifications'] && $user->data['user_id'] != ANONYMOUS && $user->data['user_type'] != USER_IGNORE) + { + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + $notifications = $phpbb_notifications->load_notifications(array( + 'all_unread' => true, + 'limit' => 5, + )); + + foreach ($notifications['notifications'] as $notification) + { + $template->assign_block_vars('notifications', $notification->prepare_for_display()); + } + } + + $notification_mark_hash = generate_link_hash('mark_all_notifications_read'); + // The following assigns all _common_ variables that may be used at any point in a template. $template->assign_vars(array( 'SITENAME' => $config['sitename'], @@ -4646,8 +5079,17 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'TOTAL_USERS_ONLINE' => $l_online_users, 'LOGGED_IN_USER_LIST' => $online_userlist, 'RECORD_USERS' => $l_online_record, - 'PRIVATE_MESSAGE_INFO' => $l_privmsgs_text, - 'PRIVATE_MESSAGE_INFO_UNREAD' => $l_privmsgs_text_unread, + + 'PRIVATE_MESSAGE_COUNT' => (!empty($user->data['user_unread_privmsg'])) ? $user->data['user_unread_privmsg'] : 0, + 'CURRENT_USER_AVATAR' => phpbb_get_user_avatar($user->data), + 'CURRENT_USERNAME_SIMPLE' => get_username_string('no_profile', $user->data['user_id'], $user->data['username'], $user->data['user_colour']), + 'CURRENT_USERNAME_FULL' => get_username_string('full', $user->data['user_id'], $user->data['username'], $user->data['user_colour']), + 'UNREAD_NOTIFICATIONS_COUNT' => ($notifications !== false) ? $notifications['unread_count'] : '', + 'NOTIFICATIONS_COUNT' => ($notifications !== false) ? $notifications['unread_count'] : '', + 'U_VIEW_ALL_NOTIFICATIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications'), + 'U_MARK_ALL_NOTIFICATIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications&mode=notification_list&mark=all&token=' . $notification_mark_hash), + 'U_NOTIFICATION_SETTINGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications&mode=notification_options'), + 'S_NOTIFICATIONS_DISPLAY' => $config['load_notifications'], 'S_USER_NEW_PRIVMSG' => $user->data['user_new_privmsg'], 'S_USER_UNREAD_PRIVMSG' => $user->data['user_unread_privmsg'], @@ -4656,24 +5098,25 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'SID' => $SID, '_SID' => $_SID, 'SESSION_ID' => $user->session_id, - 'ROOT_PATH' => $phpbb_root_path, + 'ROOT_PATH' => $web_path, 'BOARD_URL' => $board_url, 'L_LOGIN_LOGOUT' => $l_login_logout, - 'L_INDEX' => $user->lang['FORUM_INDEX'], + 'L_INDEX' => ($config['board_index_text'] !== '') ? $config['board_index_text'] : $user->lang['FORUM_INDEX'], + 'L_SITE_HOME' => ($config['site_home_text'] !== '') ? $config['site_home_text'] : $user->lang['HOME'], 'L_ONLINE_EXPLAIN' => $l_online_time, 'U_PRIVATEMSGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'), 'U_RETURN_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'), - 'U_POPUP_PM' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=popup'), - 'UA_POPUP_PM' => addslashes(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=popup')), 'U_MEMBERLIST' => append_sid("{$phpbb_root_path}memberlist.$phpEx"), 'U_VIEWONLINE' => ($auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel')) ? append_sid("{$phpbb_root_path}viewonline.$phpEx") : '', 'U_LOGIN_LOGOUT' => $u_login_logout, 'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"), 'U_SEARCH' => append_sid("{$phpbb_root_path}search.$phpEx"), + 'U_SITE_HOME' => $config['site_home_url'], 'U_REGISTER' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), 'U_PROFILE' => append_sid("{$phpbb_root_path}ucp.$phpEx"), + 'U_USER_PROFILE' => get_username_string('profile', $user->data['user_id'], $user->data['username'], $user->data['user_colour']), 'U_MODCP' => append_sid("{$phpbb_root_path}mcp.$phpEx", false, true, $user->session_id), 'U_FAQ' => append_sid("{$phpbb_root_path}faq.$phpEx"), 'U_SEARCH_SELF' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=egosearch'), @@ -4682,7 +5125,8 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'U_SEARCH_UNREAD' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unreadposts'), 'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'), 'U_DELETE_COOKIES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'), - 'U_TEAM' => ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile')) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=leaders'), + 'U_CONTACT_US' => ($config['contact_admin_form_enable'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin') : '', + 'U_TEAM' => ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile')) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=team'), 'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'), 'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'), 'U_RESTORE_PERMISSIONS' => ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '', @@ -4693,7 +5137,6 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'S_BOARD_DISABLED' => ($config['board_disable']) ? true : false, 'S_REGISTERED_USER' => (!empty($user->data['is_registered'])) ? true : false, 'S_IS_BOT' => (!empty($user->data['is_bot'])) ? true : false, - 'S_USER_PM_POPUP' => $user->optionget('popuppm'), 'S_USER_LANG' => $user_lang, 'S_USER_BROWSER' => (isset($user->data['session_browser'])) ? $user->data['session_browser'] : $user->lang['UNKNOWN_BROWSER'], 'S_USERNAME' => $user->data['username'], @@ -4701,7 +5144,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'S_CONTENT_FLOW_BEGIN' => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right', 'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left', 'S_CONTENT_ENCODING' => 'UTF-8', - 'S_TIMEZONE' => ($user->data['user_dst'] || ($user->data['user_id'] == ANONYMOUS && $config['board_dst'])) ? sprintf($user->lang['ALL_TIMES'], $user->lang['tz'][$tz], $user->lang['tz']['dst']) : sprintf($user->lang['ALL_TIMES'], $user->lang['tz'][$tz], ''), + 'S_TIMEZONE' => sprintf($user->lang['ALL_TIMES'], $timezone_offset, $timezone_name), 'S_DISPLAY_ONLINE_LIST' => ($l_online_time) ? 1 : 0, 'S_DISPLAY_SEARCH' => (!$config['load_search']) ? 0 : (isset($auth) ? ($auth->acl_get('u_search') && $auth->acl_getf_global('f_search')) : 1), 'S_DISPLAY_PM' => ($config['allow_privmsg'] && !empty($user->data['is_registered']) && ($auth->acl_get('u_readpm') || $auth->acl_get('u_sendpm'))) ? true : false, @@ -4711,8 +5154,8 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'S_FORUM_ID' => $forum_id, 'S_TOPIC_ID' => $topic_id, - 'S_LOGIN_ACTION' => ((!defined('ADMIN_START')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("index.$phpEx", false, true, $user->session_id)), - 'S_LOGIN_REDIRECT' => build_hidden_fields(array('redirect' => build_url())), + 'S_LOGIN_ACTION' => ((!defined('ADMIN_START')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("{$phpbb_admin_path}index.$phpEx", false, true, $user->session_id)), + 'S_LOGIN_REDIRECT' => build_hidden_fields(array('redirect' => $phpbb_path_helper->remove_web_root_path(build_url()))), 'S_ENABLE_FEEDS' => ($config['feed_enable']) ? true : false, 'S_ENABLE_FEEDS_OVERALL' => ($config['feed_overall']) ? true : false, @@ -4725,11 +5168,11 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'S_SEARCH_HIDDEN_FIELDS' => build_hidden_fields($s_search_hidden_fields), - 'T_THEME_PATH' => "{$web_path}styles/" . rawurlencode($user->theme['theme_path']) . '/theme', - 'T_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->theme['template_path']) . '/template', - 'T_SUPER_TEMPLATE_PATH' => (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? "{$web_path}styles/" . rawurlencode($user->theme['template_inherit_path']) . '/template' : "{$web_path}styles/" . rawurlencode($user->theme['template_path']) . '/template', - 'T_IMAGESET_PATH' => "{$web_path}styles/" . rawurlencode($user->theme['imageset_path']) . '/imageset', - 'T_IMAGESET_LANG_PATH' => "{$web_path}styles/" . rawurlencode($user->theme['imageset_path']) . '/imageset/' . $user->lang_name, + 'T_ASSETS_VERSION' => $config['assets_version'], + 'T_ASSETS_PATH' => "{$web_path}assets", + 'T_THEME_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme', + 'T_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/template', + 'T_SUPER_TEMPLATE_PATH' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/template', 'T_IMAGES_PATH' => "{$web_path}images/", 'T_SMILIES_PATH' => "{$web_path}{$config['smilies_path']}/", 'T_AVATAR_PATH' => "{$web_path}{$config['avatar_path']}/", @@ -4737,14 +5180,15 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'T_ICONS_PATH' => "{$web_path}{$config['icons_path']}/", 'T_RANKS_PATH' => "{$web_path}{$config['ranks_path']}/", 'T_UPLOAD_PATH' => "{$web_path}{$config['upload_path']}/", - 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . rawurlencode($user->theme['theme_path']) . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&lang=' . $user->lang_name), - 'T_STYLESHEET_NAME' => $user->theme['theme_name'], - - 'T_THEME_NAME' => rawurlencode($user->theme['theme_path']), - 'T_TEMPLATE_NAME' => rawurlencode($user->theme['template_path']), - 'T_SUPER_TEMPLATE_NAME' => rawurlencode((isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? $user->theme['template_inherit_path'] : $user->theme['template_path']), - 'T_IMAGESET_NAME' => rawurlencode($user->theme['imageset_path']), - 'T_IMAGESET_LANG_NAME' => $user->data['user_lang'], + 'T_STYLESHEET_LINK' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme/stylesheet.css?assets_version=' . $config['assets_version'], + 'T_STYLESHEET_LANG_LINK' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme/' . $user->lang_name . '/stylesheet.css?assets_version=' . $config['assets_version'], + 'T_JQUERY_LINK' => !empty($config['allow_cdn']) && !empty($config['load_jquery_url']) ? $config['load_jquery_url'] : "{$web_path}assets/javascript/jquery.min.js?assets_version=" . $config['assets_version'], + 'S_ALLOW_CDN' => !empty($config['allow_cdn']), + + 'T_THEME_NAME' => rawurlencode($user->style['style_path']), + 'T_THEME_LANG_NAME' => $user->data['user_lang'], + 'T_TEMPLATE_NAME' => $user->style['style_path'], + 'T_SUPER_TEMPLATE_NAME' => rawurlencode((isset($user->style['style_parent_tree']) && $user->style['style_parent_tree']) ? $user->style['style_parent_tree'] : $user->style['style_path']), 'T_IMAGES' => 'images', 'T_SMILIES' => $config['smilies_path'], 'T_AVATAR' => $config['avatar_path'], @@ -4754,75 +5198,169 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'T_UPLOAD' => $config['upload_path'], 'SITE_LOGO_IMG' => $user->img('site_logo'), - - 'A_COOKIE_SETTINGS' => addslashes('; path=' . $config['cookie_path'] . ((!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain']) . ((!$config['cookie_secure']) ? '' : '; secure')), )); - // application/xhtml+xml not used because of IE - header('Content-type: text/html; charset=UTF-8'); - - header('Cache-Control: private, no-cache="set-cookie"'); - header('Expires: 0'); - header('Pragma: no-cache'); - + // An array of http headers that phpbb will set. The following event may override these. + $http_headers = array( + // application/xhtml+xml not used because of IE + 'Content-type' => 'text/html; charset=UTF-8', + 'Cache-Control' => 'private, no-cache="set-cookie"', + 'Expires' => gmdate('D, d M Y H:i:s', time()) . ' GMT', + ); if (!empty($user->data['is_bot'])) { // Let reverse proxies know we detected a bot. - header('X-PHPBB-IS-BOT: yes'); + $http_headers['X-PHPBB-IS-BOT'] = 'yes'; + } + + /** + * Execute code and/or overwrite _common_ template variables after they have been assigned. + * + * @event core.page_header_after + * @var string page_title Page title + * @var bool display_online_list Do we display online users list + * @var string item Restrict online users to a certain + * session item, e.g. forum for + * session_forum_id + * @var int item_id Restrict online users to item id + * @var array http_headers HTTP headers that should be set by phpbb + * + * @since 3.1.0-b3 + */ + $vars = array('page_title', 'display_online_list', 'item_id', 'item', 'http_headers'); + extract($phpbb_dispatcher->trigger_event('core.page_header_after', compact($vars))); + + foreach ($http_headers as $hname => $hval) + { + header((string) $hname . ': ' . (string) $hval); } return; } /** -* Generate page footer +* Check and display the SQL report if requested. +* +* @param \phpbb\request\request_interface $request Request object +* @param \phpbb\auth\auth $auth Auth object +* @param \phpbb\db\driver\driver_interface $db Database connection */ -function page_footer($run_cron = true) +function phpbb_check_and_display_sql_report(\phpbb\request\request_interface $request, \phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db) { - global $db, $config, $template, $user, $auth, $cache, $starttime, $phpbb_root_path, $phpEx; + if ($request->variable('explain', false) && $auth->acl_get('a_') && defined('DEBUG')) + { + $db->sql_report('display'); + } +} + +/** +* Generate the debug output string +* +* @param \phpbb\db\driver\driver_interface $db Database connection +* @param \phpbb\config\config $config Config object +* @param \phpbb\auth\auth $auth Auth object +* @param \phpbb\user $user User object +* @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher +* @return string +*/ +function phpbb_generate_debug_output(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\auth\auth $auth, \phpbb\user $user, \phpbb\event\dispatcher_interface $phpbb_dispatcher) +{ + $debug_info = array(); // Output page creation time - if (defined('DEBUG')) + if (defined('PHPBB_DISPLAY_LOAD_TIME')) { - $mtime = explode(' ', microtime()); - $totaltime = $mtime[0] + $mtime[1] - $starttime; - - if (!empty($_REQUEST['explain']) && $auth->acl_get('a_') && defined('DEBUG_EXTRA') && method_exists($db, 'sql_report')) + if (isset($GLOBALS['starttime'])) { - $db->sql_report('display'); + $totaltime = microtime(true) - $GLOBALS['starttime']; + $debug_info[] = sprintf('<abbr title="SQL time: %.3fs / PHP time: %.3fs">Time: %.3fs</abbr>', $db->get_sql_time(), ($totaltime - $db->get_sql_time()), $totaltime); } - $debug_output = sprintf('Time : %.3fs | ' . $db->sql_num_queries() . ' Queries | GZIP : ' . (($config['gzip_compress'] && @extension_loaded('zlib')) ? 'On' : 'Off') . (($user->load) ? ' | Load : ' . $user->load : ''), $totaltime); + $debug_info[] = sprintf('<abbr title="Cached: %d">Queries: %d</abbr>', $db->sql_num_queries(true), $db->sql_num_queries()); - if ($auth->acl_get('a_') && defined('DEBUG_EXTRA')) + $memory_usage = memory_get_peak_usage(); + if ($memory_usage) { - if (function_exists('memory_get_usage')) - { - if ($memory_usage = memory_get_usage()) - { - global $base_memory_usage; - $memory_usage -= $base_memory_usage; - $memory_usage = get_formatted_filesize($memory_usage); + $memory_usage = get_formatted_filesize($memory_usage); - $debug_output .= ' | Memory Usage: ' . $memory_usage; - } - } + $debug_info[] = 'Peak Memory Usage: ' . $memory_usage; + } + } - $debug_output .= ' | <a href="' . build_url() . '&explain=1">Explain</a>'; + if (defined('DEBUG')) + { + $debug_info[] = 'GZIP: ' . (($config['gzip_compress'] && @extension_loaded('zlib')) ? 'On' : 'Off'); + + if ($user->load) + { + $debug_info[] = 'Load: ' . $user->load; } + + if ($auth->acl_get('a_')) + { + $debug_info[] = '<a href="' . build_url() . '&explain=1">SQL Explain</a>'; + } + } + + /** + * Modify debug output information + * + * @event core.phpbb_generate_debug_output + * @var array debug_info Array of strings with debug information + * + * @since 3.1.0-RC3 + */ + $vars = array('debug_info'); + extract($phpbb_dispatcher->trigger_event('core.phpbb_generate_debug_output', compact($vars))); + + return implode(' | ', $debug_info); +} + +/** +* Generate page footer +* +* @param bool $run_cron Whether or not to run the cron +* @param bool $display_template Whether or not to display the template +* @param bool $exit_handler Whether or not to run the exit_handler() +*/ +function page_footer($run_cron = true, $display_template = true, $exit_handler = true) +{ + global $db, $config, $template, $user, $auth, $cache, $starttime, $phpbb_root_path, $phpEx; + global $request, $phpbb_dispatcher, $phpbb_admin_path; + + // A listener can set this variable to `true` when it overrides this function + $page_footer_override = false; + + /** + * Execute code and/or overwrite page_footer() + * + * @event core.page_footer + * @var bool run_cron Shall we run cron tasks + * @var bool page_footer_override Shall we return instead of running + * the rest of page_footer() + * @since 3.1.0-a1 + */ + $vars = array('run_cron', 'page_footer_override'); + extract($phpbb_dispatcher->trigger_event('core.page_footer', compact($vars))); + + if ($page_footer_override) + { + return; } + phpbb_check_and_display_sql_report($request, $auth, $db); + $template->assign_vars(array( - 'DEBUG_OUTPUT' => (defined('DEBUG')) ? $debug_output : '', + 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user, $phpbb_dispatcher), 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', - 'CREDIT_LINE' => $user->lang('POWERED_BY', '<a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Group'), + 'CREDIT_LINE' => $user->lang('POWERED_BY', '<a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Limited'), - 'U_ACP' => ($auth->acl_get('a_') && !empty($user->data['is_registered'])) ? append_sid("{$phpbb_root_path}adm/index.$phpEx", false, true, $user->session_id) : '') + 'U_ACP' => ($auth->acl_get('a_') && !empty($user->data['is_registered'])) ? append_sid("{$phpbb_admin_path}index.$phpEx", false, true, $user->session_id) : '') ); // Call cron-type script $call_cron = false; - if (!defined('IN_CRON') && $run_cron && !$config['board_disable'] && !$user->data['is_bot']) + if (!defined('IN_CRON') && !$config['use_system_cron'] && $run_cron && !$config['board_disable'] && !$user->data['is_bot'] && !$cache->get('_cron.lock_check')) { $call_cron = true; $time_now = (!empty($user->time_now) && is_int($user->time_now)) ? $user->time_now : time(); @@ -4843,47 +5381,44 @@ function page_footer($run_cron = true) // Call cron job? if ($call_cron) { - $cron_type = ''; + global $phpbb_container; + $cron = $phpbb_container->get('cron.manager'); + $task = $cron->find_one_ready_task(); - if ($time_now - $config['queue_interval'] > $config['last_queue_run'] && !defined('IN_ADMIN') && file_exists($phpbb_root_path . 'cache/queue.' . $phpEx)) - { - // Process email queue - $cron_type = 'queue'; - } - else if (method_exists($cache, 'tidy') && $time_now - $config['cache_gc'] > $config['cache_last_gc']) - { - // Tidy the cache - $cron_type = 'tidy_cache'; - } - else if ($config['warnings_expire_days'] && ($time_now - $config['warnings_gc'] > $config['warnings_last_gc'])) - { - $cron_type = 'tidy_warnings'; - } - else if ($time_now - $config['database_gc'] > $config['database_last_gc']) - { - // Tidy the database - $cron_type = 'tidy_database'; - } - else if ($time_now - $config['search_gc'] > $config['search_last_gc']) + if ($task) { - // Tidy the search - $cron_type = 'tidy_search'; + $url = $task->get_url(); + $template->assign_var('RUN_CRON_TASK', '<img src="' . $url . '" width="1" height="1" alt="cron" />'); } - else if ($time_now - $config['session_gc'] > $config['session_last_gc']) - { - $cron_type = 'tidy_sessions'; - } - - if ($cron_type) + else { - $template->assign_var('RUN_CRON_TASK', '<img src="' . append_sid($phpbb_root_path . 'cron.' . $phpEx, 'cron_type=' . $cron_type) . '" width="1" height="1" alt="cron" />'); + $cache->put('_cron.lock_check', true, 60); } } - $template->display('body'); + /** + * Execute code and/or modify output before displaying the template. + * + * @event core.page_footer_after + * @var bool display_template Whether or not to display the template + * @var bool exit_handler Whether or not to run the exit_handler() + * + * @since 3.1.0-RC5 + */ + $vars = array('display_template', 'exit_handler'); + extract($phpbb_dispatcher->trigger_event('core.page_footer_after', compact($vars))); + + if ($display_template) + { + $template->display('body'); + } garbage_collection(); - exit_handler(); + + if ($exit_handler) + { + exit_handler(); + } } /** @@ -4893,6 +5428,18 @@ function page_footer($run_cron = true) function garbage_collection() { global $cache, $db; + global $phpbb_dispatcher; + + if (!empty($phpbb_dispatcher)) + { + /** + * Unload some objects, to free some memory, before we finish our task + * + * @event core.garbage_collection + * @since 3.1.0-a1 + */ + $phpbb_dispatcher->dispatch('core.garbage_collection'); + } // Unload cache, must be done before the DB connection if closed if (!empty($cache)) @@ -4932,7 +5479,7 @@ function exit_handler() } /** -* Handler for init calls in phpBB. This function is called in user::setup(); +* Handler for init calls in phpBB. This function is called in \phpbb\user::setup(); * This function supports hooks. */ function phpbb_user_session_handler() @@ -4950,4 +5497,70 @@ function phpbb_user_session_handler() return; } -?>
\ No newline at end of file +/** +* Check if PCRE has UTF-8 support +* PHP may not be linked with the bundled PCRE lib and instead with an older version +* +* @return bool Returns true if PCRE (the regular expressions library) supports UTF-8 encoding +*/ +function phpbb_pcre_utf8_support() +{ + static $utf8_pcre_properties = null; + if (is_null($utf8_pcre_properties)) + { + $utf8_pcre_properties = (@preg_match('/\p{L}/u', 'a') !== false); + } + return $utf8_pcre_properties; +} + +/** +* Casts a numeric string $input to an appropriate numeric type (i.e. integer or float) +* +* @param string $input A numeric string. +* +* @return int|float Integer $input if $input fits integer, +* float $input otherwise. +*/ +function phpbb_to_numeric($input) +{ + return ($input > PHP_INT_MAX) ? (float) $input : (int) $input; +} + +/** +* Get the board contact details (e.g. for emails) +* +* @param \phpbb\config\config $config +* @param string $phpEx +* @return string +*/ +function phpbb_get_board_contact(\phpbb\config\config $config, $phpEx) +{ + if ($config['contact_admin_form_enable']) + { + return generate_board_url() . '/memberlist.' . $phpEx . '?mode=contactadmin'; + } + else + { + return $config['board_contact']; + } +} + +/** +* Get a clickable board contact details link +* +* @param \phpbb\config\config $config +* @param string $phpbb_root_path +* @param string $phpEx +* @return string +*/ +function phpbb_get_board_contact_link(\phpbb\config\config $config, $phpbb_root_path, $phpEx) +{ + if ($config['contact_admin_form_enable'] && $config['email_enable']) + { + return append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin'); + } + else + { + return 'mailto:' . htmlspecialchars($config['board_contact']); + } +} diff --git a/phpBB/includes/functions_acp.php b/phpBB/includes/functions_acp.php new file mode 100644 index 0000000000..a53a54368e --- /dev/null +++ b/phpBB/includes/functions_acp.php @@ -0,0 +1,707 @@ +<?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. +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Header for acp pages +*/ +function adm_page_header($page_title) +{ + global $config, $db, $user, $template; + global $phpbb_root_path, $phpbb_admin_path, $phpEx, $SID, $_SID; + global $phpbb_dispatcher; + + if (defined('HEADER_INC')) + { + return; + } + + define('HEADER_INC', true); + + // A listener can set this variable to `true` when it overrides this function + $adm_page_header_override = false; + + /** + * Execute code and/or overwrite adm_page_header() + * + * @event core.adm_page_header + * @var string page_title Page title + * @var bool adm_page_header_override Shall we return instead of + * running the rest of adm_page_header() + * @since 3.1.0-a1 + */ + $vars = array('page_title', 'adm_page_header_override'); + extract($phpbb_dispatcher->trigger_event('core.adm_page_header', compact($vars))); + + if ($adm_page_header_override) + { + return; + } + + // gzip_compression + if ($config['gzip_compress']) + { + if (@extension_loaded('zlib') && !headers_sent()) + { + ob_start('ob_gzhandler'); + } + } + + $template->assign_vars(array( + 'PAGE_TITLE' => $page_title, + 'USERNAME' => $user->data['username'], + + 'SID' => $SID, + '_SID' => $_SID, + 'SESSION_ID' => $user->session_id, + 'ROOT_PATH' => $phpbb_root_path, + 'ADMIN_ROOT_PATH' => $phpbb_admin_path, + + 'U_LOGOUT' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=logout'), + 'U_ADM_LOGOUT' => append_sid("{$phpbb_admin_path}index.$phpEx", 'action=admlogout'), + 'U_ADM_INDEX' => append_sid("{$phpbb_admin_path}index.$phpEx"), + 'U_INDEX' => append_sid("{$phpbb_root_path}index.$phpEx"), + + 'T_IMAGES_PATH' => "{$phpbb_root_path}images/", + 'T_SMILIES_PATH' => "{$phpbb_root_path}{$config['smilies_path']}/", + 'T_AVATAR_PATH' => "{$phpbb_root_path}{$config['avatar_path']}/", + 'T_AVATAR_GALLERY_PATH' => "{$phpbb_root_path}{$config['avatar_gallery_path']}/", + 'T_ICONS_PATH' => "{$phpbb_root_path}{$config['icons_path']}/", + 'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/", + 'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/", + + 'T_ASSETS_VERSION' => $config['assets_version'], + + 'ICON_MOVE_UP' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_up.gif" alt="' . $user->lang['MOVE_UP'] . '" title="' . $user->lang['MOVE_UP'] . '" />', + 'ICON_MOVE_UP_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_up_disabled.gif" alt="' . $user->lang['MOVE_UP'] . '" title="' . $user->lang['MOVE_UP'] . '" />', + 'ICON_MOVE_DOWN' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_down.gif" alt="' . $user->lang['MOVE_DOWN'] . '" title="' . $user->lang['MOVE_DOWN'] . '" />', + 'ICON_MOVE_DOWN_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_down_disabled.gif" alt="' . $user->lang['MOVE_DOWN'] . '" title="' . $user->lang['MOVE_DOWN'] . '" />', + 'ICON_EDIT' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_edit.gif" alt="' . $user->lang['EDIT'] . '" title="' . $user->lang['EDIT'] . '" />', + 'ICON_EDIT_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_edit_disabled.gif" alt="' . $user->lang['EDIT'] . '" title="' . $user->lang['EDIT'] . '" />', + 'ICON_DELETE' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_delete.gif" alt="' . $user->lang['DELETE'] . '" title="' . $user->lang['DELETE'] . '" />', + 'ICON_DELETE_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_delete_disabled.gif" alt="' . $user->lang['DELETE'] . '" title="' . $user->lang['DELETE'] . '" />', + 'ICON_SYNC' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_sync.gif" alt="' . $user->lang['RESYNC'] . '" title="' . $user->lang['RESYNC'] . '" />', + 'ICON_SYNC_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_sync_disabled.gif" alt="' . $user->lang['RESYNC'] . '" title="' . $user->lang['RESYNC'] . '" />', + + 'S_USER_LANG' => $user->lang['USER_LANG'], + 'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'], + 'S_CONTENT_ENCODING' => 'UTF-8', + 'S_CONTENT_FLOW_BEGIN' => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right', + 'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left', + )); + + // An array of http headers that phpbb will set. The following event may override these. + $http_headers = array( + // application/xhtml+xml not used because of IE + 'Content-type' => 'text/html; charset=UTF-8', + 'Cache-Control' => 'private, no-cache="set-cookie"', + 'Expires' => gmdate('D, d M Y H:i:s', time()) . ' GMT', + ); + + /** + * Execute code and/or overwrite _common_ template variables after they have been assigned. + * + * @event core.adm_page_header_after + * @var string page_title Page title + * @var array http_headers HTTP headers that should be set by phpbb + * + * @since 3.1.0-RC3 + */ + $vars = array('page_title', 'http_headers'); + extract($phpbb_dispatcher->trigger_event('core.adm_page_header_after', compact($vars))); + + foreach ($http_headers as $hname => $hval) + { + header((string) $hname . ': ' . (string) $hval); + } + + return; +} + +/** +* Page footer for acp pages +*/ +function adm_page_footer($copyright_html = true) +{ + global $db, $config, $template, $user, $auth, $cache; + global $starttime, $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $request, $phpbb_dispatcher; + + // A listener can set this variable to `true` when it overrides this function + $adm_page_footer_override = false; + + /** + * Execute code and/or overwrite adm_page_footer() + * + * @event core.adm_page_footer + * @var bool copyright_html Shall we display the copyright? + * @var bool adm_page_footer_override Shall we return instead of + * running the rest of adm_page_footer() + * @since 3.1.0-a1 + */ + $vars = array('copyright_html', 'adm_page_footer_override'); + extract($phpbb_dispatcher->trigger_event('core.adm_page_footer', compact($vars))); + + if ($adm_page_footer_override) + { + return; + } + + phpbb_check_and_display_sql_report($request, $auth, $db); + + $template->assign_vars(array( + 'DEBUG_OUTPUT' => phpbb_generate_debug_output($db, $config, $auth, $user, $phpbb_dispatcher), + 'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '', + 'S_COPYRIGHT_HTML' => $copyright_html, + 'CREDIT_LINE' => $user->lang('POWERED_BY', '<a href="https://www.phpbb.com/">phpBB</a>® Forum Software © phpBB Limited'), + 'T_JQUERY_LINK' => !empty($config['allow_cdn']) && !empty($config['load_jquery_url']) ? $config['load_jquery_url'] : "{$phpbb_root_path}assets/javascript/jquery.min.js", + 'S_ALLOW_CDN' => !empty($config['allow_cdn']), + 'VERSION' => $config['version']) + ); + + $template->display('body'); + + garbage_collection(); + exit_handler(); +} + +/** +* Generate back link for acp pages +*/ +function adm_back_link($u_action) +{ + global $user; + return '<br /><br /><a href="' . $u_action . '">« ' . $user->lang['BACK_TO_PREV'] . '</a>'; +} + +/** +* Build select field options in acp pages +*/ +function build_select($option_ary, $option_default = false) +{ + global $user; + + $html = ''; + foreach ($option_ary as $value => $title) + { + $selected = ($option_default !== false && $value == $option_default) ? ' selected="selected"' : ''; + $html .= '<option value="' . $value . '"' . $selected . '>' . $user->lang[$title] . '</option>'; + } + + return $html; +} + +/** +* Build radio fields in acp pages +*/ +function h_radio($name, $input_ary, $input_default = false, $id = false, $key = false, $separator = '') +{ + global $user; + + $html = ''; + $id_assigned = false; + foreach ($input_ary as $value => $title) + { + $selected = ($input_default !== false && $value == $input_default) ? ' checked="checked"' : ''; + $html .= '<label><input type="radio" name="' . $name . '"' . (($id && !$id_assigned) ? ' id="' . $id . '"' : '') . ' value="' . $value . '"' . $selected . (($key) ? ' accesskey="' . $key . '"' : '') . ' class="radio" /> ' . $user->lang[$title] . '</label>' . $separator; + $id_assigned = true; + } + + return $html; +} + +/** +* Build configuration template for acp configuration pages +*/ +function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars) +{ + global $user, $module, $phpbb_dispatcher; + + $tpl = ''; + $name = 'config[' . $config_key . ']'; + + // Make sure there is no notice printed out for non-existent config options (we simply set them) + if (!isset($new[$config_key])) + { + $new[$config_key] = ''; + } + + switch ($tpl_type[0]) + { + case 'text': + case 'password': + case 'url': + case 'email': + case 'color': + case 'date': + case 'time': + case 'datetime': + case 'datetime-local': + case 'month': + case 'range': + case 'search': + case 'tel': + case 'week': + $size = (int) $tpl_type[1]; + $maxlength = (int) $tpl_type[2]; + + $tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '" value="' . $new[$config_key] . '"' . (($tpl_type[0] === 'password') ? ' autocomplete="off"' : '') . ' />'; + break; + + case 'number': + $min = $max = $maxlength = ''; + $min = ( isset($tpl_type[1]) ) ? (int) $tpl_type[1] : false; + if ( isset($tpl_type[2]) ) + { + $max = (int) $tpl_type[2]; + $maxlength = strlen( (string) $max ); + } + + $tpl = '<input id="' . $key . '" type="number" maxlength="' . (( $maxlength != '' ) ? $maxlength : 255) . '"' . (( $min != '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="' . $name . '" value="' . $new[$config_key] . '" />'; + break; + + case 'dimension': + $min = $max = $maxlength = $size = ''; + + $min = (int) $tpl_type[1]; + + if ( isset($tpl_type[2]) ) + { + $max = (int) $tpl_type[2]; + $size = $maxlength = strlen( (string) $max ); + } + + $tpl = '<input id="' . $key . '" type="number"' . (( $size != '' ) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength != '') ? $maxlength : 255) . '"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_width]" value="' . $new[$config_key . '_width'] . '" /> x <input type="number"' . (( $size != '' ) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength != '') ? $maxlength : 255) . '"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_height]" value="' . $new[$config_key . '_height'] . '" />'; + break; + + case 'textarea': + $rows = (int) $tpl_type[1]; + $cols = (int) $tpl_type[2]; + + $tpl = '<textarea id="' . $key . '" name="' . $name . '" rows="' . $rows . '" cols="' . $cols . '">' . $new[$config_key] . '</textarea>'; + break; + + case 'radio': + $key_yes = ($new[$config_key]) ? ' checked="checked"' : ''; + $key_no = (!$new[$config_key]) ? ' checked="checked"' : ''; + + $tpl_type_cond = explode('_', $tpl_type[1]); + $type_no = ($tpl_type_cond[0] == 'disabled' || $tpl_type_cond[0] == 'enabled') ? false : true; + + $tpl_no = '<label><input type="radio" name="' . $name . '" value="0"' . $key_no . ' class="radio" /> ' . (($type_no) ? $user->lang['NO'] : $user->lang['DISABLED']) . '</label>'; + $tpl_yes = '<label><input type="radio" id="' . $key . '" name="' . $name . '" value="1"' . $key_yes . ' class="radio" /> ' . (($type_no) ? $user->lang['YES'] : $user->lang['ENABLED']) . '</label>'; + + $tpl = ($tpl_type_cond[0] == 'yes' || $tpl_type_cond[0] == 'enabled') ? $tpl_yes . $tpl_no : $tpl_no . $tpl_yes; + break; + + case 'select': + case 'custom': + + $return = ''; + + if (isset($vars['method'])) + { + $call = array($module->module, $vars['method']); + } + else if (isset($vars['function'])) + { + $call = $vars['function']; + } + else + { + break; + } + + if (isset($vars['params'])) + { + $args = array(); + foreach ($vars['params'] as $value) + { + switch ($value) + { + case '{CONFIG_VALUE}': + $value = $new[$config_key]; + break; + + case '{KEY}': + $value = $key; + break; + } + + $args[] = $value; + } + } + else + { + $args = array($new[$config_key], $key); + } + + $return = call_user_func_array($call, $args); + + if ($tpl_type[0] == 'select') + { + $size = (isset($tpl_type[1])) ? (int) $tpl_type[1] : 1; + $data_toggle = (!empty($tpl_type[2])) ? ' data-togglable-settings="true"' : ''; + + $tpl = '<select id="' . $key . '" name="' . $name . '"' . (($size > 1) ? ' size="' . $size . '"' : '') . $data_toggle . '>' . $return . '</select>'; + } + else + { + $tpl = $return; + } + + break; + + default: + break; + } + + if (isset($vars['append'])) + { + $tpl .= $vars['append']; + } + + /** + * Overwrite the html code we display for the config value + * + * @event core.build_config_template + * @var array tpl_type Config type array: + * 0 => data type + * 1 [optional] => string: size, int: minimum + * 2 [optional] => string: max. length, int: maximum + * @var string key Should be used for the id attribute in html + * @var array new Array with the config values we display + * @var string name Should be used for the name attribute + * @var array vars Array with the options for the config + * @var string tpl The resulting html code we display + * @since 3.1.0-a1 + */ + $vars = array('tpl_type', 'key', 'new', 'name', 'vars', 'tpl'); + extract($phpbb_dispatcher->trigger_event('core.build_config_template', compact($vars))); + + return $tpl; +} + +/** +* Going through a config array and validate values, writing errors to $error. The validation method accepts parameters separated by ':' for string and int. +* The first parameter defines the type to be used, the second the lower bound and the third the upper bound. Only the type is required. +*/ +function validate_config_vars($config_vars, &$cfg_array, &$error) +{ + global $phpbb_root_path, $user, $phpbb_dispatcher; + + $type = 0; + $min = 1; + $max = 2; + + foreach ($config_vars as $config_name => $config_definition) + { + if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false) + { + continue; + } + + if (!isset($config_definition['validate'])) + { + continue; + } + + $validator = explode(':', $config_definition['validate']); + + // Validate a bit. ;) (0 = type, 1 = min, 2= max) + switch ($validator[$type]) + { + case 'string': + $length = utf8_strlen($cfg_array[$config_name]); + + // the column is a VARCHAR + $validator[$max] = (isset($validator[$max])) ? min(255, $validator[$max]) : 255; + + if (isset($validator[$min]) && $length < $validator[$min]) + { + $error[] = sprintf($user->lang['SETTING_TOO_SHORT'], $user->lang[$config_definition['lang']], $validator[$min]); + } + else if (isset($validator[$max]) && $length > $validator[2]) + { + $error[] = sprintf($user->lang['SETTING_TOO_LONG'], $user->lang[$config_definition['lang']], $validator[$max]); + } + break; + + case 'bool': + $cfg_array[$config_name] = ($cfg_array[$config_name]) ? 1 : 0; + break; + + case 'int': + $cfg_array[$config_name] = (int) $cfg_array[$config_name]; + + if (isset($validator[$min]) && $cfg_array[$config_name] < $validator[$min]) + { + $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$config_definition['lang']], $validator[$min]); + } + else if (isset($validator[$max]) && $cfg_array[$config_name] > $validator[$max]) + { + $error[] = sprintf($user->lang['SETTING_TOO_BIG'], $user->lang[$config_definition['lang']], $validator[$max]); + } + + if (strpos($config_name, '_max') !== false) + { + // Min/max pairs of settings should ensure that min <= max + // Replace _max with _min to find the name of the minimum + // corresponding configuration variable + $min_name = str_replace('_max', '_min', $config_name); + + if (isset($cfg_array[$min_name]) && is_numeric($cfg_array[$min_name]) && $cfg_array[$config_name] < $cfg_array[$min_name]) + { + // A minimum value exists and the maximum value is less than it + $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$config_definition['lang']], (int) $cfg_array[$min_name]); + } + } + break; + + case 'email': + if (!preg_match('/^' . get_preg_expression('email') . '$/i', $cfg_array[$config_name])) + { + $error[] = $user->lang['EMAIL_INVALID_EMAIL']; + } + break; + + // Absolute path + case 'script_path': + if (!$cfg_array[$config_name]) + { + break; + } + + $destination = str_replace('\\', '/', $cfg_array[$config_name]); + + if ($destination !== '/') + { + // Adjust destination path (no trailing slash) + if (substr($destination, -1, 1) == '/') + { + $destination = substr($destination, 0, -1); + } + + $destination = str_replace(array('../', './'), '', $destination); + + if ($destination[0] != '/') + { + $destination = '/' . $destination; + } + } + + $cfg_array[$config_name] = trim($destination); + + break; + + // Absolute path + case 'lang': + if (!$cfg_array[$config_name]) + { + break; + } + + $cfg_array[$config_name] = basename($cfg_array[$config_name]); + + if (!file_exists($phpbb_root_path . 'language/' . $cfg_array[$config_name] . '/')) + { + $error[] = $user->lang['WRONG_DATA_LANG']; + } + break; + + // Relative path (appended $phpbb_root_path) + case 'rpath': + case 'rwpath': + if (!$cfg_array[$config_name]) + { + break; + } + + $destination = $cfg_array[$config_name]; + + // Adjust destination path (no trailing slash) + if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\') + { + $destination = substr($destination, 0, -1); + } + + $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination); + if ($destination && ($destination[0] == '/' || $destination[0] == "\\")) + { + $destination = ''; + } + + $cfg_array[$config_name] = trim($destination); + + // Absolute file path + case 'absolute_path': + case 'absolute_path_writable': + // Path being relative (still prefixed by phpbb_root_path), but with the ability to escape the root dir... + case 'path': + case 'wpath': + + if (!$cfg_array[$config_name]) + { + break; + } + + $cfg_array[$config_name] = trim($cfg_array[$config_name]); + + // Make sure no NUL byte is present... + if (strpos($cfg_array[$config_name], "\0") !== false || strpos($cfg_array[$config_name], '%00') !== false) + { + $cfg_array[$config_name] = ''; + break; + } + + $path = in_array($config_definition['validate'], array('wpath', 'path', 'rpath', 'rwpath')) ? $phpbb_root_path . $cfg_array[$config_name] : $cfg_array[$config_name]; + + if (!file_exists($path)) + { + $error[] = sprintf($user->lang['DIRECTORY_DOES_NOT_EXIST'], $cfg_array[$config_name]); + } + + if (file_exists($path) && !is_dir($path)) + { + $error[] = sprintf($user->lang['DIRECTORY_NOT_DIR'], $cfg_array[$config_name]); + } + + // Check if the path is writable + if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath' || $config_definition['validate'] === 'absolute_path_writable') + { + if (file_exists($path) && !phpbb_is_writable($path)) + { + $error[] = sprintf($user->lang['DIRECTORY_NOT_WRITABLE'], $cfg_array[$config_name]); + } + } + + break; + + default: + /** + * Validate a config value + * + * @event core.validate_config_variable + * @var array cfg_array Array with config values + * @var string config_name Name of the config we validate + * @var array config_definition Array with the options for + * this config + * @var array error Array of errors, the errors should + * be strings only, language keys are + * not replaced afterwards + * @since 3.1.0-a1 + */ + $vars = array('cfg_array', 'config_name', 'config_definition', 'error'); + extract($phpbb_dispatcher->trigger_event('core.validate_config_variable', compact($vars))); + break; + } + } + + return; +} + +/** +* Checks whatever or not a variable is OK for use in the Database +* param mixed $value_ary An array of the form array(array('lang' => ..., 'value' => ..., 'column_type' =>))' +* param mixed $error The error array +*/ +function validate_range($value_ary, &$error) +{ + global $user; + + $column_types = array( + 'BOOL' => array('php_type' => 'int', 'min' => 0, 'max' => 1), + 'USINT' => array('php_type' => 'int', 'min' => 0, 'max' => 65535), + 'UINT' => array('php_type' => 'int', 'min' => 0, 'max' => (int) 0x7fffffff), + // Do not use (int) 0x80000000 - it evaluates to different + // values on 32-bit and 64-bit systems. + // Apparently -2147483648 is a float on 32-bit systems, + // despite fitting in an int, thus explicit cast is needed. + 'INT' => array('php_type' => 'int', 'min' => (int) -2147483648, 'max' => (int) 0x7fffffff), + 'TINT' => array('php_type' => 'int', 'min' => -128, 'max' => 127), + + 'VCHAR' => array('php_type' => 'string', 'min' => 0, 'max' => 255), + ); + foreach ($value_ary as $value) + { + $column = explode(':', $value['column_type']); + $max = $min = 0; + $type = 0; + if (!isset($column_types[$column[0]])) + { + continue; + } + else + { + $type = $column_types[$column[0]]; + } + + switch ($type['php_type']) + { + case 'string' : + $max = (isset($column[1])) ? min($column[1],$type['max']) : $type['max']; + if (utf8_strlen($value['value']) > $max) + { + $error[] = sprintf($user->lang['SETTING_TOO_LONG'], $user->lang[$value['lang']], $max); + } + break; + + case 'int': + $min = (isset($column[1])) ? max($column[1],$type['min']) : $type['min']; + $max = (isset($column[2])) ? min($column[2],$type['max']) : $type['max']; + if ($value['value'] < $min) + { + $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$value['lang']], $min); + } + else if ($value['value'] > $max) + { + $error[] = sprintf($user->lang['SETTING_TOO_BIG'], $user->lang[$value['lang']], $max); + } + break; + } + } +} + +/** +* Inserts new config display_vars into an exisiting display_vars array +* at the given position. +* +* @param array $display_vars An array of existing config display vars +* @param array $add_config_vars An array of new config display vars +* @param array $where Where to place the new config vars, +* before or after an exisiting config, as an array +* of the form: array('after' => 'config_name') or +* array('before' => 'config_name'). +* @return array The array of config display vars +*/ +function phpbb_insert_config_array($display_vars, $add_config_vars, $where) +{ + if (is_array($where) && array_key_exists(current($where), $display_vars)) + { + $position = array_search(current($where), array_keys($display_vars)) + ((key($where) == 'before') ? 0 : 1); + $display_vars = array_merge( + array_slice($display_vars, 0, $position), + $add_config_vars, + array_slice($display_vars, $position) + ); + } + + return $display_vars; +} diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 3e69a997a2..79f9db2f3f 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -1,10 +1,13 @@ <?php /** * -* @package acp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -24,8 +27,6 @@ if (!defined('IN_PHPBB')) * @param string $table constant or fullname of the table * @param int $parent_id parent_id of the current set (default = 0) * @param array $where contains strings to compare closer on the where statement (additional) -* -* @author EXreaction */ function recalc_nested_sets(&$new_id, $pkey, $table, $parent_id = 0, $where = array()) { @@ -312,8 +313,6 @@ function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $incl * @param bool $add_log True if log entry should be added * * @return bool False on error -* -* @author bantu */ function copy_forum_permissions($src_forum_id, $dest_forum_ids, $clear_dest_perms = true, $add_log = true) { @@ -619,7 +618,7 @@ function move_posts($post_ids, $topic_id, $auto_sync = true) */ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true) { - global $db, $config; + global $db, $config, $phpbb_container, $phpbb_dispatcher; $approved_topics = 0; $forum_ids = $topic_ids = array(); @@ -645,7 +644,7 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s 'posts' => ($call_delete_posts) ? delete_posts($where_type, $where_ids, false, true, $post_count_sync, false) : 0, ); - $sql = 'SELECT topic_id, forum_id, topic_approved, topic_moved_id + $sql = 'SELECT topic_id, forum_id, topic_visibility, topic_moved_id FROM ' . TOPICS_TABLE . ' WHERE ' . $where_clause; $result = $db->sql_query($sql); @@ -655,7 +654,7 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s $forum_ids[] = $row['forum_id']; $topic_ids[] = $row['topic_id']; - if ($row['topic_approved'] && !$row['topic_moved_id']) + if ($row['topic_visibility'] == ITEM_APPROVED && !$row['topic_moved_id']) { $approved_topics++; } @@ -673,6 +672,20 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s $table_ary = array(BOOKMARKS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, POLL_VOTES_TABLE, POLL_OPTIONS_TABLE, TOPICS_WATCH_TABLE, TOPICS_TABLE); + /** + * Perform additional actions before topic(s) deletion + * + * @event core.delete_topics_before_query + * @var array table_ary Array of tables from which all rows will be deleted that hold a topic_id occuring in topic_ids + * @var array topic_ids Array of topic ids to delete + * @since 3.1.4-RC1 + */ + $vars = array( + 'table_ary', + 'topic_ids', + ); + extract($phpbb_dispatcher->trigger_event('core.delete_topics_before_query', compact($vars))); + foreach ($table_ary as $table) { $sql = "DELETE FROM $table @@ -681,6 +694,18 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s } unset($table_ary); + /** + * Perform additional actions after topic(s) deletion + * + * @event core.delete_topics_after_query + * @var array topic_ids Array of topic ids that were deleted + * @since 3.1.4-RC1 + */ + $vars = array( + 'topic_ids', + ); + extract($phpbb_dispatcher->trigger_event('core.delete_topics_after_query', compact($vars))); + $moved_topic_ids = array(); // update the other forums @@ -716,6 +741,14 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s set_config_count('num_topics', $approved_topics * (-1), true); } + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + $phpbb_notifications->delete_notifications(array( + 'notification.type.topic', + 'notification.type.approve_topic', + 'notification.type.topic_in_queue', + ), $topic_ids); + return $return; } @@ -724,7 +757,38 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s */ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true, $post_count_sync = true, $call_delete_topics = true) { - global $db, $config, $phpbb_root_path, $phpEx; + global $db, $config, $phpbb_root_path, $phpEx, $auth, $user, $phpbb_container, $phpbb_dispatcher; + + // Notifications types to delete + $delete_notifications_types = array( + 'notification.type.quote', + 'notification.type.approve_post', + 'notification.type.post_in_queue', + ); + + /** + * Perform additional actions before post(s) deletion + * + * @event core.delete_posts_before + * @var string where_type Variable containing posts deletion mode + * @var mixed where_ids Array or comma separated list of posts ids to delete + * @var bool auto_sync Flag indicating if topics/forums should be synchronized + * @var bool posted_sync Flag indicating if topics_posted table should be resynchronized + * @var bool post_count_sync Flag indicating if posts count should be resynchronized + * @var bool call_delete_topics Flag indicating if topics having no posts should be deleted + * @var array delete_notifications_types Array with notifications types to delete + * @since 3.1.0-a4 + */ + $vars = array( + 'where_type', + 'where_ids', + 'auto_sync', + 'posted_sync', + 'post_count_sync', + 'call_delete_topics', + 'delete_notifications_types', + ); + extract($phpbb_dispatcher->trigger_event('core.delete_posts_before', compact($vars))); if ($where_type === 'range') { @@ -768,7 +832,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = $approved_posts = 0; $post_ids = $topic_ids = $forum_ids = $post_counts = $remove_topics = array(); - $sql = 'SELECT post_id, poster_id, post_approved, post_postcount, topic_id, forum_id + $sql = 'SELECT post_id, poster_id, post_visibility, post_postcount, topic_id, forum_id FROM ' . POSTS_TABLE . ' WHERE ' . $where_clause; $result = $db->sql_query($sql); @@ -780,12 +844,12 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = $topic_ids[] = (int) $row['topic_id']; $forum_ids[] = (int) $row['forum_id']; - if ($row['post_postcount'] && $post_count_sync && $row['post_approved']) + if ($row['post_postcount'] && $post_count_sync && $row['post_visibility'] == ITEM_APPROVED) { $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1; } - if ($row['post_approved']) + if ($row['post_visibility'] == ITEM_APPROVED) { $approved_posts++; } @@ -848,17 +912,15 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = } // Remove the message from the search index - $search_type = basename($config['search_type']); + $search_type = $config['search_type']; - if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx)) + if (!class_exists($search_type)) { trigger_error('NO_SUCH_SEARCH_MODULE'); } - include_once("{$phpbb_root_path}includes/search/$search_type.$phpEx"); - $error = false; - $search = new $search_type($error); + $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user); if ($error) { @@ -869,8 +931,56 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = delete_attachments('post', $post_ids, false); + /** + * Perform additional actions during post(s) deletion + * + * @event core.delete_posts_in_transaction + * @var array post_ids Array with deleted posts' ids + * @var array poster_ids Array with deleted posts' author ids + * @var array topic_ids Array with deleted posts' topic ids + * @var array forum_ids Array with deleted posts' forum ids + * @var string where_type Variable containing posts deletion mode + * @var mixed where_ids Array or comma separated list of posts ids to delete + * @var array delete_notifications_types Array with notifications types to delete + * @since 3.1.0-a4 + */ + $vars = array( + 'post_ids', + 'poster_ids', + 'topic_ids', + 'forum_ids', + 'where_type', + 'where_ids', + 'delete_notifications_types', + ); + extract($phpbb_dispatcher->trigger_event('core.delete_posts_in_transaction', compact($vars))); + $db->sql_transaction('commit'); + /** + * Perform additional actions after post(s) deletion + * + * @event core.delete_posts_after + * @var array post_ids Array with deleted posts' ids + * @var array poster_ids Array with deleted posts' author ids + * @var array topic_ids Array with deleted posts' topic ids + * @var array forum_ids Array with deleted posts' forum ids + * @var string where_type Variable containing posts deletion mode + * @var mixed where_ids Array or comma separated list of posts ids to delete + * @var array delete_notifications_types Array with notifications types to delete + * @since 3.1.0-a4 + */ + $vars = array( + 'post_ids', + 'poster_ids', + 'topic_ids', + 'forum_ids', + 'where_type', + 'where_ids', + 'delete_notifications_types', + ); + extract($phpbb_dispatcher->trigger_event('core.delete_posts_after', compact($vars))); + // Resync topics_posted table if ($posted_sync) { @@ -884,7 +994,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = sync('forum', 'forum_id', $forum_ids, true, true); } - if ($approved_posts) + if ($approved_posts && $post_count_sync) { set_config_count('num_posts', $approved_posts * (-1), true); } @@ -895,6 +1005,10 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = delete_topics('topic_id', $remove_topics, $auto_sync, $post_count_sync, false); } + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + $phpbb_notifications->delete_notifications($delete_notifications_types, $post_ids); + return sizeof($post_ids); } @@ -1132,8 +1246,6 @@ function delete_attachments($mode, $ids, $resync = true) * @param bool $auto_sync Will call sync() if this is true * * @return array Array with affected forums -* -* @author bantu */ function delete_topic_shadows($forum_id, $sql_more = '', $auto_sync = true) { @@ -1277,7 +1389,7 @@ function phpbb_unlink($filename, $mode = 'file', $entry_removed = false) * - forum Resync complete forum * - topic Resync topics * - topic_moved Removes topic shadows that would be in the same forum as the topic they link to -* - topic_approved Resyncs the topic_approved flag according to the status of the first post +* - topic_visibility Resyncs the topic_visibility flag according to the status of the first post * - post_reported Resyncs the post_reported flag, relying on actual reports * - topic_reported Resyncs the topic_reported flag, relying on post_reported flags * - post_attachement Same as post_reported, but with attachment flags @@ -1297,7 +1409,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $where_ids = ($where_ids) ? array((int) $where_ids) : array(); } - if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_approved' || $mode == 'topic_reported' || $mode == 'post_reported') + if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_visibility' || $mode == 'topic_reported' || $mode == 'post_reported') { if (!$where_type) { @@ -1343,7 +1455,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, { case 'topic_moved': $db->sql_transaction('begin'); - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'mysql4': case 'mysqli': @@ -1383,43 +1495,55 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $db->sql_transaction('commit'); break; - case 'topic_approved': + case 'topic_visibility': $db->sql_transaction('begin'); - switch ($db->sql_layer) + + $sql = 'SELECT t.topic_id, p.post_visibility + FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p + $where_sql_and p.topic_id = t.topic_id + AND p.post_visibility = " . ITEM_APPROVED; + $result = $db->sql_query($sql); + + $topics_approved = array(); + while ($row = $db->sql_fetchrow($result)) { - case 'mysql4': - case 'mysqli': - $sql = 'UPDATE ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - SET t.topic_approved = p.post_approved - $where_sql_and t.topic_first_post_id = p.post_id"; - $db->sql_query($sql); - break; + $topics_approved[] = (int) $row['topic_id']; + } + $db->sql_freeresult($result); - default: - $sql = 'SELECT t.topic_id, p.post_approved - FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - $where_sql_and p.post_id = t.topic_first_post_id - AND p.post_approved <> t.topic_approved"; - $result = $db->sql_query($sql); + $sql = 'SELECT t.topic_id, p.post_visibility + FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p + $where_sql_and " . $db->sql_in_set('t.topic_id', $topics_approved, true, true) . ' + AND p.topic_id = t.topic_id + AND p.post_visibility = ' . ITEM_DELETED; + $result = $db->sql_query($sql); - $topic_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_ids[] = $row['topic_id']; - } - $db->sql_freeresult($result); + $topics_softdeleted = array(); + while ($row = $db->sql_fetchrow($result)) + { + $topics_softdeleted[] = (int) $row['topic_id']; + } + $db->sql_freeresult($result); - if (!sizeof($topic_ids)) - { - return; - } + $topics_softdeleted = array_diff($topics_softdeleted, $topics_approved); + $topics_not_unapproved = array_merge($topics_softdeleted, $topics_approved); + + $update_ary = array( + ITEM_UNAPPROVED => (!empty($topics_not_unapproved)) ? $where_sql_and . ' ' . $db->sql_in_set('topic_id', $topics_not_unapproved, true) : '', + ITEM_APPROVED => (!empty($topics_approved)) ? ' WHERE ' . $db->sql_in_set('topic_id', $topics_approved) : '', + ITEM_DELETED => (!empty($topics_softdeleted)) ? ' WHERE ' . $db->sql_in_set('topic_id', $topics_softdeleted) : '', + ); + foreach ($update_ary as $visibility => $sql_where) + { + if ($sql_where) + { $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_approved = 1 - topic_approved - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); + SET topic_visibility = ' . $visibility . ' + ' . $sql_where; $db->sql_query($sql); - break; + } } $db->sql_transaction('commit'); @@ -1660,9 +1784,12 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $forum_data[$forum_id] = $row; if ($sync_extra) { - $forum_data[$forum_id]['posts'] = 0; - $forum_data[$forum_id]['topics'] = 0; - $forum_data[$forum_id]['topics_real'] = 0; + $forum_data[$forum_id]['posts_approved'] = 0; + $forum_data[$forum_id]['posts_unapproved'] = 0; + $forum_data[$forum_id]['posts_softdeleted'] = 0; + $forum_data[$forum_id]['topics_approved'] = 0; + $forum_data[$forum_id]['topics_unapproved'] = 0; + $forum_data[$forum_id]['topics_softdeleted'] = 0; } $forum_data[$forum_id]['last_post_id'] = 0; $forum_data[$forum_id]['last_post_subject'] = ''; @@ -1683,20 +1810,27 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, // 2: Get topic counts for each forum (optional) if ($sync_extra) { - $sql = 'SELECT forum_id, topic_approved, COUNT(topic_id) AS forum_topics + $sql = 'SELECT forum_id, topic_visibility, COUNT(topic_id) AS total_topics FROM ' . TOPICS_TABLE . ' WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . ' - GROUP BY forum_id, topic_approved'; + GROUP BY forum_id, topic_visibility'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { $forum_id = (int) $row['forum_id']; - $forum_data[$forum_id]['topics_real'] += $row['forum_topics']; - if ($row['topic_approved']) + if ($row['topic_visibility'] == ITEM_APPROVED) { - $forum_data[$forum_id]['topics'] = $row['forum_topics']; + $forum_data[$forum_id]['topics_approved'] = $row['total_topics']; + } + else if ($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) + { + $forum_data[$forum_id]['topics_unapproved'] = $row['total_topics']; + } + else if ($row['topic_visibility'] == ITEM_DELETED) + { + $forum_data[$forum_id]['topics_softdeleted'] = $row['total_topics']; } } $db->sql_freeresult($result); @@ -1707,18 +1841,16 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, { if (sizeof($forum_ids) == 1) { - $sql = 'SELECT SUM(t.topic_replies + 1) AS forum_posts + $sql = 'SELECT SUM(t.topic_posts_approved) AS forum_posts_approved, SUM(t.topic_posts_unapproved) AS forum_posts_unapproved, SUM(t.topic_posts_softdeleted) AS forum_posts_softdeleted FROM ' . TOPICS_TABLE . ' t WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_approved = 1 AND t.topic_status <> ' . ITEM_MOVED; } else { - $sql = 'SELECT t.forum_id, SUM(t.topic_replies + 1) AS forum_posts + $sql = 'SELECT t.forum_id, SUM(t.topic_posts_approved) AS forum_posts_approved, SUM(t.topic_posts_unapproved) AS forum_posts_unapproved, SUM(t.topic_posts_softdeleted) AS forum_posts_softdeleted FROM ' . TOPICS_TABLE . ' t WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_approved = 1 AND t.topic_status <> ' . ITEM_MOVED . ' GROUP BY t.forum_id'; } @@ -1729,7 +1861,9 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, { $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id']; - $forum_data[$forum_id]['posts'] = (int) $row['forum_posts']; + $forum_data[$forum_id]['posts_approved'] = (int) $row['forum_posts_approved']; + $forum_data[$forum_id]['posts_unapproved'] = (int) $row['forum_posts_unapproved']; + $forum_data[$forum_id]['posts_softdeleted'] = (int) $row['forum_posts_softdeleted']; } $db->sql_freeresult($result); } @@ -1740,14 +1874,14 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $sql = 'SELECT MAX(t.topic_last_post_id) as last_post_id FROM ' . TOPICS_TABLE . ' t WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_approved = 1'; + AND t.topic_visibility = ' . ITEM_APPROVED; } else { $sql = 'SELECT t.forum_id, MAX(t.topic_last_post_id) as last_post_id FROM ' . TOPICS_TABLE . ' t WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' - AND t.topic_approved = 1 + AND t.topic_visibility = ' . ITEM_APPROVED . ' GROUP BY t.forum_id'; } @@ -1810,7 +1944,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, if ($sync_extra) { - array_push($fieldnames, 'posts', 'topics', 'topics_real'); + array_push($fieldnames, 'posts_approved', 'posts_unapproved', 'posts_softdeleted', 'topics_approved', 'topics_unapproved', 'topics_softdeleted'); } foreach ($forum_data as $forum_id => $row) @@ -1845,11 +1979,11 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, break; case 'topic': - $topic_data = $post_ids = $approved_unapproved_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array(); + $topic_data = $post_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array(); $db->sql_transaction('begin'); - $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_approved, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_replies, t.topic_replies_real, t.topic_first_post_id, t.topic_first_poster_name, t.topic_first_poster_colour, t.topic_last_post_id, t.topic_last_post_subject, t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_poster_colour, t.topic_last_post_time + $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_visibility, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_first_post_id, t.topic_first_poster_name, t.topic_first_poster_colour, t.topic_last_post_id, t.topic_last_post_subject, t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_poster_colour, t.topic_last_post_time FROM ' . TOPICS_TABLE . " t $where_sql"; $result = $db->sql_query($sql); @@ -1864,8 +1998,10 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $topic_id = (int) $row['topic_id']; $topic_data[$topic_id] = $row; - $topic_data[$topic_id]['replies_real'] = -1; - $topic_data[$topic_id]['replies'] = 0; + $topic_data[$topic_id]['visibility'] = ITEM_UNAPPROVED; + $topic_data[$topic_id]['posts_approved'] = 0; + $topic_data[$topic_id]['posts_unapproved'] = 0; + $topic_data[$topic_id]['posts_softdeleted'] = 0; $topic_data[$topic_id]['first_post_id'] = 0; $topic_data[$topic_id]['last_post_id'] = 0; unset($topic_data[$topic_id]['topic_id']); @@ -1882,11 +2018,11 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $db->sql_freeresult($result); // Use "t" as table alias because of the $where_sql clause - // NOTE: 't.post_approved' in the GROUP BY is causing a major slowdown. - $sql = 'SELECT t.topic_id, t.post_approved, COUNT(t.post_id) AS total_posts, MIN(t.post_id) AS first_post_id, MAX(t.post_id) AS last_post_id + // NOTE: 't.post_visibility' in the GROUP BY is causing a major slowdown. + $sql = 'SELECT t.topic_id, t.post_visibility, COUNT(t.post_id) AS total_posts, MIN(t.post_id) AS first_post_id, MAX(t.post_id) AS last_post_id FROM ' . POSTS_TABLE . " t $where_sql - GROUP BY t.topic_id, t.post_approved"; + GROUP BY t.topic_id, t.post_visibility"; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -1907,14 +2043,38 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, // When we'll be done, only topics with no posts will remain unset($delete_topics[$topic_id]); - $topic_data[$topic_id]['replies_real'] += $row['total_posts']; - $topic_data[$topic_id]['first_post_id'] = (!$topic_data[$topic_id]['first_post_id']) ? $row['first_post_id'] : min($topic_data[$topic_id]['first_post_id'], $row['first_post_id']); + if ($row['post_visibility'] == ITEM_APPROVED) + { + $topic_data[$topic_id]['posts_approved'] = $row['total_posts']; + } + else if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) + { + $topic_data[$topic_id]['posts_unapproved'] = $row['total_posts']; + } + else if ($row['post_visibility'] == ITEM_DELETED) + { + $topic_data[$topic_id]['posts_softdeleted'] = $row['total_posts']; + } - if ($row['post_approved'] || !$topic_data[$topic_id]['last_post_id']) + if ($row['post_visibility'] == ITEM_APPROVED) { - $topic_data[$topic_id]['replies'] = $row['total_posts'] - 1; + $topic_data[$topic_id]['visibility'] = ITEM_APPROVED; + $topic_data[$topic_id]['first_post_id'] = $row['first_post_id']; $topic_data[$topic_id]['last_post_id'] = $row['last_post_id']; } + else if ($topic_data[$topic_id]['visibility'] != ITEM_APPROVED) + { + // If there is no approved post, we take the min/max of the other visibilities + // for the last and first post info, because it is only visible to moderators anyway + $topic_data[$topic_id]['first_post_id'] = (!empty($topic_data[$topic_id]['first_post_id'])) ? min($topic_data[$topic_id]['first_post_id'], $row['first_post_id']) : $row['first_post_id']; + $topic_data[$topic_id]['last_post_id'] = max($topic_data[$topic_id]['last_post_id'], $row['last_post_id']); + + if ($topic_data[$topic_id]['visibility'] == ITEM_UNAPPROVED || $topic_data[$topic_id]['visibility'] == ITEM_REAPPROVE) + { + // Soft delete status is stronger than unapproved. + $topic_data[$topic_id]['visibility'] = $row['post_visibility']; + } + } } } $db->sql_freeresult($result); @@ -1955,7 +2115,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, unset($delete_topics, $delete_topic_ids); } - $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour + $sql = 'SELECT p.post_id, p.topic_id, p.post_visibility, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' AND u.user_id = p.poster_id'; @@ -1968,10 +2128,6 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, if ($row['post_id'] == $topic_data[$topic_id]['first_post_id']) { - if ($topic_data[$topic_id]['topic_approved'] != $row['post_approved']) - { - $approved_unapproved_ids[] = $topic_id; - } $topic_data[$topic_id]['time'] = $row['post_time']; $topic_data[$topic_id]['poster'] = $row['poster_id']; $topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; @@ -2032,7 +2188,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $sync_shadow_topics = array(); if (sizeof($post_ids)) { - $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour + $sql = 'SELECT p.post_id, p.topic_id, p.post_visibility, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' AND u.user_id = p.poster_id'; @@ -2099,18 +2255,8 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, unset($sync_shadow_topics, $shadow_topic_data); } - // approved becomes unapproved, and vice-versa - if (sizeof($approved_unapproved_ids)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_approved = 1 - topic_approved - WHERE ' . $db->sql_in_set('topic_id', $approved_unapproved_ids); - $db->sql_query($sql); - } - unset($approved_unapproved_ids); - // These are fields that will be synchronised - $fieldnames = array('time', 'replies', 'replies_real', 'poster', 'first_post_id', 'first_poster_name', 'first_poster_colour', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); + $fieldnames = array('time', 'visibility', 'posts_approved', 'posts_unapproved', 'posts_softdeleted', 'poster', 'first_post_id', 'first_poster_name', 'first_poster_colour', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); if ($sync_extra) { @@ -2191,7 +2337,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, */ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync = true) { - global $db; + global $db, $phpbb_dispatcher; if (!is_array($forum_id)) { @@ -2208,6 +2354,7 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync if (!($prune_flags & FORUM_FLAG_PRUNE_ANNOUNCE)) { $sql_and .= ' AND topic_type <> ' . POST_ANNOUNCE; + $sql_and .= ' AND topic_type <> ' . POST_GLOBAL; } if (!($prune_flags & FORUM_FLAG_PRUNE_STICKY)) @@ -2225,6 +2372,26 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync $sql_and .= " AND topic_last_view_time < $prune_date"; } + if ($prune_mode == 'shadow') + { + $sql_and .= ' AND topic_status = ' . ITEM_MOVED . " AND topic_last_post_time < $prune_date"; + } + + /** + * Use this event to modify the SQL that selects topics to be pruned + * + * @event core.prune_sql + * @var string forum_id The forum id + * @var string prune_mode The prune mode + * @var string prune_date The prune date + * @var int prune_flags The prune flags + * @var bool auto_sync Whether or not to perform auto sync + * @var string sql_and SQL text appended to where clause + * @since 3.1.3-RC1 + */ + $vars = array('forum_id', 'prune_mode', 'prune_date', 'prune_flags', 'auto_sync', 'sql_and'); + extract($phpbb_dispatcher->trigger_event('core.prune_sql', compact($vars))); + $sql = 'SELECT topic_id FROM ' . TOPICS_TABLE . ' WHERE ' . $db->sql_in_set('forum_id', $forum_id) . " @@ -2294,36 +2461,25 @@ function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_fr } /** -* remove_comments will strip the sql comment lines out of an uploaded sql file -* specifically for mssql and postgres type files in the install.... +* Cache moderators. Called whenever permissions are changed +* via admin_permissions. Changes of usernames and group names +* must be carried through for the moderators table. * -* @deprecated Use phpbb_remove_comments() instead. -*/ -function remove_comments(&$output) -{ - // Remove /* */ comments (http://ostermiller.org/findcomment.html) - $output = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $output); - - // Return by reference and value. - return $output; -} - -/** -* Cache moderators, called whenever permissions are changed via admin_permissions. Changes of username -* and group names must be carried through for the moderators table +* @param \phpbb\db\driver\driver_interface $db Database connection +* @param \phpbb\cache\driver\driver_interface Cache driver +* @param \phpbb\auth\auth $auth Authentication object +* @return null */ -function cache_moderators() +function phpbb_cache_moderators($db, $cache, $auth) { - global $db, $cache, $auth, $phpbb_root_path, $phpEx; - // Remove cached sql results $cache->destroy('sql', MODERATOR_CACHE_TABLE); // Clear table - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'sqlite': - case 'firebird': + case 'sqlite3': $db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE); break; @@ -2345,7 +2501,7 @@ function cache_moderators() $ug_id_ary = array_keys($hold_ary); // Remove users who have group memberships with DENY moderator permissions - $sql = $db->sql_build_query('SELECT', array( + $sql_ary_deny = array( 'SELECT' => 'a.forum_id, ug.user_id, g.group_id', 'FROM' => array( @@ -2358,8 +2514,8 @@ function cache_moderators() 'LEFT_JOIN' => array( array( 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id' - ) + 'ON' => 'a.auth_role_id = r.role_id', + ), ), 'WHERE' => '(o.auth_option_id = a.auth_option_id OR o.auth_option_id = r.auth_option_id) @@ -2370,8 +2526,9 @@ function cache_moderators() AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . " AND ug.user_pending = 0 - AND o.auth_option " . $db->sql_like_expression('m_' . $db->any_char), - )); + AND o.auth_option " . $db->sql_like_expression('m_' . $db->get_any_char()), + ); + $sql = $db->sql_build_query('SELECT', $sql_ary_deny); $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -2396,6 +2553,7 @@ function cache_moderators() { $usernames_ary[$row['user_id']] = $row['username']; } + $db->sql_freeresult($result); foreach ($hold_ary as $user_id => $forum_id_ary) { @@ -2486,302 +2644,45 @@ function cache_moderators() /** * View log -* If $log_count is set to false, we will skip counting all entries in the database. +* +* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved +* @param array &$log The result array with the logs +* @param mixed &$log_count If $log_count is set to false, we will skip counting all entries in the database. +* Otherwise an integer with the number of total matching entries is returned. +* @param int $limit Limit the number of entries that are returned +* @param int $offset Offset when fetching the log entries, f.e. when paginating +* @param mixed $forum_id Restrict the log entries to the given forum_id (can also be an array of forum_ids) +* @param int $topic_id Restrict the log entries to the given topic_id +* @param int $user_id Restrict the log entries to the given user_id +* @param int $log_time Only get log entries newer than the given timestamp +* @param string $sort_by SQL order option, e.g. 'l.log_time DESC' +* @param string $keywords Will only return log entries that have the keywords in log_operation or log_data +* +* @return int Returns the offset of the last valid page, if the specified offset was invalid (too high) */ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC', $keywords = '') { - global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path; + global $phpbb_log; - $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array(); - - $profile_url = (defined('IN_ADMIN')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview') : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile'); - - switch ($mode) - { - case 'admin': - $log_type = LOG_ADMIN; - $sql_forum = ''; - break; + $count_logs = ($log_count !== false); - case 'mod': - $log_type = LOG_MOD; - $sql_forum = ''; - - if ($topic_id) - { - $sql_forum = 'AND l.topic_id = ' . (int) $topic_id; - } - else if (is_array($forum_id)) - { - $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id)); - } - else if ($forum_id) - { - $sql_forum = 'AND l.forum_id = ' . (int) $forum_id; - } - break; - - case 'user': - $log_type = LOG_USERS; - $sql_forum = 'AND l.reportee_id = ' . (int) $user_id; - break; - - case 'users': - $log_type = LOG_USERS; - $sql_forum = ''; - break; - - case 'critical': - $log_type = LOG_CRITICAL; - $sql_forum = ''; - break; - - default: - return; - } + $log = $phpbb_log->get_logs($mode, $count_logs, $limit, $offset, $forum_id, $topic_id, $user_id, $limit_days, $sort_by, $keywords); + $log_count = $phpbb_log->get_log_count(); - // Use no preg_quote for $keywords because this would lead to sole backslashes being added - // We also use an OR connection here for spaces and the | string. Currently, regex is not supported for searching (but may come later). - $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY); - $sql_keywords = ''; - - if (!empty($keywords)) - { - $keywords_pattern = array(); - - // Build pattern and keywords... - for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++) - { - $keywords_pattern[] = preg_quote($keywords[$i], '#'); - $keywords[$i] = $db->sql_like_expression($db->any_char . $keywords[$i] . $db->any_char); - } - - $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui'; - - $operations = array(); - foreach ($user->lang as $key => $value) - { - if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value)) - { - $operations[] = $key; - } - } - - $sql_keywords = 'AND ('; - if (!empty($operations)) - { - $sql_keywords .= $db->sql_in_set('l.log_operation', $operations) . ' OR '; - } - $sql_lower = $db->sql_lower_text('l.log_data'); - $sql_keywords .= "$sql_lower " . implode(" OR $sql_lower ", $keywords) . ')'; - } - - if ($log_count !== false) - { - $sql = 'SELECT COUNT(l.log_id) AS total_entries - FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u - WHERE l.log_type = $log_type - AND l.user_id = u.user_id - AND l.log_time >= $limit_days - $sql_keywords - $sql_forum"; - $result = $db->sql_query($sql); - $log_count = (int) $db->sql_fetchfield('total_entries'); - $db->sql_freeresult($result); - } - - // $log_count may be false here if false was passed in for it, - // because in this case we did not run the COUNT() query above. - // If we ran the COUNT() query and it returned zero rows, return; - // otherwise query for logs below. - if ($log_count === 0) - { - // Save the queries, because there are no logs to display - return 0; - } - - if ($offset >= $log_count) - { - $offset = ($offset - $limit < 0) ? 0 : $offset - $limit; - } - - $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour - FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u - WHERE l.log_type = $log_type - AND u.user_id = l.user_id - " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . " - $sql_keywords - $sql_forum - ORDER BY $sort_by"; - $result = $db->sql_query_limit($sql, $limit, $offset); - - $i = 0; - $log = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['topic_id']) - { - $topic_id_list[] = $row['topic_id']; - } - - if ($row['reportee_id']) - { - $reportee_id_list[] = $row['reportee_id']; - } - - $log[$i] = array( - 'id' => $row['log_id'], - - 'reportee_id' => $row['reportee_id'], - 'reportee_username' => '', - 'reportee_username_full'=> '', - - 'user_id' => $row['user_id'], - 'username' => $row['username'], - 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url), - - 'ip' => $row['log_ip'], - 'time' => $row['log_time'], - 'forum_id' => $row['forum_id'], - 'topic_id' => $row['topic_id'], - - 'viewforum' => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false, - 'action' => (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}', - ); - - if (!empty($row['log_data'])) - { - $log_data_ary = @unserialize($row['log_data']); - $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary; - - if (isset($user->lang[$row['log_operation']])) - { - // Check if there are more occurrences of % than arguments, if there are we fill out the arguments array - // It doesn't matter if we add more arguments than placeholders - if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0) - { - $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), '')); - } - - $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary); - - // If within the admin panel we do not censor text out - if (defined('IN_ADMIN')) - { - $log[$i]['action'] = bbcode_nl2br($log[$i]['action']); - } - else - { - $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action'])); - } - } - else if (!empty($log_data_ary)) - { - $log[$i]['action'] .= '<br />' . implode('', $log_data_ary); - } - - /* Apply make_clickable... has to be seen if it is for good. :/ - // Seems to be not for the moment, reconsider later... - $log[$i]['action'] = make_clickable($log[$i]['action']); - */ - } - - $i++; - } - $db->sql_freeresult($result); - - if (sizeof($topic_id_list)) - { - $topic_id_list = array_unique($topic_id_list); - - // This query is not really needed if move_topics() updates the forum_id field, - // although it's also used to determine if the topic still exists in the database - $sql = 'SELECT topic_id, forum_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list)); - $result = $db->sql_query($sql); - - $default_forum_id = 0; - - while ($row = $db->sql_fetchrow($result)) - { - if (!$row['forum_id']) - { - if ($auth->acl_getf_global('f_read')) - { - if (!$default_forum_id) - { - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type = ' . FORUM_POST; - $f_result = $db->sql_query_limit($sql, 1); - $default_forum_id = (int) $db->sql_fetchfield('forum_id', false, $f_result); - $db->sql_freeresult($f_result); - } - - $is_auth[$row['topic_id']] = $default_forum_id; - } - } - else - { - if ($auth->acl_get('f_read', $row['forum_id'])) - { - $is_auth[$row['topic_id']] = $row['forum_id']; - } - } - - if ($auth->acl_gets('a_', 'm_', $row['forum_id'])) - { - $is_mod[$row['topic_id']] = $row['forum_id']; - } - } - $db->sql_freeresult($result); - - foreach ($log as $key => $row) - { - $log[$key]['viewtopic'] = (isset($is_auth[$row['topic_id']])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $is_auth[$row['topic_id']] . '&t=' . $row['topic_id']) : false; - $log[$key]['viewlogs'] = (isset($is_mod[$row['topic_id']])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&mode=topic_logs&t=' . $row['topic_id'], true, $user->session_id) : false; - } - } - - if (sizeof($reportee_id_list)) - { - $reportee_id_list = array_unique($reportee_id_list); - $reportee_names_list = array(); - - $sql = 'SELECT user_id, username, user_colour - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $reportee_id_list); - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $reportee_names_list[$row['user_id']] = $row; - } - $db->sql_freeresult($result); - - foreach ($log as $key => $row) - { - if (!isset($reportee_names_list[$row['reportee_id']])) - { - continue; - } - - $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username']; - $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_names_list[$row['reportee_id']]['username'], $reportee_names_list[$row['reportee_id']]['user_colour'], false, $profile_url); - } - } - - return $offset; + return $phpbb_log->get_valid_offset(); } /** -* Update foes - remove moderators and administrators from foe lists... +* Removes moderators and administrators from foe lists. +* +* @param \phpbb\db\driver\driver_interface $db Database connection +* @param \phpbb\auth\auth $auth Authentication object +* @param array|bool $group_id If an array, remove all members of this group from foe lists, or false to ignore +* @param array|bool $user_id If an array, remove this user from foe lists, or false to ignore +* @return null */ -function update_foes($group_id = false, $user_id = false) +function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false) { - global $db, $auth; - // update foes for some user if (is_array($user_id) && sizeof($user_id)) { @@ -2796,18 +2697,18 @@ function update_foes($group_id = false, $user_id = false) if (is_array($group_id) && sizeof($group_id)) { // Grab group settings... - $sql = $db->sql_build_query('SELECT', array( + $sql_ary = array( 'SELECT' => 'a.group_id', 'FROM' => array( ACL_OPTIONS_TABLE => 'ao', - ACL_GROUPS_TABLE => 'a' + ACL_GROUPS_TABLE => 'a', ), 'LEFT_JOIN' => array( array( 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id' + 'ON' => 'a.auth_role_id = r.role_id', ), ), @@ -2815,8 +2716,9 @@ function update_foes($group_id = false, $user_id = false) AND ' . $db->sql_in_set('a.group_id', $group_id) . " AND ao.auth_option IN ('a_', 'm_')", - 'GROUP_BY' => 'a.group_id' - )); + 'GROUP_BY' => 'a.group_id', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); $result = $db->sql_query($sql); $groups = array(); @@ -2831,11 +2733,11 @@ function update_foes($group_id = false, $user_id = false) return; } - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'mysqli': case 'mysql4': - $sql = 'DELETE ' . (($db->sql_layer === 'mysqli' || version_compare($db->sql_server_info(true), '4.1', '>=')) ? 'z.*' : ZEBRA_TABLE) . ' + $sql = 'DELETE ' . (($db->get_sql_layer() === 'mysqli' || version_compare($db->sql_server_info(true), '4.1', '>=')) ? 'z.*' : ZEBRA_TABLE) . ' FROM ' . ZEBRA_TABLE . ' z, ' . USER_GROUP_TABLE . ' ug WHERE z.zebra_id = ug.user_id AND z.foe = 1 @@ -2946,6 +2848,7 @@ function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $li $users[] = $row; } + $db->sql_freeresult($result); return $offset; } @@ -2988,7 +2891,7 @@ function get_database_size() $database_size = false; // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0 - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'mysql': case 'mysql4': @@ -3004,7 +2907,7 @@ function get_database_size() if (preg_match('#(3\.23|[45]\.)#', $version)) { - $db_name = (preg_match('#^(?:3\.23\.(?:[6-9]|[1-9]{2}))|[45]\.#', $version)) ? "`{$db->dbname}`" : $db->dbname; + $db_name = (preg_match('#^(?:3\.23\.(?:[6-9]|[1-9]{2}))|[45]\.#', $version)) ? "`{$db->get_db_name()}`" : $db->get_db_name(); $sql = 'SHOW TABLE STATUS FROM ' . $db_name; @@ -3033,18 +2936,8 @@ function get_database_size() } break; - case 'firebird': - global $dbname; - - // if it on the local machine, we can get lucky - if (file_exists($dbname)) - { - $database_size = filesize($dbname); - } - - break; - case 'sqlite': + case 'sqlite3': global $dbhost; if (file_exists($dbhost)) @@ -3061,7 +2954,7 @@ function get_database_size() $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - + $sql = 'SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize FROM sysfiles'; @@ -3070,7 +2963,7 @@ function get_database_size() // Azure stats are stored elsewhere if (strpos($row['mssql_version'], 'SQL Azure') !== false) { - $sql = 'SELECT ((SUM(reserved_page_count) * 8.0) * 1024.0) as dbsize + $sql = 'SELECT ((SUM(reserved_page_count) * 8.0) * 1024.0) as dbsize FROM sys.dm_db_partition_stats'; } } @@ -3090,7 +2983,7 @@ function get_database_size() if ($row['proname'] == 'pg_database_size') { - $database = $db->dbname; + $database = $db->get_db_name(); if (strpos($database, '.') !== false) { list($database, ) = explode('.', $database); @@ -3130,71 +3023,24 @@ function get_database_size() /** * Retrieve contents from remotely stored file +* +* @deprecated 3.1.2 Use file_downloader instead */ function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 6) { - global $user; - - if ($fsock = @fsockopen($host, $port, $errno, $errstr, $timeout)) - { - @fputs($fsock, "GET $directory/$filename HTTP/1.0\r\n"); - @fputs($fsock, "HOST: $host\r\n"); - @fputs($fsock, "Connection: close\r\n\r\n"); - - $timer_stop = time() + $timeout; - stream_set_timeout($fsock, $timeout); - - $file_info = ''; - $get_info = false; + global $phpbb_container; - while (!@feof($fsock)) - { - if ($get_info) - { - $file_info .= @fread($fsock, 1024); - } - else - { - $line = @fgets($fsock, 1024); - if ($line == "\r\n") - { - $get_info = true; - } - else if (stripos($line, '404 not found') !== false) - { - $errstr = $user->lang['FILE_NOT_FOUND'] . ': ' . $filename; - return false; - } - } + // Get file downloader and assign $errstr and $errno + $file_downloader = $phpbb_container->get('file_downloader'); - $stream_meta_data = stream_get_meta_data($fsock); - - if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop) - { - $errstr = $user->lang['FSOCK_TIMEOUT']; - return false; - } - } - @fclose($fsock); - } - else - { - if ($errstr) - { - $errstr = utf8_convert_message($errstr); - return false; - } - else - { - $errstr = $user->lang['FSOCK_DISABLED']; - return false; - } - } + $file_data = $file_downloader->get($host, $directory, $filename, $port, $timeout); + $errstr = $file_downloader->get_error_string(); + $errno = $file_downloader->get_error_number(); - return $file_info; + return $file_data; } -/** +/* * Tidy Warnings * Remove all warnings which have now expired from the database * The duration of a warning can be defined by the administrator @@ -3278,77 +3124,29 @@ function tidy_database() */ function add_permission_language() { - global $user, $phpEx; + global $user, $phpEx, $phpbb_extension_manager; - // First of all, our own file. We need to include it as the first file because it presets all relevant variables. - $user->add_lang('acp/permissions_phpbb'); + // add permission language files from extensions + $finder = $phpbb_extension_manager->get_finder(); - $files_to_add = array(); + $lang_files = $finder + ->prefix('permissions_') + ->suffix(".$phpEx") + ->core_path('language/' . $user->lang_name . '/') + ->extension_directory('/language/' . $user->lang_name) + ->find(); - // Now search in acp and mods folder for permissions_ files. - foreach (array('acp/', 'mods/') as $path) + foreach ($lang_files as $lang_file => $ext_name) { - $dh = @opendir($user->lang_path . $user->lang_name . '/' . $path); - - if ($dh) + if ($ext_name === '/') { - while (($file = readdir($dh)) !== false) - { - if ($file !== 'permissions_phpbb.' . $phpEx && strpos($file, 'permissions_') === 0 && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx) - { - $files_to_add[] = $path . substr($file, 0, -(strlen($phpEx) + 1)); - } - } - closedir($dh); + $user->add_lang($lang_file); } - } - - if (!sizeof($files_to_add)) - { - return false; - } - - $user->add_lang($files_to_add); - return true; -} - -/** - * Obtains the latest version information - * - * @param bool $force_update Ignores cached data. Defaults to false. - * @param bool $warn_fail Trigger a warning if obtaining the latest version information fails. Defaults to false. - * @param int $ttl Cache version information for $ttl seconds. Defaults to 86400 (24 hours). - * - * @return string | false Version info on success, false on failure. - */ -function obtain_latest_version_info($force_update = false, $warn_fail = false, $ttl = 86400) -{ - global $cache; - - $info = $cache->get('versioncheck'); - - if ($info === false || $force_update) - { - $errstr = ''; - $errno = 0; - - $info = get_remote_file('version.phpbb.com', '/phpbb', - ((defined('PHPBB_QA')) ? '30x_qa.txt' : '30x.txt'), $errstr, $errno); - - if (empty($info)) + else { - $cache->destroy('versioncheck'); - if ($warn_fail) - { - trigger_error($errstr, E_USER_WARNING); - } - return false; + $user->add_lang_ext($ext_name, $lang_file); } - - $cache->put('versioncheck', $info, $ttl); } - - return $info; } /** @@ -3370,5 +3168,3 @@ function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more ' . $sql_more; $db->sql_query($sql); } - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_compatibility.php b/phpBB/includes/functions_compatibility.php new file mode 100644 index 0000000000..43952ae57a --- /dev/null +++ b/phpBB/includes/functions_compatibility.php @@ -0,0 +1,197 @@ +<?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. +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Get user avatar +* +* @deprecated 3.1.0-a1 (To be removed: 3.3.0) +* +* @param string $avatar Users assigned avatar name +* @param int $avatar_type Type of avatar +* @param string $avatar_width Width of users avatar +* @param string $avatar_height Height of users avatar +* @param string $alt Optional language string for alt tag within image, can be a language key or text +* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP +* +* @return string Avatar image +*/ +function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false) +{ + // map arguments to new function phpbb_get_avatar() + $row = array( + 'avatar' => $avatar, + 'avatar_type' => $avatar_type, + 'avatar_width' => $avatar_width, + 'avatar_height' => $avatar_height, + ); + + return phpbb_get_avatar($row, $alt, $ignore_config); +} + +/** +* Hash the password +* +* @deprecated 3.1.0-a2 (To be removed: 3.3.0) +* +* @param string $password Password to be hashed +* +* @return string|bool Password hash or false if something went wrong during hashing +*/ +function phpbb_hash($password) +{ + global $phpbb_container; + + $passwords_manager = $phpbb_container->get('passwords.manager'); + return $passwords_manager->hash($password); +} + +/** +* Check for correct password +* +* @deprecated 3.1.0-a2 (To be removed: 3.3.0) +* +* @param string $password The password in plain text +* @param string $hash The stored password hash +* +* @return bool Returns true if the password is correct, false if not. +*/ +function phpbb_check_hash($password, $hash) +{ + global $phpbb_container; + + $passwords_manager = $phpbb_container->get('passwords.manager'); + return $passwords_manager->check($password, $hash); +} + +/** +* Eliminates useless . and .. components from specified path. +* +* Deprecated, use filesystem class instead +* +* @param string $path Path to clean +* @return string Cleaned path +* +* @deprecated +*/ +function phpbb_clean_path($path) +{ + global $phpbb_path_helper, $phpbb_container; + + if (!$phpbb_path_helper && $phpbb_container) + { + $phpbb_path_helper = $phpbb_container->get('path_helper'); + } + else if (!$phpbb_path_helper) + { + global $phpbb_root_path, $phpEx; + + // The container is not yet loaded, use a new instance + if (!class_exists('\phpbb\path_helper')) + { + require($phpbb_root_path . 'phpbb/path_helper.' . $phpEx); + } + + $request = new phpbb\request\request(); + $phpbb_path_helper = new phpbb\path_helper( + new phpbb\symfony_request( + $request + ), + new phpbb\filesystem(), + $request, + $phpbb_root_path, + $phpEx + ); + } + + return $phpbb_path_helper->clean_path($path); +} + +/** +* Pick a timezone +* +* @param string $default A timezone to select +* @param boolean $truncate Shall we truncate the options text +* +* @return string Returns the options for timezone selector only +* +* @deprecated +*/ +function tz_select($default = '', $truncate = false) +{ + global $template, $user; + + return phpbb_timezone_select($template, $user, $default, $truncate); +} + +/** +* Cache moderators. Called whenever permissions are changed +* via admin_permissions. Changes of usernames and group names +* must be carried through for the moderators table. +* +* @deprecated 3.1 +* @return null +*/ +function cache_moderators() +{ + global $db, $cache, $auth; + return phpbb_cache_moderators($db, $cache, $auth); +} + +/** +* Removes moderators and administrators from foe lists. +* +* @deprecated 3.1 +* @param array|bool $group_id If an array, remove all members of this group from foe lists, or false to ignore +* @param array|bool $user_id If an array, remove this user from foe lists, or false to ignore +* @return null +*/ +function update_foes($group_id = false, $user_id = false) +{ + global $db, $auth; + return phpbb_update_foes($db, $auth, $group_id, $user_id); +} + +/** +* Get user rank title and image +* +* @param int $user_rank the current stored users rank id +* @param int $user_posts the users number of posts +* @param string &$rank_title the rank title will be stored here after execution +* @param string &$rank_img the rank image as full img tag is stored here after execution +* @param string &$rank_img_src the rank image source is stored here after execution +* +* @deprecated 3.1.0-RC5 (To be removed: 3.3.0) +* +* Note: since we do not want to break backwards-compatibility, this function will only properly assign ranks to guests if you call it for them with user_posts == false +*/ +function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank_img_src) +{ + global $phpbb_root_path, $phpEx; + if (!function_exists('phpbb_get_user_rank')) + { + include($phpbb_root_path . 'includes/functions_display.' . $phpEx); + } + + $rank_data = phpbb_get_user_rank(array('user_rank' => $user_rank), $user_posts); + $rank_title = $rank_data['title']; + $rank_img = $rank_data['img']; + $rank_img_src = $rank_data['img_src']; +} diff --git a/phpBB/includes/functions_compress.php b/phpBB/includes/functions_compress.php index 455debd939..a7ee29dd91 100644 --- a/phpBB/includes/functions_compress.php +++ b/phpBB/includes/functions_compress.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,13 +21,17 @@ if (!defined('IN_PHPBB')) /** * Class for handling archives (compression/decompression) -* @package phpBB3 */ class compress { var $fp = 0; /** + * @var array + */ + protected $filelist = array(); + + /** * Add file to archive */ function add_file($src, $src_rm_prefix = '', $src_add_prefix = '', $skip_files = '') @@ -42,7 +49,7 @@ class compress if (is_file($phpbb_root_path . $src)) { - $this->data($src_path, file_get_contents("$phpbb_root_path$src"), false, stat("$phpbb_root_path$src")); + $this->data($src_path, file_get_contents("$phpbb_root_path$src"), stat("$phpbb_root_path$src"), false); } else if (is_dir($phpbb_root_path . $src)) { @@ -82,7 +89,7 @@ class compress continue; } - $this->data("$src_path$path$file", file_get_contents("$phpbb_root_path$src$path$file"), false, stat("$phpbb_root_path$src$path$file")); + $this->data("$src_path$path$file", file_get_contents("$phpbb_root_path$src$path$file"), stat("$phpbb_root_path$src$path$file"), false); } } } @@ -105,7 +112,7 @@ class compress return false; } - $this->data($filename, file_get_contents($src), false, stat($src)); + $this->data($filename, file_get_contents($src), stat($src), false); return true; } @@ -119,14 +126,46 @@ class compress $stat[4] = $stat[5] = 0; $stat[7] = strlen($src); $stat[9] = time(); - $this->data($name, $src, false, $stat); + $this->data($name, $src, $stat, false); return true; } /** + * Checks if a file by that name as already been added and, if it has, + * returns a new, unique name. + * + * @param string $name The filename + * @return string A unique filename + */ + protected function unique_filename($name) + { + if (isset($this->filelist[$name])) + { + $start = $name; + $ext = ''; + $this->filelist[$name]++; + + // Separate the extension off the end of the filename to preserve it + $pos = strrpos($name, '.'); + if ($pos !== false) + { + $start = substr($name, 0, $pos); + $ext = substr($name, $pos); + } + + return $start . '_' . $this->filelist[$name] . $ext; + } + + $this->filelist[$name] = 0; + return $name; + } + + /** * Return available methods + * + * @return array Array of strings of available compression methods (.tar, .tar.gz, .zip, etc.) */ - function methods() + static public function methods() { $methods = array('.tar'); $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib'); @@ -150,12 +189,10 @@ class compress * * Zip extraction function by Alexandre Tedeschi, alexandrebr at gmail dot com * -* Modified extensively by psoTFX and DavidMJ, (c) phpBB Group, 2003 +* Modified extensively by psoTFX and DavidMJ, (c) phpBB Limited, 2003 * * Based on work by Eric Mueller and Denis125 * Official ZIP file format: http://www.pkware.com/appnote.txt -* -* @package phpBB3 */ class compress_zip extends compress { @@ -359,9 +396,10 @@ class compress_zip extends compress /** * Create the structures ... note we assume version made by is MSDOS */ - function data($name, $data, $is_dir = false, $stat) + function data($name, $data, $stat, $is_dir = false) { $name = str_replace('\\', '/', $name); + $name = $this->unique_filename($name); $hexdtime = pack('V', $this->unix_to_dos_time($stat[9])); @@ -471,7 +509,7 @@ class compress_zip extends compress $mimetype = 'application/zip'; - header('Pragma: no-cache'); + header('Cache-Control: private, no-cache'); header("Content-Type: $mimetype; name=\"$download_name.zip\""); header("Content-disposition: attachment; filename=$download_name.zip"); @@ -490,8 +528,6 @@ class compress_zip extends compress /** * Tar/tar.gz compression routine * Header/checksum creation derived from tarfile.pl, (c) Tom Horsley, 1994 -* -* @package phpBB3 */ class compress_tar extends compress { @@ -632,8 +668,9 @@ class compress_tar extends compress /** * Create the structures */ - function data($name, $data, $is_dir = false, $stat) + function data($name, $data, $stat, $is_dir = false) { + $name = $this->unique_filename($name); $this->wrote = true; $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite'); @@ -720,7 +757,7 @@ class compress_tar extends compress break; } - header('Pragma: no-cache'); + header('Cache-Control: private, no-cache'); header("Content-Type: $mimetype; name=\"$download_name$this->type\""); header("Content-disposition: attachment; filename=$download_name$this->type"); @@ -735,5 +772,3 @@ class compress_tar extends compress } } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_content.php b/phpBB/includes/functions_content.php index 19459239d5..6f861b8607 100644 --- a/phpBB/includes/functions_content.php +++ b/phpBB/includes/functions_content.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -75,7 +78,7 @@ function gen_sort_selects(&$limit_days, &$sort_by_text, &$sort_days, &$sort_key, foreach ($sorts as $name => $sort_ary) { $key = $sort_ary['key']; - $selected = $$sort_ary['key']; + $selected = ${$sort_ary['key']}; // Check if the key is selectable. If not, we reset to the default or first key found. // This ensures the values are always valid. We also set $sort_dir/sort_key/etc. to the @@ -84,12 +87,12 @@ function gen_sort_selects(&$limit_days, &$sort_by_text, &$sort_days, &$sort_key, { if ($sort_ary['default'] !== false) { - $selected = $$key = $sort_ary['default']; + $selected = ${$key} = $sort_ary['default']; } else { @reset($sort_ary['options']); - $selected = $$key = key($sort_ary['options']); + $selected = ${$key} = key($sort_ary['options']); } } @@ -111,7 +114,7 @@ function gen_sort_selects(&$limit_days, &$sort_by_text, &$sort_days, &$sort_key, */ function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list = false, $force_display = false) { - global $config, $auth, $template, $user, $db; + global $config, $auth, $template, $user, $db, $phpbb_path_helper; // We only return if the jumpbox is not forced to be displayed (in case it is needed for functionality) if (!$config['load_jumpbox'] && $force_display === false) @@ -171,8 +174,9 @@ function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list $template->assign_block_vars('jumpbox_forums', array( 'FORUM_ID' => ($select_all) ? 0 : -1, 'FORUM_NAME' => ($select_all) ? $user->lang['ALL_FORUMS'] : $user->lang['SELECT_FORUM'], - 'S_FORUM_COUNT' => $iteration) - ); + 'S_FORUM_COUNT' => $iteration, + 'LINK' => $phpbb_path_helper->append_url_params($action, array('f' => $forum_id)), + )); $iteration++; $display_jumpbox = true; @@ -185,8 +189,9 @@ function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list 'S_FORUM_COUNT' => $iteration, 'S_IS_CAT' => ($row['forum_type'] == FORUM_CAT) ? true : false, 'S_IS_LINK' => ($row['forum_type'] == FORUM_LINK) ? true : false, - 'S_IS_POST' => ($row['forum_type'] == FORUM_POST) ? true : false) - ); + 'S_IS_POST' => ($row['forum_type'] == FORUM_POST) ? true : false, + 'LINK' => $phpbb_path_helper->append_url_params($action, array('f' => $row['forum_id'])), + )); for ($i = 0; $i < $padding; $i++) { @@ -197,10 +202,13 @@ function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list $db->sql_freeresult($result); unset($padding_store); + $url_parts = $phpbb_path_helper->get_url_parts($action); + $template->assign_vars(array( - 'S_DISPLAY_JUMPBOX' => $display_jumpbox, - 'S_JUMPBOX_ACTION' => $action) - ); + 'S_DISPLAY_JUMPBOX' => $display_jumpbox, + 'S_JUMPBOX_ACTION' => $action, + 'HIDDEN_FIELDS_FOR_JUMPBOX' => build_hidden_fields($url_parts['params']), + )); return; } @@ -427,16 +435,34 @@ function strip_bbcode(&$text, $uid = '') * For display of custom parsed text on user-facing pages * Expects $text to be the value directly from the database (stored value) */ -function generate_text_for_display($text, $uid, $bitfield, $flags) +function generate_text_for_display($text, $uid, $bitfield, $flags, $censor_text = true) { static $bbcode; + global $phpbb_dispatcher; if ($text === '') { return ''; } - $text = censor_text($text); + /** + * Use this event to modify the text before it is parsed + * + * @event core.modify_text_for_display_before + * @var string text The text to parse + * @var string uid The BBCode UID + * @var string bitfield The BBCode Bitfield + * @var int flags The BBCode Flags + * @var bool censor_text Whether or not to apply word censors + * @since 3.1.0-a1 + */ + $vars = array('text', 'uid', 'bitfield', 'flags', 'censor_text'); + extract($phpbb_dispatcher->trigger_event('core.modify_text_for_display_before', compact($vars))); + + if ($censor_text) + { + $text = censor_text($text); + } // Parse bbcode if bbcode uid stored and bbcode enabled if ($uid && ($flags & OPTION_FLAG_BBCODE)) @@ -462,6 +488,19 @@ function generate_text_for_display($text, $uid, $bitfield, $flags) $text = bbcode_nl2br($text); $text = smiley_text($text, !($flags & OPTION_FLAG_SMILIES)); + /** + * Use this event to modify the text after it is parsed + * + * @event core.modify_text_for_display_after + * @var string text The text to parse + * @var string uid The BBCode UID + * @var string bitfield The BBCode Bitfield + * @var int flags The BBCode Flags + * @since 3.1.0-a1 + */ + $vars = array('text', 'uid', 'bitfield', 'flags'); + extract($phpbb_dispatcher->trigger_event('core.modify_text_for_display_after', compact($vars))); + return $text; } @@ -469,10 +508,44 @@ function generate_text_for_display($text, $uid, $bitfield, $flags) * For parsing custom parsed text to be stored within the database. * This function additionally returns the uid and bitfield that needs to be stored. * Expects $text to be the value directly from request_var() and in it's non-parsed form +* +* @param string $text The text to be replaced with the parsed one +* @param string $uid The BBCode uid for this parse +* @param string $bitfield The BBCode bitfield for this parse +* @param int $flags The allow_bbcode, allow_urls and allow_smilies compiled into a single integer. +* @param bool $allow_bbcode If BBCode is allowed (i.e. if BBCode is parsed) +* @param bool $allow_urls If urls is allowed +* @param bool $allow_smilies If smilies are allowed +* +* @return array An array of string with the errors that occurred while parsing */ function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bbcode = false, $allow_urls = false, $allow_smilies = false) { - global $phpbb_root_path, $phpEx; + global $phpbb_root_path, $phpEx, $phpbb_dispatcher; + + /** + * Use this event to modify the text before it is prepared for storage + * + * @event core.modify_text_for_storage_before + * @var string text The text to parse + * @var string uid The BBCode UID + * @var string bitfield The BBCode Bitfield + * @var int flags The BBCode Flags + * @var bool allow_bbcode Whether or not to parse BBCode + * @var bool allow_urls Whether or not to parse URLs + * @var bool allow_smilies Whether or not to parse Smilies + * @since 3.1.0-a1 + */ + $vars = array( + 'text', + 'uid', + 'bitfield', + 'flags', + 'allow_bbcode', + 'allow_urls', + 'allow_smilies', + ); + extract($phpbb_dispatcher->trigger_event('core.modify_text_for_storage_before', compact($vars))); $uid = $bitfield = ''; $flags = (($allow_bbcode) ? OPTION_FLAG_BBCODE : 0) + (($allow_smilies) ? OPTION_FLAG_SMILIES : 0) + (($allow_urls) ? OPTION_FLAG_LINKS : 0); @@ -501,7 +574,20 @@ function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bb $bitfield = $message_parser->bbcode_bitfield; - return; + /** + * Use this event to modify the text after it is prepared for storage + * + * @event core.modify_text_for_storage_after + * @var string text The text to parse + * @var string uid The BBCode UID + * @var string bitfield The BBCode Bitfield + * @var int flags The BBCode Flags + * @since 3.1.0-a1 + */ + $vars = array('text', 'uid', 'bitfield', 'flags'); + extract($phpbb_dispatcher->trigger_event('core.modify_text_for_storage_after', compact($vars))); + + return $message_parser->warn_msg; } /** @@ -510,10 +596,33 @@ function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bb */ function generate_text_for_edit($text, $uid, $flags) { - global $phpbb_root_path, $phpEx; + global $phpbb_root_path, $phpEx, $phpbb_dispatcher; + + /** + * Use this event to modify the text before it is decoded for editing + * + * @event core.modify_text_for_edit_before + * @var string text The text to parse + * @var string uid The BBCode UID + * @var int flags The BBCode Flags + * @since 3.1.0-a1 + */ + $vars = array('text', 'uid', 'flags'); + extract($phpbb_dispatcher->trigger_event('core.modify_text_for_edit_before', compact($vars))); decode_message($text, $uid); + /** + * Use this event to modify the text after it is decoded for editing + * + * @event core.modify_text_for_edit_after + * @var string text The text to parse + * @var int flags The BBCode Flags + * @since 3.1.0-a1 + */ + $vars = array('text', 'flags'); + extract($phpbb_dispatcher->trigger_event('core.modify_text_for_edit_after', compact($vars))); + return array( 'allow_bbcode' => ($flags & OPTION_FLAG_BBCODE) ? 1 : 0, 'allow_smilies' => ($flags & OPTION_FLAG_SMILIES) ? 1 : 0, @@ -603,7 +712,7 @@ function make_clickable_callback($type, $whitespace, $url, $relative_url, $class break; } - $short_url = (strlen($url) > 55) ? substr($url, 0, 39) . ' ... ' . substr($url, -10) : $url; + $short_url = (utf8_strlen($url) > 55) ? utf8_substr($url, 0, 39) . ' ... ' . utf8_substr($url, -10) : $url; switch ($type) { @@ -663,37 +772,62 @@ function make_clickable($text, $server_url = false, $class = 'postlink') $server_url = generate_board_url(); } - static $magic_url_match; - static $magic_url_replace; static $static_class; + static $magic_url_match_args; - if (!is_array($magic_url_match) || $static_class != $class) + if (!isset($magic_url_match_args[$server_url]) || $static_class != $class) { $static_class = $class; $class = ($static_class) ? ' class="' . $static_class . '"' : ''; $local_class = ($static_class) ? ' class="' . $static_class . '-local"' : ''; - $magic_url_match = $magic_url_replace = array(); - // Be sure to not let the matches cross over. ;) + if (!is_array($magic_url_match_args)) + { + $magic_url_match_args = array(); + } // relative urls for this board - $magic_url_match[] = '#(^|[\n\t (>.])(' . preg_quote($server_url, '#') . ')/(' . get_preg_expression('relative_url_inline') . ')#ie'; - $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_LOCAL, '\$1', '\$2', '\$3', '$local_class')"; + $magic_url_match_args[$server_url][] = array( + '#(^|[\n\t (>.])(' . preg_quote($server_url, '#') . ')/(' . get_preg_expression('relative_url_inline') . ')#iu', + MAGIC_URL_LOCAL, + $local_class, + ); // matches a xxxx://aaaaa.bbb.cccc. ... - $magic_url_match[] = '#(^|[\n\t (>.])(' . get_preg_expression('url_inline') . ')#ie'; - $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_FULL, '\$1', '\$2', '', '$class')"; + $magic_url_match_args[$server_url][] = array( + '#(^|[\n\t (>.])(' . get_preg_expression('url_inline') . ')#iu', + MAGIC_URL_FULL, + $class, + ); // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing - $magic_url_match[] = '#(^|[\n\t (>])(' . get_preg_expression('www_url_inline') . ')#ie'; - $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_WWW, '\$1', '\$2', '', '$class')"; + $magic_url_match_args[$server_url][] = array( + '#(^|[\n\t (>])(' . get_preg_expression('www_url_inline') . ')#iu', + MAGIC_URL_WWW, + $class, + ); // matches an email@domain type address at the start of a line, or after a space or after what might be a BBCode. - $magic_url_match[] = '/(^|[\n\t (>])(' . get_preg_expression('email') . ')/ie'; - $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_EMAIL, '\$1', '\$2', '', '')"; + $magic_url_match_args[$server_url][] = array( + '/(^|[\n\t (>])(' . get_preg_expression('email') . ')/iu', + MAGIC_URL_EMAIL, + '', + ); + } + + foreach ($magic_url_match_args[$server_url] as $magic_args) + { + if (preg_match($magic_args[0], $text, $matches)) + { + $text = preg_replace_callback($magic_args[0], function($matches) use ($magic_args) + { + $relative_url = isset($matches[3]) ? $matches[3] : ''; + return make_clickable_callback($magic_args[1], $matches[1], $matches[2], $relative_url, $magic_args[2]); + }, $text); + } } - return preg_replace($magic_url_match, $magic_url_replace, $text); + return $text; } /** @@ -749,7 +883,7 @@ function bbcode_nl2br($text) */ function smiley_text($text, $force_option = false) { - global $config, $user, $phpbb_root_path; + global $config, $user, $phpbb_path_helper; if ($force_option || !$config['allow_smilies'] || !$user->optionget('viewsmilies')) { @@ -757,8 +891,8 @@ function smiley_text($text, $force_option = false) } else { - $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; - return preg_replace('#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/(.*?) \/><!\-\- s\1 \-\->#', '<img src="' . $root_path . $config['smilies_path'] . '/\2 />', $text); + $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_path_helper->get_web_root_path(); + return preg_replace('#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/(.*?) \/><!\-\- s\1 \-\->#', '<img class="smilies" src="' . $root_path . $config['smilies_path'] . '/\2 />', $text); } } @@ -778,7 +912,7 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, return; } - global $template, $cache, $user; + global $template, $cache, $user, $phpbb_dispatcher; global $extensions, $config, $phpbb_root_path, $phpEx; // @@ -956,12 +1090,12 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, } $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id']); + $l_downloaded_viewed = 'VIEWED_COUNTS'; switch ($display_cat) { // Images case ATTACHMENT_CATEGORY_IMAGE: - $l_downloaded_viewed = 'VIEWED_COUNT'; $inline_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id']); $download_link .= '&mode=view'; @@ -975,7 +1109,6 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, // Images, but display Thumbnail case ATTACHMENT_CATEGORY_THUMB: - $l_downloaded_viewed = 'VIEWED_COUNT'; $thumbnail_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id'] . '&t=1'); $download_link .= '&mode=view'; @@ -989,7 +1122,6 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, // Windows Media Streams case ATTACHMENT_CATEGORY_WM: - $l_downloaded_viewed = 'VIEWED_COUNT'; // Giving the filename directly because within the wm object all variables are in local context making it impossible // to validate against a valid session (all params can differ) @@ -1008,7 +1140,6 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, // Real Media Streams case ATTACHMENT_CATEGORY_RM: case ATTACHMENT_CATEGORY_QUICKTIME: - $l_downloaded_viewed = 'VIEWED_COUNT'; $block_array += array( 'S_RM_FILE' => ($display_cat == ATTACHMENT_CATEGORY_RM) ? true : false, @@ -1025,8 +1156,6 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, case ATTACHMENT_CATEGORY_FLASH: list($width, $height) = @getimagesize($filename); - $l_downloaded_viewed = 'VIEWED_COUNT'; - $block_array += array( 'S_FLASH_FILE' => true, 'WIDTH' => $width, @@ -1039,7 +1168,7 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, break; default: - $l_downloaded_viewed = 'DOWNLOAD_COUNT'; + $l_downloaded_viewed = 'DOWNLOAD_COUNTS'; $block_array += array( 'S_FILE' => true, @@ -1047,14 +1176,45 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, break; } - $l_download_count = (!isset($attachment['download_count']) || $attachment['download_count'] == 0) ? $user->lang[$l_downloaded_viewed . '_NONE'] : (($attachment['download_count'] == 1) ? sprintf($user->lang[$l_downloaded_viewed], $attachment['download_count']) : sprintf($user->lang[$l_downloaded_viewed . 'S'], $attachment['download_count'])); + if (!isset($attachment['download_count'])) + { + $attachment['download_count'] = 0; + } $block_array += array( 'U_DOWNLOAD_LINK' => $download_link, - 'L_DOWNLOAD_COUNT' => $l_download_count + 'L_DOWNLOAD_COUNT' => $user->lang($l_downloaded_viewed, (int) $attachment['download_count']), ); } + /** + * Use this event to modify the attachment template data. + * + * This event is triggered once per attachment. + * + * @event core.parse_attachments_modify_template_data + * @var array attachment Array with attachment data + * @var array block_array Template data of the attachment + * @var int display_cat Attachment category data + * @var string download_link Attachment download link + * @var array extensions Array with attachment extensions data + * @var mixed forum_id The forum id the attachments are displayed in (false if in private message) + * @var bool preview Flag indicating if we are in post preview mode + * @var array update_count Array with attachment ids to update download count + * @since 3.1.0-RC5 + */ + $vars = array( + 'attachment', + 'block_array', + 'display_cat', + 'download_link', + 'extensions', + 'forum_id', + 'preview', + 'update_count', + ); + extract($phpbb_dispatcher->trigger_event('core.parse_attachments_modify_template_data', compact($vars))); + $template->assign_block_vars('_file', $block_array); $compiled_attachments[] = $template->assign_display('attachment_tpl'); @@ -1124,8 +1284,8 @@ function extension_allowed($forum_id, $extension, &$extensions) * @param string $string The text to truncate to the given length. String is specialchared. * @param int $max_length Maximum length of string (multibyte character count as 1 char / Html entity count as 1 char) * @param int $max_store_length Maximum character length of string (multibyte character count as 1 char / Html entity count as entity chars). -* @param bool $allow_reply Allow Re: in front of string -* NOTE: This parameter can cause undesired behavior (returning strings longer than $max_store_length) and is deprecated. +* @param bool $allow_reply Allow Re: in front of string +* NOTE: This parameter can cause undesired behavior (returning strings longer than $max_store_length) and is deprecated. * @param string $append String to be appended */ function truncate_string($string, $max_length = 60, $max_store_length = 255, $allow_reply = false, $append = '') @@ -1191,11 +1351,11 @@ function truncate_string($string, $max_length = 60, $max_store_length = 255, $al * @param string $custom_profile_url optional parameter to specify a profile url. The user id get appended to this url as &u={user_id} * * @return string A string consisting of what is wanted based on $mode. -* @author BartVB, Acyd Burn */ function get_username_string($mode, $user_id, $username, $username_colour = '', $guest_username = false, $custom_profile_url = false) { static $_profile_cache; + global $phpbb_dispatcher; // We cache some common variables we need within this function if (empty($_profile_cache)) @@ -1203,9 +1363,9 @@ function get_username_string($mode, $user_id, $username, $username_colour = '', global $phpbb_root_path, $phpEx; $_profile_cache['base_url'] = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u={USER_ID}'); - $_profile_cache['tpl_noprofile'] = '{USERNAME}'; + $_profile_cache['tpl_noprofile'] = '<span class="username">{USERNAME}</span>'; $_profile_cache['tpl_noprofile_colour'] = '<span style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</span>'; - $_profile_cache['tpl_profile'] = '<a href="{PROFILE_URL}">{USERNAME}</a>'; + $_profile_cache['tpl_profile'] = '<a href="{PROFILE_URL}" class="username">{USERNAME}</a>'; $_profile_cache['tpl_profile_colour'] = '<a href="{PROFILE_URL}" style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</a>'; } @@ -1224,7 +1384,8 @@ function get_username_string($mode, $user_id, $username, $username_colour = '', // Return colour if ($mode == 'colour') { - return $username_colour; + $username_string = $username_colour; + break; } // no break; @@ -1244,7 +1405,8 @@ function get_username_string($mode, $user_id, $username, $username_colour = '', // Return username if ($mode == 'username') { - return $username; + $username_string = $username; + break; } // no break; @@ -1265,23 +1427,108 @@ function get_username_string($mode, $user_id, $username, $username_colour = '', // Return profile if ($mode == 'profile') { - return $profile_url; + $username_string = $profile_url; + break; } // no break; } - if (($mode == 'full' && !$profile_url) || $mode == 'no_profile') + if (!isset($username_string)) { - return str_replace(array('{USERNAME_COLOUR}', '{USERNAME}'), array($username_colour, $username), (!$username_colour) ? $_profile_cache['tpl_noprofile'] : $_profile_cache['tpl_noprofile_colour']); + if (($mode == 'full' && !$profile_url) || $mode == 'no_profile') + { + $username_string = str_replace(array('{USERNAME_COLOUR}', '{USERNAME}'), array($username_colour, $username), (!$username_colour) ? $_profile_cache['tpl_noprofile'] : $_profile_cache['tpl_noprofile_colour']); + } + else + { + $username_string = str_replace(array('{PROFILE_URL}', '{USERNAME_COLOUR}', '{USERNAME}'), array($profile_url, $username_colour, $username), (!$username_colour) ? $_profile_cache['tpl_profile'] : $_profile_cache['tpl_profile_colour']); + } } - return str_replace(array('{PROFILE_URL}', '{USERNAME_COLOUR}', '{USERNAME}'), array($profile_url, $username_colour, $username), (!$username_colour) ? $_profile_cache['tpl_profile'] : $_profile_cache['tpl_profile_colour']); + /** + * Use this event to change the output of get_username_string() + * + * @event core.modify_username_string + * @var string mode profile|username|colour|full|no_profile + * @var int user_id String or array of additional url + * parameters + * @var string username The user's username + * @var string username_colour The user's colour + * @var string guest_username Optional parameter to specify the + * guest username. + * @var string custom_profile_url Optional parameter to specify a + * profile url. + * @var string username_string The string that has been generated + * @var array _profile_cache Array of original return templates + * @since 3.1.0-a1 + */ + $vars = array( + 'mode', + 'user_id', + 'username', + 'username_colour', + 'guest_username', + 'custom_profile_url', + 'username_string', + '_profile_cache', + ); + extract($phpbb_dispatcher->trigger_event('core.modify_username_string', compact($vars))); + + return $username_string; } /** -* @package phpBB3 + * Add an option to the quick-mod tools. + * + * @param string $url The recepting URL for the quickmod actions. + * @param string $option The language key for the value of the option. + * @param string $lang_string The language string to use. + */ +function phpbb_add_quickmod_option($url, $option, $lang_string) +{ + global $template, $user, $phpbb_path_helper; + + $lang_string = $user->lang($lang_string); + $template->assign_block_vars('quickmod', array( + 'VALUE' => $option, + 'TITLE' => $lang_string, + 'LINK' => $phpbb_path_helper->append_url_params($url, array('action' => $option)), + )); +} + +/** +* Concatenate an array into a string list. +* +* @param array $items Array of items to concatenate +* @param object $user The phpBB $user object. +* +* @return string String list. Examples: "A"; "A and B"; "A, B, and C" */ +function phpbb_generate_string_list($items, $user) +{ + if (empty($items)) + { + return ''; + } + + $count = sizeof($items); + $last_item = array_pop($items); + $lang_key = 'STRING_LIST_MULTI'; + + if ($count == 1) + { + return $last_item; + } + else if ($count == 2) + { + $lang_key = 'STRING_LIST_SIMPLE'; + } + $list = implode($user->lang['COMMA_SEPARATOR'], $items); + + return $user->lang($lang_key, $list, $last_item); +} + class bitfield { var $data; @@ -1372,5 +1619,3 @@ class bitfield $this->data = $this->data | $bitfield->get_blob(); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php index 3b26f417e9..61ab4721c4 100644 --- a/phpBB/includes/functions_convert.php +++ b/phpBB/includes/functions_convert.php @@ -1,10 +1,13 @@ <?php /** * -* @package install -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -824,7 +827,7 @@ function get_avatar_dim($src, $axis, $func = false, $arg1 = false, $arg2 = false break; case AVATAR_REMOTE: - // see notes on this functions usage and (hopefully) model $func to avoid this accordingly + // see notes on this functions usage and (hopefully) model $func to avoid this accordingly return get_remote_avatar_dim($src, $axis); break; @@ -1004,8 +1007,8 @@ function get_remote_avatar_dim($src, $axis) { $bigger = ($remote_avatar_cache[$src][0] > $remote_avatar_cache[$src][1]) ? 0 : 1; $ratio = $default[$bigger] / $remote_avatar_cache[$src][$bigger]; - $remote_avatar_cache[$src][0] = (int)($remote_avatar_cache[$src][0] * $ratio); - $remote_avatar_cache[$src][1] = (int)($remote_avatar_cache[$src][1] * $ratio); + $remote_avatar_cache[$src][0] = (int) ($remote_avatar_cache[$src][0] * $ratio); + $remote_avatar_cache[$src][1] = (int) ($remote_avatar_cache[$src][1] * $ratio); } } @@ -1028,7 +1031,6 @@ function set_user_options() 'attachsig' => array('bit' => 6, 'default' => 0), 'bbcode' => array('bit' => 8, 'default' => 1), 'smilies' => array('bit' => 9, 'default' => 1), - 'popuppm' => array('bit' => 10, 'default' => 0), 'sig_bbcode' => array('bit' => 15, 'default' => 1), 'sig_smilies' => array('bit' => 16, 'default' => 1), 'sig_links' => array('bit' => 17, 'default' => 1), @@ -1118,7 +1120,7 @@ function words_unique(&$words) * Adds a user to the specified group and optionally makes them a group leader * This function does not create the group if it does not exist and so should only be called after the groups have been created */ -function add_user_group($group_id, $user_id, $group_leader=false) +function add_user_group($group_id, $user_id, $group_leader = false) { global $convert, $phpbb_root_path, $config, $user, $db; @@ -1238,7 +1240,7 @@ function get_config() $filename = $convert->options['forum_path'] . '/' . $convert->config_schema['filename']; if (!file_exists($filename)) { - $convert->p_master->error($user->lang['FILE_NOT_FOUND'] . ': ' . $filename, __LINE__, __FILE__); + $convert->p_master->error($user->lang('FILE_NOT_FOUND', $filename), __LINE__, __FILE__); } if (isset($convert->config_schema['array_name'])) @@ -1285,7 +1287,9 @@ function restore_config($schema) { $var = (empty($m[2]) || empty($convert_config[$m[2]])) ? "''" : "'" . addslashes($convert_config[$m[2]]) . "'"; $exec = '$config_value = ' . $m[1] . '(' . $var . ');'; + // @codingStandardsIgnoreStart eval($exec); + // @codingStandardsIgnoreEnd } else { @@ -1298,7 +1302,7 @@ function restore_config($schema) $src_ary = $schema['array_name']; $config_value = (isset($convert_config[$src_ary][$src])) ? $convert_config[$src_ary][$src] : ''; } - } + } if ($config_value !== '') { @@ -1643,7 +1647,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO) switch ($sql_type) { case 'insert': - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'mysql': case 'mysql4': @@ -1652,6 +1656,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO) case 'mssql': case 'sqlite': + case 'sqlite3': case 'mssqlnative': $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); break; @@ -1720,7 +1725,7 @@ function add_default_groups() 'GUESTS' => array('', 0, 0), 'REGISTERED' => array('', 0, 0), 'REGISTERED_COPPA' => array('', 0, 0), - 'GLOBAL_MODERATORS' => array('00AA00', 1, 0), + 'GLOBAL_MODERATORS' => array('00AA00', 2, 0), 'ADMINISTRATORS' => array('AA0000', 1, 1), 'BOTS' => array('9E8DA7', 0, 0), 'NEWLY_REGISTERED' => array('', 0, 0), @@ -1749,7 +1754,7 @@ function add_default_groups() 'group_type' => GROUP_SPECIAL, 'group_colour' => (string) $data[0], 'group_legend' => (int) $data[1], - 'group_founder_manage' => (int) $data[2] + 'group_founder_manage' => (int) $data[2], ); } @@ -1759,6 +1764,38 @@ function add_default_groups() } } +function add_groups_to_teampage() +{ + global $db; + + $teampage_groups = array( + 'ADMINISTRATORS' => 1, + 'GLOBAL_MODERATORS' => 2, + ); + + $sql = 'SELECT * + FROM ' . GROUPS_TABLE . ' + WHERE ' . $db->sql_in_set('group_name', array_keys($teampage_groups)); + $result = $db->sql_query($sql); + + $teampage_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $teampage_ary[] = array( + 'group_id' => (int) $row['group_id'], + 'teampage_name' => '', + 'teampage_position' => (int) $teampage_groups[$row['group_name']], + 'teampage_parent' => 0, + ); + } + $db->sql_freeresult($result); + + if (sizeof($teampage_ary)) + { + $db->sql_multi_insert(TEAMPAGE_TABLE, $teampage_ary); + } +} + /** * Sync post count. We might need to do this in batches. @@ -1769,7 +1806,7 @@ function sync_post_count($offset, $limit) $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id FROM ' . POSTS_TABLE . ' WHERE post_postcount = 1 - AND post_approved = 1 + AND post_visibility = ' . ITEM_APPROVED . ' GROUP BY poster_id ORDER BY poster_id'; $result = $db->sql_query_limit($sql, $limit, $offset); @@ -1885,7 +1922,7 @@ function add_bots() 'user_email' => '', 'user_lang' => $config['default_lang'], 'user_style' => 1, - 'user_timezone' => 0, + 'user_timezone' => 'UTC', 'user_allow_massemail' => 0, ); @@ -1942,7 +1979,7 @@ function update_dynamic_config() $sql = 'SELECT COUNT(post_id) AS stat FROM ' . POSTS_TABLE . ' - WHERE post_approved = 1'; + WHERE post_visibility = ' . ITEM_APPROVED; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -1951,7 +1988,7 @@ function update_dynamic_config() $sql = 'SELECT COUNT(topic_id) AS stat FROM ' . TOPICS_TABLE . ' - WHERE topic_approved = 1'; + WHERE topic_visibility = ' . ITEM_APPROVED; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -2004,10 +2041,10 @@ function update_topics_posted() { global $db, $config; - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'sqlite': - case 'firebird': + case 'sqlite3': $db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE); break; @@ -2111,6 +2148,7 @@ function fix_empty_primary_groups() } $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . ' WHERE group_id = ' . get_group_id('global_moderators'); + $result = $db->sql_query($sql); $user_ids = array(); while ($row = $db->sql_fetchrow($result)) @@ -2259,7 +2297,7 @@ function convert_bbcode($message, $convert_size = true, $extended_bbcodes = fals $message = preg_replace('#\[size=([0-9]+)\](.*?)\[/size\]#i', '[size=\1]\2[/size]', $message); $message = preg_replace('#\[size=[0-9]{2,}\](.*?)\[/size\]#i', '[size=29]\1[/size]', $message); - for ($i = sizeof($size); $i; ) + for ($i = sizeof($size); $i;) { $i--; $message = str_replace('[size=' . $i . ']', '[size=' . $size[$i] . ']', $message); @@ -2473,7 +2511,3 @@ function fill_dateformat($user_dateformat) return ((empty($user_dateformat)) ? $config['default_dateformat'] : $user_dateformat); } - - - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_database_helper.php b/phpBB/includes/functions_database_helper.php index 664c246888..8f363d56f3 100644 --- a/phpBB/includes/functions_database_helper.php +++ b/phpBB/includes/functions_database_helper.php @@ -1,9 +1,13 @@ <?php /** * -* @package phpBB3 -* @copyright (c) 2012 phpBB Group -* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* 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. * */ @@ -22,14 +26,14 @@ if (!defined('IN_PHPBB')) * * The only supported table is bookmarks. * -* @param dbal $db Database object +* @param \phpbb\db\driver\driver_interface $db Database object * @param string $table Table on which to perform the update * @param string $column Column whose values to change * @param array $from_values An array of values that should be changed * @param int $to_value The new value * @return null */ -function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_values, $to_value) +function phpbb_update_rows_avoiding_duplicates(\phpbb\db\driver\driver_interface $db, $table, $column, $from_values, $to_value) { $sql = "SELECT $column, user_id FROM $table @@ -107,14 +111,14 @@ function phpbb_update_rows_avoiding_duplicates($db, $table, $column, $from_value * * The only supported table is topics_watch. * -* @param dbal $db Database object +* @param \phpbb\db\driver\driver_interface $db Database object * @param string $table Table on which to perform the update * @param string $column Column whose values to change * @param array $from_values An array of values that should be changed * @param int $to_value The new value * @return null */ -function phpbb_update_rows_avoiding_duplicates_notify_status($db, $table, $column, $from_values, $to_value) +function phpbb_update_rows_avoiding_duplicates_notify_status(\phpbb\db\driver\driver_interface $db, $table, $column, $from_values, $to_value) { $sql = "SELECT $column, user_id, notify_status FROM $table diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index ee7048638d..b62b514293 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -23,6 +26,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod { global $db, $auth, $user, $template; global $phpbb_root_path, $phpEx, $config; + global $request, $phpbb_dispatcher, $phpbb_container; $forum_rows = $subforums = $forum_ids = $forum_ids_moderator = $forum_moderators = $active_forum_ary = array(); $parent_id = $visible_forums = 0; @@ -54,12 +58,26 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod // Handle marking everything read if ($mark_read == 'all') { - $redirect = build_url(array('mark', 'hash')); + $redirect = build_url(array('mark', 'hash', 'mark_time')); meta_refresh(3, $redirect); if (check_link_hash(request_var('hash', ''), 'global')) { - markread('all'); + markread('all', false, false, request_var('mark_time', 0)); + + if ($request->is_ajax()) + { + // Tell the ajax script what language vars and URL need to be replaced + $data = array( + 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'], + 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'], + 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}index.$phpEx", 'hash=' . generate_link_hash('global') . '&mark=forums&mark_time=' . time()) : '', + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED'] + ); + $json_response = new \phpbb\json_response(); + $json_response->send($data); + } trigger_error( $user->lang['FORUMS_MARKED'] . '<br /><br />' . @@ -90,7 +108,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod } else if ($config['load_anon_lastread'] || $user->data['is_registered']) { - $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : ''; + $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); if (!$user->data['is_registered']) @@ -109,7 +127,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod $sql_array['SELECT'] .= ', fa.user_id'; } - $sql = $db->sql_build_query('SELECT', array( + $sql_ary = array( 'SELECT' => $sql_array['SELECT'], 'FROM' => $sql_array['FROM'], 'LEFT_JOIN' => $sql_array['LEFT_JOIN'], @@ -117,27 +135,41 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'WHERE' => $sql_where, 'ORDER_BY' => 'f.left_id', - )); + ); + /** + * Event to modify the SQL query before the forum data is queried + * + * @event core.display_forums_modify_sql + * @var array sql_ary The SQL array to get the data of the forums + * @since 3.1.0-a1 + */ + $vars = array('sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_sql', compact($vars))); + + $sql = $db->sql_build_query('SELECT', $sql_ary); $result = $db->sql_query($sql); $forum_tracking_info = array(); $branch_root_id = $root_data['forum_id']; - // Check for unread global announcements (index page only) - $ga_unread = false; - if ($root_data['forum_id'] == 0) - { - $unread_ga_list = get_unread_topics($user->data['user_id'], 'AND t.forum_id = 0', '', 1); - - if (!empty($unread_ga_list)) - { - $ga_unread = true; - } - } + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); while ($row = $db->sql_fetchrow($result)) { + /** + * Event to modify the data set of a forum + * + * This event is triggered once per forum + * + * @event core.display_forums_modify_row + * @var int branch_root_id Last top-level forum + * @var array row The data of the forum + * @since 3.1.0-a1 + */ + $vars = array('branch_root_id', 'row'); + extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_row', compact($vars))); + $forum_id = $row['forum_id']; // Mark forums read? @@ -187,9 +219,11 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod $forum_tracking_info[$forum_id] = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark']; } - // Count the difference of real to public topics, so we can display an information to moderators - $row['forum_id_unapproved_topics'] = ($auth->acl_get('m_approve', $forum_id) && ($row['forum_topics_real'] != $row['forum_topics'])) ? $forum_id : 0; - $row['forum_topics'] = ($auth->acl_get('m_approve', $forum_id)) ? $row['forum_topics_real'] : $row['forum_topics']; + // Lets check whether there are unapproved topics/posts, so we can display an information to moderators + $row['forum_id_unapproved_topics'] = ($auth->acl_get('m_approve', $forum_id) && $row['forum_topics_unapproved']) ? $forum_id : 0; + $row['forum_id_unapproved_posts'] = ($auth->acl_get('m_approve', $forum_id) && $row['forum_posts_unapproved']) ? $forum_id : 0; + $row['forum_posts'] = $phpbb_content_visibility->get_count('forum_posts', $row, $forum_id); + $row['forum_topics'] = $phpbb_content_visibility->get_count('forum_topics', $row, $forum_id); // Display active topics from this forum? if ($show_active && $row['forum_type'] == FORUM_POST && $auth->acl_get('f_read', $forum_id) && ($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS)) @@ -252,6 +286,11 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod $forum_rows[$parent_id]['forum_id_unapproved_topics'] = $forum_id; } + if (!$forum_rows[$parent_id]['forum_id_unapproved_posts'] && $row['forum_id_unapproved_posts']) + { + $forum_rows[$parent_id]['forum_id_unapproved_posts'] = $forum_id; + } + $forum_rows[$parent_id]['forum_topics'] += $row['forum_topics']; // Do not list redirects in LINK Forums as Posts. @@ -271,21 +310,50 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod $forum_rows[$parent_id]['forum_id_last_post'] = $forum_id; } } + + /** + * Event to modify the forum rows data set + * + * This event is triggered once per forum + * + * @event core.display_forums_modify_forum_rows + * @var array forum_rows Data array of all forums we display + * @var array subforums Data array of all subforums we display + * @var int branch_root_id Current top-level forum + * @var int parent_id Current parent forum + * @var array row The data of the forum + * @since 3.1.0-a1 + */ + $vars = array('forum_rows', 'subforums', 'branch_root_id', 'parent_id', 'row'); + extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_forum_rows', compact($vars))); } $db->sql_freeresult($result); // Handle marking posts if ($mark_read == 'forums') { - $redirect = build_url(array('mark', 'hash')); + $redirect = build_url(array('mark', 'hash', 'mark_time')); $token = request_var('hash', ''); if (check_link_hash($token, 'global')) { - // Add 0 to forums array to mark global announcements correctly - $forum_ids[] = 0; - markread('topics', $forum_ids); + markread('topics', $forum_ids, false, request_var('mark_time', 0)); $message = sprintf($user->lang['RETURN_FORUM'], '<a href="' . $redirect . '">', '</a>'); meta_refresh(3, $redirect); + + if ($request->is_ajax()) + { + // Tell the ajax script what language vars and URL need to be replaced + $data = array( + 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'], + 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'], + 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'hash=' . generate_link_hash('global') . '&f=' . $root_data['forum_id'] . '&mark=forums&mark_time=' . time()) : '', + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED'] + ); + $json_response = new \phpbb\json_response(); + $json_response->send($data); + } + trigger_error($user->lang['FORUMS_MARKED'] . '<br /><br />' . $message); } else @@ -307,14 +375,36 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod get_moderators($forum_moderators, $forum_ids_moderator); } + /** + * Event to perform additional actions before the forum list is being generated + * + * @event core.display_forums_before + * @var array active_forum_ary Array with forum data to display active topics + * @var bool display_moderators Flag indicating if we display forum moderators + * @var array forum_moderators Array with forum moderators list + * @var array forum_rows Data array of all forums we display + * @var bool return_moderators Flag indicating if moderators list should be returned + * @var array root_data Array with the root forum data + * @since 3.1.4-RC1 + */ + $vars = array( + 'active_forum_ary', + 'display_moderators', + 'forum_moderators', + 'forum_rows', + 'return_moderators', + 'root_data', + ); + extract($phpbb_dispatcher->trigger_event('core.display_forums_before', compact($vars))); + // Used to tell whatever we have to create a dummy category or not. $last_catless = true; foreach ($forum_rows as $row) { - // Empty category + // Category if ($row['parent_id'] == $root_data['forum_id'] && $row['forum_type'] == FORUM_CAT) { - $template->assign_block_vars('forumrow', array( + $cat_row = array( 'S_IS_CAT' => true, 'FORUM_ID' => $row['forum_id'], 'FORUM_NAME' => $row['forum_name'], @@ -323,8 +413,32 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'FORUM_FOLDER_IMG_SRC' => '', 'FORUM_IMAGE' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="' . $user->lang['FORUM_CAT'] . '" />' : '', 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', - 'U_VIEWFORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id'])) + 'U_VIEWFORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']), + ); + + /** + * Modify the template data block of the 'category' + * + * This event is triggered once per 'category' + * + * @event core.display_forums_modify_category_template_vars + * @var array cat_row Template data of the 'category' + * @var bool catless The flag indicating whether the 'category' has a parent category + * @var bool last_catless The flag indicating whether the last forum had a parent category + * @var array root_data Array with the root forum data + * @var array row The data of the 'category' + * @since 3.1.0-RC4 + */ + $vars = array( + 'cat_row', + 'catless', + 'last_catless', + 'root_data', + 'row', ); + extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_category_template_vars', compact($vars))); + + $template->assign_block_vars('forumrow', $cat_row); continue; } @@ -334,12 +448,6 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod $forum_unread = (isset($forum_tracking_info[$forum_id]) && $row['orig_forum_last_post_time'] > $forum_tracking_info[$forum_id]) ? true : false; - // Mark the first visible forum on index as unread if there's any unread global announcement - if ($ga_unread && !empty($forum_ids_moderator) && $forum_id == $forum_ids_moderator[0]) - { - $forum_unread = true; - } - $folder_image = $folder_alt = $l_subforums = ''; $subforums_list = array(); @@ -383,7 +491,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod } } - $l_subforums = (sizeof($subforums[$forum_id]) == 1) ? $user->lang['SUBFORUM'] . ': ' : $user->lang['SUBFORUMS'] . ': '; + $l_subforums = (sizeof($subforums[$forum_id]) == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS']; $folder_image = ($forum_unread) ? 'forum_unread_subforum' : 'forum_read_subforum'; } else @@ -415,12 +523,13 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod if ($row['forum_last_post_id']) { $last_post_subject = $row['forum_last_post_subject']; + $last_post_subject_truncated = truncate_string(censor_text($last_post_subject), 30, 255, false, $user->lang['ELLIPSIS']); $last_post_time = $user->format_date($row['forum_last_post_time']); $last_post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id_last_post'] . '&p=' . $row['forum_last_post_id']) . '#p' . $row['forum_last_post_id']; } else { - $last_post_subject = $last_post_time = $last_post_url = ''; + $last_post_subject = $last_post_time = $last_post_url = $last_post_subject_truncated = ''; } // Output moderator listing ... if applicable @@ -428,18 +537,23 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod if ($display_moderators && !empty($forum_moderators[$forum_id])) { $l_moderator = (sizeof($forum_moderators[$forum_id]) == 1) ? $user->lang['MODERATOR'] : $user->lang['MODERATORS']; - $moderators_list = implode(', ', $forum_moderators[$forum_id]); + $moderators_list = implode($user->lang['COMMA_SEPARATOR'], $forum_moderators[$forum_id]); } $l_post_click_count = ($row['forum_type'] == FORUM_LINK) ? 'CLICKS' : 'POSTS'; $post_click_count = ($row['forum_type'] != FORUM_LINK || $row['forum_flags'] & FORUM_FLAG_LINK_TRACK) ? $row['forum_posts'] : ''; - $s_subforums_list = array(); + $s_subforums_list = $subforums_row = array(); foreach ($subforums_list as $subforum) { $s_subforums_list[] = '<a href="' . $subforum['link'] . '" class="subforum ' . (($subforum['unread']) ? 'unread' : 'read') . '" title="' . (($subforum['unread']) ? $user->lang['UNREAD_POSTS'] : $user->lang['NO_UNREAD_POSTS']) . '">' . $subforum['name'] . '</a>'; + $subforums_row[] = array( + 'U_SUBFORUM' => $subforum['link'], + 'SUBFORUM_NAME' => $subforum['name'], + 'S_UNREAD' => $subforum['unread'], + ); } - $s_subforums_list = (string) implode(', ', $s_subforums_list); + $s_subforums_list = (string) implode($user->lang['COMMA_SEPARATOR'], $s_subforums_list); $catless = ($row['parent_id'] == $root_data['forum_id']) ? true : false; if ($row['forum_type'] != FORUM_LINK) @@ -460,7 +574,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod } } - $template->assign_block_vars('forumrow', array( + $forum_row = array( 'S_IS_CAT' => false, 'S_NO_CAT' => $catless && !$last_catless, 'S_IS_LINK' => ($row['forum_type'] == FORUM_LINK) ? true : false, @@ -469,6 +583,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'S_LOCKED_FORUM' => ($row['forum_status'] == ITEM_LOCKED) ? true : false, 'S_LIST_SUBFORUMS' => ($row['display_subforum_list']) ? true : false, 'S_SUBFORUMS' => (sizeof($subforums_list)) ? true : false, + 'S_DISPLAY_SUBJECT' => ($last_post_subject && $config['display_last_subject'] && !$row['forum_password'] && $auth->acl_get('f_read', $row['forum_id'])) ? true : false, 'S_FEED_ENABLED' => ($config['feed_forum'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $row['forum_options']) && $row['forum_type'] == FORUM_POST) ? true : false, 'FORUM_ID' => $row['forum_id'], @@ -476,12 +591,13 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'FORUM_DESC' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), 'TOPICS' => $row['forum_topics'], $l_post_click_count => $post_click_count, + 'FORUM_IMG_STYLE' => $folder_image, 'FORUM_FOLDER_IMG' => $user->img($folder_image, $folder_alt), - 'FORUM_FOLDER_IMG_SRC' => $user->img($folder_image, $folder_alt, false, '', 'src'), 'FORUM_FOLDER_IMG_ALT' => isset($user->lang[$folder_alt]) ? $user->lang[$folder_alt] : '', 'FORUM_IMAGE' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="' . $user->lang[$folder_alt] . '" />' : '', 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', - 'LAST_POST_SUBJECT' => censor_text($last_post_subject), + 'LAST_POST_SUBJECT' => (!$row['forum_password'] && $auth->acl_get('f_read', $row['forum_id'])) ? censor_text($last_post_subject) : "", + 'LAST_POST_SUBJECT_TRUNCATED' => (!$row['forum_password'] && $auth->acl_get('f_read', $row['forum_id'])) ? $last_post_subject_truncated : "", 'LAST_POST_TIME' => $last_post_time, 'LAST_POSTER' => get_username_string('username', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']), 'LAST_POSTER_COLOUR' => get_username_string('colour', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']), @@ -493,32 +609,90 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'L_MODERATOR_STR' => $l_moderator, 'U_UNAPPROVED_TOPICS' => ($row['forum_id_unapproved_topics']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_topics&f=' . $row['forum_id_unapproved_topics']) : '', + 'U_UNAPPROVED_POSTS' => ($row['forum_id_unapproved_posts']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_posts&f=' . $row['forum_id_unapproved_posts']) : '', 'U_VIEWFORUM' => $u_viewforum, 'U_LAST_POSTER' => get_username_string('profile', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']), - 'U_LAST_POST' => $last_post_url) + 'U_LAST_POST' => $last_post_url, ); + /** + * Modify the template data block of the forum + * + * This event is triggered once per forum + * + * @event core.display_forums_modify_template_vars + * @var array forum_row Template data of the forum + * @var array row The data of the forum + * @var array subforums_row Template data of subforums + * @since 3.1.0-a1 + * @change 3.1.0-b5 Added var subforums_row + */ + $vars = array('forum_row', 'row', 'subforums_row'); + extract($phpbb_dispatcher->trigger_event('core.display_forums_modify_template_vars', compact($vars))); + + $template->assign_block_vars('forumrow', $forum_row); + // Assign subforums loop for style authors - foreach ($subforums_list as $subforum) - { - $template->assign_block_vars('forumrow.subforum', array( - 'U_SUBFORUM' => $subforum['link'], - 'SUBFORUM_NAME' => $subforum['name'], - 'S_UNREAD' => $subforum['unread']) - ); - } + $template->assign_block_vars_array('forumrow.subforum', $subforums_row); + + /** + * Modify and/or assign additional template data for the forum + * after forumrow loop has been assigned. This can be used + * to create additional forumrow subloops in extensions. + * + * This event is triggered once per forum + * + * @event core.display_forums_add_template_data + * @var array forum_row Template data of the forum + * @var array row The data of the forum + * @var array subforums_list The data of subforums + * @var array subforums_row Template data of subforums + * @var bool catless The flag indicating whether a forum has a parent category + * @since 3.1.0-b5 + */ + $vars = array( + 'forum_row', + 'row', + 'subforums_list', + 'subforums_row', + 'catless', + ); + extract($phpbb_dispatcher->trigger_event('core.display_forums_add_template_data', compact($vars))); $last_catless = $catless; } $template->assign_vars(array( - 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'hash=' . generate_link_hash('global') . '&f=' . $root_data['forum_id'] . '&mark=forums') : '', + 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'hash=' . generate_link_hash('global') . '&f=' . $root_data['forum_id'] . '&mark=forums&mark_time=' . time()) : '', 'S_HAS_SUBFORUM' => ($visible_forums) ? true : false, 'L_SUBFORUM' => ($visible_forums == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS'], 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPICS_UNAPPROVED'), + 'UNAPPROVED_POST_IMG' => $user->img('icon_topic_unapproved', 'POSTS_UNAPPROVED_FORUM'), )); + /** + * Event to perform additional actions after the forum list has been generated + * + * @event core.display_forums_after + * @var array active_forum_ary Array with forum data to display active topics + * @var bool display_moderators Flag indicating if we display forum moderators + * @var array forum_moderators Array with forum moderators list + * @var array forum_rows Data array of all forums we display + * @var bool return_moderators Flag indicating if moderators list should be returned + * @var array root_data Array with the root forum data + * @since 3.1.0-RC5 + */ + $vars = array( + 'active_forum_ary', + 'display_moderators', + 'forum_moderators', + 'forum_rows', + 'return_moderators', + 'root_data', + ); + extract($phpbb_dispatcher->trigger_event('core.display_forums_after', compact($vars))); + if ($return_moderators) { return array($active_forum_ary, $forum_moderators); @@ -568,6 +742,8 @@ function generate_forum_nav(&$forum_data) // Get forum parents $forum_parents = get_forum_parents($forum_data); + $microdata_attr = 'data-forum-id'; + // Build navigation links if (!empty($forum_parents)) { @@ -587,6 +763,7 @@ function generate_forum_nav(&$forum_data) 'S_IS_POST' => ($parent_type == FORUM_POST) ? true : false, 'FORUM_NAME' => $parent_name, 'FORUM_ID' => $parent_forum_id, + 'MICRODATA' => $microdata_attr . '="' . $parent_forum_id . '"', 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $parent_forum_id)) ); } @@ -598,6 +775,7 @@ function generate_forum_nav(&$forum_data) 'S_IS_POST' => ($forum_data['forum_type'] == FORUM_POST) ? true : false, 'FORUM_NAME' => $forum_data['forum_name'], 'FORUM_ID' => $forum_data['forum_id'], + 'MICRODATA' => $microdata_attr . '="' . $forum_data['forum_id'] . '"', 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_data['forum_id'])) ); @@ -655,48 +833,6 @@ function get_forum_parents(&$forum_data) } /** -* Generate topic pagination -*/ -function topic_generate_pagination($replies, $url) -{ - global $config, $user; - - // Make sure $per_page is a valid value - $per_page = ($config['posts_per_page'] <= 0) ? 1 : $config['posts_per_page']; - - if (($replies + 1) > $per_page) - { - $total_pages = ceil(($replies + 1) / $per_page); - $pagination = ''; - - $times = 1; - for ($j = 0; $j < $replies + 1; $j += $per_page) - { - $pagination .= '<a href="' . $url . ($j == 0 ? '' : '&start=' . $j) . '">' . $times . '</a>'; - if ($times == 1 && $total_pages > 5) - { - $pagination .= '<span class="page-dots"> ... </span>'; - - // Display the last three pages - $times = $total_pages - 3; - $j += ($total_pages - 4) * $per_page; - } - else if ($times < $total_pages) - { - $pagination .= '<span class="page-sep">' . $user->lang['COMMA_SEPARATOR'] . '</span>'; - } - $times++; - } - } - else - { - $pagination = ''; - } - - return $pagination; -} - -/** * Obtain list of moderators of each forum */ function get_moderators(&$forum_moderators, $forum_id = false) @@ -790,7 +926,7 @@ function gen_forum_auth_level($mode, $forum_id, $forum_status) ($auth->acl_get('f_post', $forum_id) && !$locked) ? $user->lang['RULES_POST_CAN'] : $user->lang['RULES_POST_CANNOT'], ($auth->acl_get('f_reply', $forum_id) && !$locked) ? $user->lang['RULES_REPLY_CAN'] : $user->lang['RULES_REPLY_CANNOT'], ($user->data['is_registered'] && $auth->acl_gets('f_edit', 'm_edit', $forum_id) && !$locked) ? $user->lang['RULES_EDIT_CAN'] : $user->lang['RULES_EDIT_CANNOT'], - ($user->data['is_registered'] && $auth->acl_gets('f_delete', 'm_delete', $forum_id) && !$locked) ? $user->lang['RULES_DELETE_CAN'] : $user->lang['RULES_DELETE_CANNOT'], + ($user->data['is_registered'] && ($auth->acl_gets('f_delete', 'm_delete', $forum_id) || $auth->acl_gets('f_softdelete', 'm_softdelete', $forum_id)) && !$locked) ? $user->lang['RULES_DELETE_CAN'] : $user->lang['RULES_DELETE_CANNOT'], ); if ($config['allow_attachments']) @@ -864,7 +1000,6 @@ function topic_status(&$topic_row, $replies, $unread_topic, &$folder_img, &$fold $folder_new .= '_locked'; } - $folder_img = ($unread_topic) ? $folder_new : $folder; $folder_alt = ($unread_topic) ? 'UNREAD_POSTS' : (($topic_row['topic_status'] == ITEM_LOCKED) ? 'TOPIC_LOCKED' : 'NO_UNREAD_POSTS'); @@ -883,20 +1018,35 @@ function topic_status(&$topic_row, $replies, $unread_topic, &$folder_img, &$fold /** * Assign/Build custom bbcodes for display in screens supporting using of bbcodes -* The custom bbcodes buttons will be placed within the template block 'custom_codes' +* The custom bbcodes buttons will be placed within the template block 'custom_tags' */ function display_custom_bbcodes() { - global $db, $template, $user; + global $db, $template, $user, $phpbb_dispatcher; // Start counting from 22 for the bbcode ids (every bbcode takes two ids - opening/closing) $num_predefined_bbcodes = 22; - $sql = 'SELECT bbcode_id, bbcode_tag, bbcode_helpline - FROM ' . BBCODES_TABLE . ' - WHERE display_on_posting = 1 - ORDER BY bbcode_tag'; - $result = $db->sql_query($sql); + $sql_ary = array( + 'SELECT' => 'b.bbcode_id, b.bbcode_tag, b.bbcode_helpline', + 'FROM' => array(BBCODES_TABLE => 'b'), + 'WHERE' => 'b.display_on_posting = 1', + 'ORDER_BY' => 'b.bbcode_tag', + ); + + /** + * Event to modify the SQL query before custom bbcode data is queried + * + * @event core.display_custom_bbcodes_modify_sql + * @var array sql_ary The SQL array to get the bbcode data + * @var int num_predefined_bbcodes The number of predefined core bbcodes + * (multiplied by factor of 2) + * @since 3.1.0-a3 + */ + $vars = array('sql_ary', 'num_predefined_bbcodes'); + extract($phpbb_dispatcher->trigger_event('core.display_custom_bbcodes_modify_sql', compact($vars))); + + $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary)); $i = 0; while ($row = $db->sql_fetchrow($result)) @@ -907,17 +1057,41 @@ function display_custom_bbcodes() $row['bbcode_helpline'] = $user->lang[strtoupper($row['bbcode_helpline'])]; } - $template->assign_block_vars('custom_tags', array( + $custom_tags = array( 'BBCODE_NAME' => "'[{$row['bbcode_tag']}]', '[/" . str_replace('=', '', $row['bbcode_tag']) . "]'", 'BBCODE_ID' => $num_predefined_bbcodes + ($i * 2), 'BBCODE_TAG' => $row['bbcode_tag'], + 'BBCODE_TAG_CLEAN' => str_replace('=', '-', $row['bbcode_tag']), 'BBCODE_HELPLINE' => $row['bbcode_helpline'], 'A_BBCODE_HELPLINE' => str_replace(array('&', '"', "'", '<', '>'), array('&', '"', "\'", '<', '>'), $row['bbcode_helpline']), - )); + ); + + /** + * Event to modify the template data block of a custom bbcode + * + * This event is triggered once per bbcode + * + * @event core.display_custom_bbcodes_modify_row + * @var array custom_tags Template data of the bbcode + * @var array row The data of the bbcode + * @since 3.1.0-a1 + */ + $vars = array('custom_tags', 'row'); + extract($phpbb_dispatcher->trigger_event('core.display_custom_bbcodes_modify_row', compact($vars))); + + $template->assign_block_vars('custom_tags', $custom_tags); $i++; } $db->sql_freeresult($result); + + /** + * Display custom bbcodes + * + * @event core.display_custom_bbcodes + * @since 3.1.0-a1 + */ + $phpbb_dispatcher->dispatch('core.display_custom_bbcodes'); } /** @@ -958,6 +1132,7 @@ function display_user_activity(&$userdata) { global $auth, $template, $db, $user; global $phpbb_root_path, $phpEx; + global $phpbb_container, $phpbb_dispatcher; // Do not display user activity for users having more than 5000 posts... if ($userdata['user_posts'] > 5000) @@ -967,75 +1142,79 @@ function display_user_activity(&$userdata) $forum_ary = array(); - // Do not include those forums the user is not having read access to... - $forum_read_ary = $auth->acl_getf('!f_read'); - - foreach ($forum_read_ary as $forum_id => $not_allowed) + $forum_read_ary = $auth->acl_getf('f_read'); + foreach ($forum_read_ary as $forum_id => $allowed) { - if ($not_allowed['f_read']) + if ($allowed['f_read']) { $forum_ary[] = (int) $forum_id; } } - $forum_ary = array_unique($forum_ary); - $forum_sql = (sizeof($forum_ary)) ? 'AND ' . $db->sql_in_set('forum_id', $forum_ary, true) : ''; - - $fid_m_approve = $auth->acl_getf('m_approve', true); - $sql_m_approve = (!empty($fid_m_approve)) ? 'OR ' . $db->sql_in_set('forum_id', array_keys($fid_m_approve)) : ''; - - // Obtain active forum - $sql = 'SELECT forum_id, COUNT(post_id) AS num_posts - FROM ' . POSTS_TABLE . ' - WHERE poster_id = ' . $userdata['user_id'] . " - AND post_postcount = 1 - AND (post_approved = 1 - $sql_m_approve) - $forum_sql - GROUP BY forum_id - ORDER BY num_posts DESC"; - $result = $db->sql_query_limit($sql, 1); - $active_f_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); + $forum_ary = array_diff($forum_ary, $user->get_passworded_forums()); - if (!empty($active_f_row)) + $active_f_row = $active_t_row = array(); + if (!empty($forum_ary)) { - $sql = 'SELECT forum_name - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $active_f_row['forum_id']; - $result = $db->sql_query($sql, 3600); - $active_f_row['forum_name'] = (string) $db->sql_fetchfield('forum_name'); + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + + // Obtain active forum + $sql = 'SELECT forum_id, COUNT(post_id) AS num_posts + FROM ' . POSTS_TABLE . ' + WHERE poster_id = ' . $userdata['user_id'] . ' + AND post_postcount = 1 + AND ' . $phpbb_content_visibility->get_forums_visibility_sql('post', $forum_ary) . ' + GROUP BY forum_id + ORDER BY num_posts DESC'; + $result = $db->sql_query_limit($sql, 1); + $active_f_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - } - // Obtain active topic - // We need to exclude passworded forums here so we do not leak the topic title - $forum_ary_topic = array_unique(array_merge($forum_ary, $user->get_passworded_forums())); - $forum_sql_topic = (!empty($forum_ary_topic)) ? 'AND ' . $db->sql_in_set('forum_id', $forum_ary_topic, true) : ''; - - $sql = 'SELECT topic_id, COUNT(post_id) AS num_posts - FROM ' . POSTS_TABLE . ' - WHERE poster_id = ' . $userdata['user_id'] . " - AND post_postcount = 1 - AND (post_approved = 1 - $sql_m_approve) - $forum_sql_topic - GROUP BY topic_id - ORDER BY num_posts DESC"; - $result = $db->sql_query_limit($sql, 1); - $active_t_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); + if (!empty($active_f_row)) + { + $sql = 'SELECT forum_name + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . $active_f_row['forum_id']; + $result = $db->sql_query($sql, 3600); + $active_f_row['forum_name'] = (string) $db->sql_fetchfield('forum_name'); + $db->sql_freeresult($result); + } - if (!empty($active_t_row)) - { - $sql = 'SELECT topic_title - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $active_t_row['topic_id']; - $result = $db->sql_query($sql); - $active_t_row['topic_title'] = (string) $db->sql_fetchfield('topic_title'); + // Obtain active topic + $sql = 'SELECT topic_id, COUNT(post_id) AS num_posts + FROM ' . POSTS_TABLE . ' + WHERE poster_id = ' . $userdata['user_id'] . ' + AND post_postcount = 1 + AND ' . $phpbb_content_visibility->get_forums_visibility_sql('post', $forum_ary) . ' + GROUP BY topic_id + ORDER BY num_posts DESC'; + $result = $db->sql_query_limit($sql, 1); + $active_t_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); + + if (!empty($active_t_row)) + { + $sql = 'SELECT topic_title + FROM ' . TOPICS_TABLE . ' + WHERE topic_id = ' . $active_t_row['topic_id']; + $result = $db->sql_query($sql); + $active_t_row['topic_title'] = (string) $db->sql_fetchfield('topic_title'); + $db->sql_freeresult($result); + } } + /** + * Alter list of forums and topics to display as active + * + * @event core.display_user_activity_modify_actives + * @var array userdata User's data + * @var array active_f_row List of active forums + * @var array active_t_row List of active posts + * @since 3.1.0-RC3 + */ + $vars = array('userdata', 'active_f_row', 'active_t_row'); + extract($phpbb_dispatcher->trigger_event('core.display_user_activity_modify_actives', compact($vars))); + $userdata['active_t_row'] = $active_t_row; $userdata['active_f_row'] = $active_f_row; @@ -1061,10 +1240,10 @@ function display_user_activity(&$userdata) $template->assign_vars(array( 'ACTIVE_FORUM' => $active_f_name, - 'ACTIVE_FORUM_POSTS' => ($active_f_count == 1) ? sprintf($user->lang['USER_POST'], 1) : sprintf($user->lang['USER_POSTS'], $active_f_count), + 'ACTIVE_FORUM_POSTS' => $user->lang('USER_POSTS', (int) $active_f_count), 'ACTIVE_FORUM_PCT' => sprintf($l_active_pct, $active_f_pct), 'ACTIVE_TOPIC' => censor_text($active_t_name), - 'ACTIVE_TOPIC_POSTS' => ($active_t_count == 1) ? sprintf($user->lang['USER_POST'], 1) : sprintf($user->lang['USER_POSTS'], $active_t_count), + 'ACTIVE_TOPIC_POSTS' => $user->lang('USER_POSTS', (int) $active_t_count), 'ACTIVE_TOPIC_PCT' => sprintf($l_active_pct, $active_t_pct), 'U_ACTIVE_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $active_f_id), 'U_ACTIVE_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $active_t_id), @@ -1078,6 +1257,7 @@ function display_user_activity(&$userdata) function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $notify_status = 'unset', $start = 0, $item_title = '') { global $template, $db, $user, $phpEx, $start, $phpbb_root_path; + global $request; $table_sql = ($mode == 'forum') ? FORUMS_WATCH_TABLE : TOPICS_WATCH_TABLE; $where_sql = ($mode == 'forum') ? 'forum_id' : 'topic_id'; @@ -1086,7 +1266,7 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $u_url .= ($mode == 'forum') ? '&f' : '&f=' . $forum_id . '&t'; $is_watching = 0; - // Is user watching this thread? + // Is user watching this topic? if ($user_id != ANONYMOUS) { $can_watch = true; @@ -1105,7 +1285,6 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, if (!is_null($notify_status) && $notify_status !== '') { - if (isset($_GET['unwatch'])) { $uid = request_var('uid', 0); @@ -1113,10 +1292,15 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, if ($token && check_link_hash($token, "{$mode}_$match_id") || confirm_box(true)) { - if ($uid != $user_id || $_GET['unwatch'] != $mode) + if ($uid != $user_id || $request->variable('unwatch', '', false, \phpbb\request\request_interface::GET) != $mode) { $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['ERR_UNWATCHING'] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>'); + $message = $user->lang['ERR_UNWATCHING']; + + if (!$request->is_ajax()) + { + $message .= '<br /><br />' . $user->lang('RETURN_' . strtoupper($mode), '<a href="' . $redirect_url . '">', '</a>'); + } trigger_error($message); } @@ -1126,8 +1310,12 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $db->sql_query($sql); $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['NOT_WATCHING_' . strtoupper($mode)] . '<br /><br />'; - $message .= sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>'); + $message = $user->lang['NOT_WATCHING_' . strtoupper($mode)]; + + if (!$request->is_ajax()) + { + $message .= '<br /><br />' . $user->lang('RETURN_' . strtoupper($mode), '<a href="' . $redirect_url . '">', '</a>'); + } meta_refresh(3, $redirect_url); trigger_error($message); } @@ -1178,10 +1366,15 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, if ($token && check_link_hash($token, "{$mode}_$match_id") || confirm_box(true)) { - if ($uid != $user_id || $_GET['watch'] != $mode) + if ($uid != $user_id || $request->variable('watch', '', false, \phpbb\request\request_interface::GET) != $mode) { $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['ERR_WATCHING'] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>'); + $message = $user->lang['ERR_WATCHING']; + + if (!$request->is_ajax()) + { + $message .= '<br /><br />' . $user->lang('RETURN_' . strtoupper($mode), '<a href="' . $redirect_url . '">', '</a>'); + } trigger_error($message); } @@ -1192,7 +1385,12 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $db->sql_query($sql); $redirect_url = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&start=$start"); - $message = $user->lang['ARE_WATCHING_' . strtoupper($mode)] . '<br /><br />' . sprintf($user->lang['RETURN_' . strtoupper($mode)], '<a href="' . $redirect_url . '">', '</a>'); + $message = $user->lang['ARE_WATCHING_' . strtoupper($mode)]; + + if (!$request->is_ajax()) + { + $message .= '<br /><br />' . $user->lang('RETURN_' . strtoupper($mode), '<a href="' . $redirect_url . '">', '</a>'); + } meta_refresh(3, $redirect_url); trigger_error($message); } @@ -1221,7 +1419,8 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, } else { - if ((isset($_GET['unwatch']) && $_GET['unwatch'] == $mode) || (isset($_GET['watch']) && $_GET['watch'] == $mode)) + if ((isset($_GET['unwatch']) && $request->variable('unwatch', '', false, \phpbb\request\request_interface::GET) == $mode) || + (isset($_GET['watch']) && $request->variable('watch', '', false, \phpbb\request\request_interface::GET) == $mode)) { login_box(); } @@ -1235,7 +1434,9 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, if ($can_watch) { $s_watching['link'] = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&" . (($is_watching) ? 'unwatch' : 'watch') . "=$mode&start=$start&hash=" . generate_link_hash("{$mode}_$match_id")); + $s_watching['link_toggle'] = append_sid("{$phpbb_root_path}view$mode.$phpEx", "$u_url=$match_id&" . ((!$is_watching) ? 'unwatch' : 'watch') . "=$mode&start=$start&hash=" . generate_link_hash("{$mode}_$match_id")); $s_watching['title'] = $user->lang[(($is_watching) ? 'STOP' : 'START') . '_WATCHING_' . strtoupper($mode)]; + $s_watching['title_toggle'] = $user->lang[((!$is_watching) ? 'STOP' : 'START') . '_WATCHING_' . strtoupper($mode)]; $s_watching['is_watching'] = $is_watching; } @@ -1245,17 +1446,34 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, /** * Get user rank title and image * -* @param int $user_rank the current stored users rank id +* @param array $user_data the current stored users data * @param int $user_posts the users number of posts -* @param string &$rank_title the rank title will be stored here after execution -* @param string &$rank_img the rank image as full img tag is stored here after execution -* @param string &$rank_img_src the rank image source is stored here after execution +* +* @return array An associative array containing the rank title (title), the rank image source (img) and the rank image as full img tag (img) * * Note: since we do not want to break backwards-compatibility, this function will only properly assign ranks to guests if you call it for them with user_posts == false */ -function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank_img_src) +function phpbb_get_user_rank($user_data, $user_posts) { - global $ranks, $config, $phpbb_root_path; + global $ranks, $config, $phpbb_root_path, $phpbb_path_helper, $phpbb_dispatcher; + + $user_rank_data = array( + 'title' => null, + 'img' => null, + 'img_src' => null, + ); + + /** + * Preparing a user's rank before displaying + * + * @event core.modify_user_rank + * @var array user_data Array with user's data + * @var int user_posts User_posts to change + * @since 3.1.0-RC4 + */ + + $vars = array('user_data', 'user_posts'); + extract($phpbb_dispatcher->trigger_event('core.modify_user_rank', compact($vars))); if (empty($ranks)) { @@ -1263,11 +1481,14 @@ function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank $ranks = $cache->obtain_ranks(); } - if (!empty($user_rank)) + if (!empty($user_data['user_rank'])) { - $rank_title = (isset($ranks['special'][$user_rank]['rank_title'])) ? $ranks['special'][$user_rank]['rank_title'] : ''; - $rank_img = (!empty($ranks['special'][$user_rank]['rank_image'])) ? '<img src="' . $phpbb_root_path . $config['ranks_path'] . '/' . $ranks['special'][$user_rank]['rank_image'] . '" alt="' . $ranks['special'][$user_rank]['rank_title'] . '" title="' . $ranks['special'][$user_rank]['rank_title'] . '" />' : ''; - $rank_img_src = (!empty($ranks['special'][$user_rank]['rank_image'])) ? $phpbb_root_path . $config['ranks_path'] . '/' . $ranks['special'][$user_rank]['rank_image'] : ''; + + $user_rank_data['title'] = (isset($ranks['special'][$user_data['user_rank']]['rank_title'])) ? $ranks['special'][$user_data['user_rank']]['rank_title'] : ''; + + $user_rank_data['img_src'] = (!empty($ranks['special'][$user_data['user_rank']]['rank_image'])) ? $phpbb_path_helper->update_web_root_path($phpbb_root_path . $config['ranks_path'] . '/' . $ranks['special'][$user_data['user_rank']]['rank_image']) : ''; + + $user_rank_data['img'] = (!empty($ranks['special'][$user_data['user_rank']]['rank_image'])) ? '<img src="' . $user_rank_data['img_src'] . '" alt="' . $ranks['special'][$user_data['user_rank']]['rank_title'] . '" title="' . $ranks['special'][$user_data['user_rank']]['rank_title'] . '" />' : ''; } else if ($user_posts !== false) { @@ -1277,67 +1498,176 @@ function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank { if ($user_posts >= $rank['rank_min']) { - $rank_title = $rank['rank_title']; - $rank_img = (!empty($rank['rank_image'])) ? '<img src="' . $phpbb_root_path . $config['ranks_path'] . '/' . $rank['rank_image'] . '" alt="' . $rank['rank_title'] . '" title="' . $rank['rank_title'] . '" />' : ''; - $rank_img_src = (!empty($rank['rank_image'])) ? $phpbb_root_path . $config['ranks_path'] . '/' . $rank['rank_image'] : ''; + $user_rank_data['title'] = $rank['rank_title']; + $user_rank_data['img_src'] = (!empty($rank['rank_image'])) ? $phpbb_path_helper->update_web_root_path($phpbb_root_path . $config['ranks_path'] . '/' . $rank['rank_image']) : ''; + $user_rank_data['img'] = (!empty($rank['rank_image'])) ? '<img src="' . $user_rank_data['img_src'] . '" alt="' . $rank['rank_title'] . '" title="' . $rank['rank_title'] . '" />' : ''; break; } } } } + + return $user_rank_data; } /** -* Get user avatar -* -* @param string $avatar Users assigned avatar name -* @param int $avatar_type Type of avatar -* @param string $avatar_width Width of users avatar -* @param string $avatar_height Height of users avatar -* @param string $alt Optional language string for alt tag within image, can be a language key or text -* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP -* -* @return string Avatar image +* Prepare profile data */ -function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false) +function phpbb_show_profile($data, $user_notes_enabled = false, $warn_user_enabled = false, $check_can_receive_pm = true) { - global $user, $config, $phpbb_root_path, $phpEx; + global $config, $auth, $user, $phpEx, $phpbb_root_path, $phpbb_dispatcher; + + $username = $data['username']; + $user_id = $data['user_id']; - if (empty($avatar) || !$avatar_type || (!$config['allow_avatar'] && !$ignore_config)) + $user_rank_data = phpbb_get_user_rank($data, (($user_id == ANONYMOUS) ? false : $data['user_posts'])); + + if ((!empty($data['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_user')) + { + $email = ($config['board_email_form'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=email&u=' . $user_id) : (($config['board_hide_emails'] && !$auth->acl_get('a_user')) ? '' : 'mailto:' . $data['user_email']); + } + else { - return ''; + $email = ''; } - $avatar_img = ''; + if ($config['load_onlinetrack']) + { + $update_time = $config['load_online_time'] * 60; + $online = (time() - $update_time < $data['session_time'] && ((isset($data['session_viewonline']) && $data['session_viewonline']) || $auth->acl_get('u_viewonline'))) ? true : false; + } + else + { + $online = false; + } - switch ($avatar_type) + if ($data['user_allow_viewonline'] || $auth->acl_get('u_viewonline')) { - case AVATAR_UPLOAD: - if (!$config['allow_avatar_upload'] && !$ignore_config) - { - return ''; - } - $avatar_img = $phpbb_root_path . "download/file.$phpEx?avatar="; - break; + $last_active = (!empty($data['session_time'])) ? $data['session_time'] : $data['user_lastvisit']; + } + else + { + $last_active = ''; + } + + $age = ''; + + if ($config['allow_birthdays'] && $data['user_birthday']) + { + list($bday_day, $bday_month, $bday_year) = array_map('intval', explode('-', $data['user_birthday'])); + + if ($bday_year) + { + $now = $user->create_datetime(); + $now = phpbb_gmgetdate($now->getTimestamp() + $now->getOffset()); - case AVATAR_GALLERY: - if (!$config['allow_avatar_local'] && !$ignore_config) + $diff = $now['mon'] - $bday_month; + if ($diff == 0) { - return ''; + $diff = ($now['mday'] - $bday_day < 0) ? 1 : 0; } - $avatar_img = $phpbb_root_path . $config['avatar_gallery_path'] . '/'; - break; - - case AVATAR_REMOTE: - if (!$config['allow_avatar_remote'] && !$ignore_config) + else { - return ''; + $diff = ($diff < 0) ? 1 : 0; } - break; + + $age = max(0, (int) ($now['year'] - $bday_year - $diff)); + } + } + + if (!function_exists('phpbb_get_banned_user_ids')) + { + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); } - $avatar_img .= $avatar; - return '<img src="' . (str_replace(' ', '%20', $avatar_img)) . '" width="' . $avatar_width . '" height="' . $avatar_height . '" alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />'; + // Can this user receive a Private Message? + $can_receive_pm = $check_can_receive_pm && ( + // They must be a "normal" user + $data['user_type'] != USER_IGNORE && + + // They must not be deactivated by the administrator + ($data['user_type'] != USER_INACTIVE || $data['user_inactive_reason'] != INACTIVE_MANUAL) && + + // They must be able to read PMs + sizeof($auth->acl_get_list($user_id, 'u_readpm')) && + + // They must not be permanently banned + !sizeof(phpbb_get_banned_user_ids($user_id, false)) && + + // They must allow users to contact via PM + (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $data['user_allow_pm']) + ); + + // Dump it out to the template + $template_data = array( + 'AGE' => $age, + 'RANK_TITLE' => $user_rank_data['title'], + 'JOINED' => $user->format_date($data['user_regdate']), + 'LAST_ACTIVE' => (empty($last_active)) ? ' - ' : $user->format_date($last_active), + 'POSTS' => ($data['user_posts']) ? $data['user_posts'] : 0, + 'WARNINGS' => isset($data['user_warnings']) ? $data['user_warnings'] : 0, + + 'USERNAME_FULL' => get_username_string('full', $user_id, $username, $data['user_colour']), + 'USERNAME' => get_username_string('username', $user_id, $username, $data['user_colour']), + 'USER_COLOR' => get_username_string('colour', $user_id, $username, $data['user_colour']), + 'U_VIEW_PROFILE' => get_username_string('profile', $user_id, $username, $data['user_colour']), + + 'A_USERNAME' => addslashes(get_username_string('username', $user_id, $username, $data['user_colour'])), + + 'AVATAR_IMG' => phpbb_get_user_avatar($data), + 'ONLINE_IMG' => (!$config['load_onlinetrack']) ? '' : (($online) ? $user->img('icon_user_online', 'ONLINE') : $user->img('icon_user_offline', 'OFFLINE')), + 'S_ONLINE' => ($config['load_onlinetrack'] && $online) ? true : false, + 'RANK_IMG' => $user_rank_data['img'], + 'RANK_IMG_SRC' => $user_rank_data['img_src'], + 'S_JABBER_ENABLED' => ($config['jab_enable']) ? true : false, + + 'S_WARNINGS' => ($auth->acl_getf_global('m_') || $auth->acl_get('m_warn')) ? true : false, + + 'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$user_id&sr=posts") : '', + 'U_NOTES' => ($user_notes_enabled && $auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $user_id, true, $user->session_id) : '', + 'U_WARN' => ($warn_user_enabled && $auth->acl_get('m_warn')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user&u=' . $user_id, true, $user->session_id) : '', + 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $user_id) : '', + 'U_EMAIL' => $email, + 'U_JABBER' => ($data['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=jabber&u=' . $user_id) : '', + + 'USER_JABBER' => ($config['jab_enable']) ? $data['user_jabber'] : '', + 'USER_JABBER_IMG' => ($config['jab_enable'] && $data['user_jabber']) ? $user->img('icon_contact_jabber', $data['user_jabber']) : '', + + 'L_SEND_EMAIL_USER' => $user->lang('SEND_EMAIL_USER', $username), + 'L_CONTACT_USER' => $user->lang('CONTACT_USER', $username), + 'L_VIEWING_PROFILE' => $user->lang('VIEWING_PROFILE', $username), + ); + + /** + * Preparing a user's data before displaying it in profile and memberlist + * + * @event core.memberlist_prepare_profile_data + * @var array data Array with user's data + * @var array template_data Template array with user's data + * @since 3.1.0-a1 + */ + $vars = array('data', 'template_data'); + extract($phpbb_dispatcher->trigger_event('core.memberlist_prepare_profile_data', compact($vars))); + + return $template_data; } -?>
\ No newline at end of file +function phpbb_sort_last_active($first, $second) +{ + global $id_cache, $sort_dir; + + $lesser_than = ($sort_dir === 'd') ? -1 : 1; + + if (isset($id_cache[$first]['group_leader']) && $id_cache[$first]['group_leader'] && (!isset($id_cache[$second]['group_leader']) || !$id_cache[$second]['group_leader'])) + { + return -1; + } + else if (isset($id_cache[$second]['group_leader']) && (!isset($id_cache[$first]['group_leader']) || !$id_cache[$first]['group_leader']) && $id_cache[$second]['group_leader']) + { + return 1; + } + else + { + return $lesser_than * (int) ($id_cache[$first]['last_visit'] - $id_cache[$second]['last_visit']); + } +} diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php new file mode 100644 index 0000000000..254e65ae3d --- /dev/null +++ b/phpBB/includes/functions_download.php @@ -0,0 +1,739 @@ +<?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. +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* A simplified function to deliver avatars +* The argument needs to be checked before calling this function. +*/ +function send_avatar_to_browser($file, $browser) +{ + global $config, $phpbb_root_path; + + $prefix = $config['avatar_salt'] . '_'; + $image_dir = $config['avatar_path']; + + // Adjust image_dir path (no trailing slash) + if (substr($image_dir, -1, 1) == '/' || substr($image_dir, -1, 1) == '\\') + { + $image_dir = substr($image_dir, 0, -1) . '/'; + } + $image_dir = str_replace(array('../', '..\\', './', '.\\'), '', $image_dir); + + if ($image_dir && ($image_dir[0] == '/' || $image_dir[0] == '\\')) + { + $image_dir = ''; + } + $file_path = $phpbb_root_path . $image_dir . '/' . $prefix . $file; + + if ((@file_exists($file_path) && @is_readable($file_path)) && !headers_sent()) + { + header('Cache-Control: public'); + + $image_data = @getimagesize($file_path); + header('Content-Type: ' . image_type_to_mime_type($image_data[2])); + + if ((strpos(strtolower($browser), 'msie') !== false) && !phpbb_is_greater_ie_version($browser, 7)) + { + header('Content-Disposition: attachment; ' . header_filename($file)); + + if (strpos(strtolower($browser), 'msie 6.0') !== false) + { + header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); + } + else + { + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT'); + } + } + else + { + header('Content-Disposition: inline; ' . header_filename($file)); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT'); + } + + $size = @filesize($file_path); + if ($size) + { + header("Content-Length: $size"); + } + + if (@readfile($file_path) == false) + { + $fp = @fopen($file_path, 'rb'); + + if ($fp !== false) + { + while (!feof($fp)) + { + echo fread($fp, 8192); + } + fclose($fp); + } + } + + flush(); + } + else + { + header('HTTP/1.0 404 Not Found'); + } +} + +/** +* Wraps an url into a simple html page. Used to display attachments in IE. +* this is a workaround for now; might be moved to template system later +* direct any complaints to 1 Microsoft Way, Redmond +*/ +function wrap_img_in_html($src, $title) +{ + echo '<!DOCTYPE html>'; + echo '<html>'; + echo '<head>'; + echo '<meta charset="utf-8">'; + echo '<title>' . $title . '</title>'; + echo '</head>'; + echo '<body>'; + echo '<div>'; + echo '<img src="' . $src . '" alt="' . $title . '" />'; + echo '</div>'; + echo '</body>'; + echo '</html>'; +} + +/** +* Send file to browser +*/ +function send_file_to_browser($attachment, $upload_dir, $category) +{ + global $user, $db, $config, $phpbb_root_path; + + $filename = $phpbb_root_path . $upload_dir . '/' . $attachment['physical_filename']; + + if (!@file_exists($filename)) + { + send_status_line(404, 'Not Found'); + trigger_error('ERROR_NO_ATTACHMENT'); + } + + // Correct the mime type - we force application/octetstream for all files, except images + // Please do not change this, it is a security precaution + if ($category != ATTACHMENT_CATEGORY_IMAGE || strpos($attachment['mimetype'], 'image') !== 0) + { + $attachment['mimetype'] = (strpos(strtolower($user->browser), 'msie') !== false || strpos(strtolower($user->browser), 'opera') !== false) ? 'application/octetstream' : 'application/octet-stream'; + } + + if (@ob_get_length()) + { + @ob_end_clean(); + } + + // Now send the File Contents to the Browser + $size = @filesize($filename); + + // To correctly display further errors we need to make sure we are using the correct headers for both (unsetting content-length may not work) + + // Check if headers already sent or not able to get the file contents. + if (headers_sent() || !@file_exists($filename) || !@is_readable($filename)) + { + // PHP track_errors setting On? + if (!empty($php_errormsg)) + { + send_status_line(500, 'Internal Server Error'); + trigger_error($user->lang['UNABLE_TO_DELIVER_FILE'] . '<br />' . sprintf($user->lang['TRACKED_PHP_ERROR'], $php_errormsg)); + } + + send_status_line(500, 'Internal Server Error'); + trigger_error('UNABLE_TO_DELIVER_FILE'); + } + + // Make sure the database record for the filesize is correct + if ($size > 0 && $size != $attachment['filesize']) + { + // Update database record + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' + SET filesize = ' . (int) $size . ' + WHERE attach_id = ' . (int) $attachment['attach_id']; + $db->sql_query($sql); + } + + // Now the tricky part... let's dance + header('Cache-Control: public'); + + // Send out the Headers. Do not set Content-Disposition to inline please, it is a security measure for users using the Internet Explorer. + header('Content-Type: ' . $attachment['mimetype']); + + if (phpbb_is_greater_ie_version($user->browser, 7)) + { + header('X-Content-Type-Options: nosniff'); + } + + if ($category == ATTACHMENT_CATEGORY_FLASH && request_var('view', 0) === 1) + { + // We use content-disposition: inline for flash files and view=1 to let it correctly play with flash player 10 - any other disposition will fail to play inline + header('Content-Disposition: inline'); + } + else + { + if (empty($user->browser) || ((strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7))) + { + header('Content-Disposition: attachment; ' . header_filename(htmlspecialchars_decode($attachment['real_filename']))); + if (empty($user->browser) || (strpos(strtolower($user->browser), 'msie 6.0') !== false)) + { + header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); + } + } + else + { + header('Content-Disposition: ' . ((strpos($attachment['mimetype'], 'image') === 0) ? 'inline' : 'attachment') . '; ' . header_filename(htmlspecialchars_decode($attachment['real_filename']))); + if (phpbb_is_greater_ie_version($user->browser, 7) && (strpos($attachment['mimetype'], 'image') !== 0)) + { + header('X-Download-Options: noopen'); + } + } + } + + // Close the db connection before sending the file etc. + file_gc(false); + + if (!set_modified_headers($attachment['filetime'], $user->browser)) + { + // We make sure those have to be enabled manually by defining a constant + // because of the potential disclosure of full attachment path + // in case support for features is absent in the webserver software. + if (defined('PHPBB_ENABLE_X_ACCEL_REDIRECT') && PHPBB_ENABLE_X_ACCEL_REDIRECT) + { + // X-Accel-Redirect - http://wiki.nginx.org/XSendfile + header('X-Accel-Redirect: ' . $user->page['root_script_path'] . $upload_dir . '/' . $attachment['physical_filename']); + exit; + } + else if (defined('PHPBB_ENABLE_X_SENDFILE') && PHPBB_ENABLE_X_SENDFILE && !phpbb_http_byte_range($size)) + { + // X-Sendfile - http://blog.lighttpd.net/articles/2006/07/02/x-sendfile + // Lighttpd's X-Sendfile does not support range requests as of 1.4.26 + // and always requires an absolute path. + header('X-Sendfile: ' . dirname(__FILE__) . "/../$upload_dir/{$attachment['physical_filename']}"); + exit; + } + + if ($size) + { + header("Content-Length: $size"); + } + + // Try to deliver in chunks + @set_time_limit(0); + + $fp = @fopen($filename, 'rb'); + + if ($fp !== false) + { + // Deliver file partially if requested + if ($range = phpbb_http_byte_range($size)) + { + fseek($fp, $range['byte_pos_start']); + + send_status_line(206, 'Partial Content'); + header('Content-Range: bytes ' . $range['byte_pos_start'] . '-' . $range['byte_pos_end'] . '/' . $range['bytes_total']); + header('Content-Length: ' . $range['bytes_requested']); + } + + while (!feof($fp)) + { + echo fread($fp, 8192); + } + fclose($fp); + } + else + { + @readfile($filename); + } + + flush(); + } + + exit; +} + +/** +* Get a browser friendly UTF-8 encoded filename +*/ +function header_filename($file) +{ + global $request; + + $user_agent = $request->header('User-Agent'); + + // There be dragons here. + // Not many follows the RFC... + if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Safari') !== false || strpos($user_agent, 'Konqueror') !== false) + { + return "filename=" . rawurlencode($file); + } + + // follow the RFC for extended filename for the rest + return "filename*=UTF-8''" . rawurlencode($file); +} + +/** +* Check if downloading item is allowed +*/ +function download_allowed() +{ + global $config, $user, $db, $request; + + if (!$config['secure_downloads']) + { + return true; + } + + $url = htmlspecialchars_decode($request->header('Referer')); + + if (!$url) + { + return ($config['secure_allow_empty_referer']) ? true : false; + } + + // Split URL into domain and script part + $url = @parse_url($url); + + if ($url === false) + { + return ($config['secure_allow_empty_referer']) ? true : false; + } + + $hostname = $url['host']; + unset($url); + + $allowed = ($config['secure_allow_deny']) ? false : true; + $iplist = array(); + + if (($ip_ary = @gethostbynamel($hostname)) !== false) + { + foreach ($ip_ary as $ip) + { + if ($ip) + { + $iplist[] = $ip; + } + } + } + + // Check for own server... + $server_name = $user->host; + + // Forcing server vars is the only way to specify/override the protocol + if ($config['force_server_vars'] || !$server_name) + { + $server_name = $config['server_name']; + } + + if (preg_match('#^.*?' . preg_quote($server_name, '#') . '.*?$#i', $hostname)) + { + $allowed = true; + } + + // Get IP's and Hostnames + if (!$allowed) + { + $sql = 'SELECT site_ip, site_hostname, ip_exclude + FROM ' . SITELIST_TABLE; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $site_ip = trim($row['site_ip']); + $site_hostname = trim($row['site_hostname']); + + if ($site_ip) + { + foreach ($iplist as $ip) + { + if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_ip, '#')) . '$#i', $ip)) + { + if ($row['ip_exclude']) + { + $allowed = ($config['secure_allow_deny']) ? false : true; + break 2; + } + else + { + $allowed = ($config['secure_allow_deny']) ? true : false; + } + } + } + } + + if ($site_hostname) + { + if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_hostname, '#')) . '$#i', $hostname)) + { + if ($row['ip_exclude']) + { + $allowed = ($config['secure_allow_deny']) ? false : true; + break; + } + else + { + $allowed = ($config['secure_allow_deny']) ? true : false; + } + } + } + } + $db->sql_freeresult($result); + } + + return $allowed; +} + +/** +* Check if the browser has the file already and set the appropriate headers- +* @returns false if a resend is in order. +*/ +function set_modified_headers($stamp, $browser) +{ + global $request; + + // let's see if we have to send the file at all + $last_load = $request->header('Modified-Since') ? strtotime(trim($request->header('Modified-Since'))) : false; + + if (strpos(strtolower($browser), 'msie 6.0') === false && !phpbb_is_greater_ie_version($browser, 7)) + { + if ($last_load !== false && $last_load >= $stamp) + { + send_status_line(304, 'Not Modified'); + // seems that we need those too ... browsers + header('Cache-Control: public'); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT'); + return true; + } + else + { + header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $stamp) . ' GMT'); + } + } + return false; +} + +/** +* Garbage Collection +* +* @param bool $exit Whether to die or not. +* +* @return null +*/ +function file_gc($exit = true) +{ + global $cache, $db; + + if (!empty($cache)) + { + $cache->unload(); + } + + $db->sql_close(); + + if ($exit) + { + exit; + } +} + +/** +* HTTP range support (RFC 2616 Section 14.35) +* +* Allows browsers to request partial file content +* in case a download has been interrupted. +* +* @param int $filesize the size of the file in bytes we are about to deliver +* +* @return mixed false if the whole file has to be delivered +* associative array on success +*/ +function phpbb_http_byte_range($filesize) +{ + // Only call find_range_request() once. + static $request_array; + + if (!$filesize) + { + return false; + } + + if (!isset($request_array)) + { + $request_array = phpbb_find_range_request(); + } + + return (empty($request_array)) ? false : phpbb_parse_range_request($request_array, $filesize); +} + +/** +* Searches for HTTP range request in request headers. +* +* @return mixed false if no request found +* array of strings containing the requested ranges otherwise +* e.g. array(0 => '0-0', 1 => '123-125') +*/ +function phpbb_find_range_request() +{ + global $request; + + $value = $request->header('Range'); + + // Make sure range request starts with "bytes=" + if (strpos($value, 'bytes=') === 0) + { + // Strip leading 'bytes=' + // Multiple ranges can be separated by a comma + return explode(',', substr($value, 6)); + } + + return false; +} + +/** +* Analyses a range request array. +* +* A range request can contain multiple ranges, +* we however only handle the first request and +* only support requests from a given byte to the end of the file. +* +* @param array $request_array array of strings containing the requested ranges +* @param int $filesize the full size of the file in bytes that has been requested +* +* @return mixed false if the whole file has to be delivered +* associative array on success +* byte_pos_start the first byte position, can be passed to fseek() +* byte_pos_end the last byte position +* bytes_requested the number of bytes requested +* bytes_total the full size of the file +*/ +function phpbb_parse_range_request($request_array, $filesize) +{ + // Go through all ranges + foreach ($request_array as $range_string) + { + $range = explode('-', trim($range_string)); + + // "-" is invalid, "0-0" however is valid and means the very first byte. + if (sizeof($range) != 2 || $range[0] === '' && $range[1] === '') + { + continue; + } + + if ($range[0] === '') + { + // Return last $range[1] bytes. + + if (!$range[1]) + { + continue; + } + + if ($range[1] >= $filesize) + { + return false; + } + + $first_byte_pos = $filesize - (int) $range[1]; + $last_byte_pos = $filesize - 1; + } + else + { + // Return bytes from $range[0] to $range[1] + + $first_byte_pos = (int) $range[0]; + $last_byte_pos = (int) $range[1]; + + if ($last_byte_pos && $last_byte_pos < $first_byte_pos) + { + // The requested range contains 0 bytes. + continue; + } + + if ($first_byte_pos >= $filesize) + { + // Requested range not satisfiable + return false; + } + + // Adjust last-byte-pos if it is absent or greater than the content. + if ($range[1] === '' || $last_byte_pos >= $filesize) + { + $last_byte_pos = $filesize - 1; + } + } + + // We currently do not support range requests that end before the end of the file + if ($last_byte_pos != $filesize - 1) + { + continue; + } + + return array( + 'byte_pos_start' => $first_byte_pos, + 'byte_pos_end' => $last_byte_pos, + 'bytes_requested' => $last_byte_pos - $first_byte_pos + 1, + 'bytes_total' => $filesize, + ); + } +} + +/** +* Increments the download count of all provided attachments +* +* @param \phpbb\db\driver\driver_interface $db The database object +* @param array|int $ids The attach_id of each attachment +* +* @return null +*/ +function phpbb_increment_downloads($db, $ids) +{ + if (!is_array($ids)) + { + $ids = array($ids); + } + + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' + SET download_count = download_count + 1 + WHERE ' . $db->sql_in_set('attach_id', $ids); + $db->sql_query($sql); +} + +/** +* Handles authentication when downloading attachments from a post or topic +* +* @param \phpbb\db\driver\driver_interface $db The database object +* @param \phpbb\auth\auth $auth The authentication object +* @param int $topic_id The id of the topic that we are downloading from +* +* @return null +*/ +function phpbb_download_handle_forum_auth($db, $auth, $topic_id) +{ + $sql_array = array( + 'SELECT' => 't.topic_visibility, t.forum_id, f.forum_name, f.forum_password, f.parent_id', + 'FROM' => array( + TOPICS_TABLE => 't', + FORUMS_TABLE => 'f', + ), + 'WHERE' => 't.topic_id = ' . (int) $topic_id . ' + AND t.forum_id = f.forum_id', + ); + + $sql = $db->sql_build_query('SELECT', $sql_array); + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row && $row['topic_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $row['forum_id'])) + { + send_status_line(404, 'Not Found'); + trigger_error('ERROR_NO_ATTACHMENT'); + } + else if ($row && $auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id'])) + { + if ($row['forum_password']) + { + // Do something else ... ? + login_forum_box($row); + } + } + else + { + send_status_line(403, 'Forbidden'); + trigger_error('SORRY_AUTH_VIEW_ATTACH'); + } +} + +/** +* Handles authentication when downloading attachments from PMs +* +* @param \phpbb\db\driver\driver_interface $db The database object +* @param \phpbb\auth\auth $auth The authentication object +* @param int $user_id The user id +* @param int $msg_id The id of the PM that we are downloading from +* +* @return null +*/ +function phpbb_download_handle_pm_auth($db, $auth, $user_id, $msg_id) +{ + if (!$auth->acl_get('u_pm_download')) + { + send_status_line(403, 'Forbidden'); + trigger_error('SORRY_AUTH_VIEW_ATTACH'); + } + + $allowed = phpbb_download_check_pm_auth($db, $user_id, $msg_id); + + if (!$allowed) + { + send_status_line(403, 'Forbidden'); + trigger_error('ERROR_NO_ATTACHMENT'); + } +} + +/** +* Checks whether a user can download from a particular PM +* +* @param \phpbb\db\driver\driver_interface $db The database object +* @param int $user_id The user id +* @param int $msg_id The id of the PM that we are downloading from +* +* @return bool Whether the user is allowed to download from that PM or not +*/ +function phpbb_download_check_pm_auth($db, $user_id, $msg_id) +{ + // Check if the attachment is within the users scope... + $sql = 'SELECT msg_id + FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE msg_id = ' . (int) $msg_id . ' + AND ( + user_id = ' . (int) $user_id . ' + OR author_id = ' . (int) $user_id . ' + )'; + $result = $db->sql_query_limit($sql, 1); + $allowed = (bool) $db->sql_fetchfield('msg_id'); + $db->sql_freeresult($result); + + return $allowed; +} + +/** +* Check if the browser is internet explorer version 7+ +* +* @param string $user_agent User agent HTTP header +* @param int $version IE version to check against +* +* @return bool true if internet explorer version is greater than $version +*/ +function phpbb_is_greater_ie_version($user_agent, $version) +{ + if (preg_match('/msie (\d+)/', strtolower($user_agent), $matches)) + { + $ie_version = (int) $matches[1]; + return ($ie_version > $version); + } + else + { + return false; + } +} diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index 21dd8bfebe..28cc603bdb 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -1,10 +1,13 @@ <?php /** * -* @package install -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -17,27 +20,6 @@ if (!defined('IN_PHPBB')) } /** -* Determine if we are able to load a specified PHP module and do so if possible -*/ -function can_load_dll($dll) -{ - // SQLite2 is a tricky thing, from 5.0.0 it requires PDO; if PDO is not loaded we must state that SQLite is unavailable - // as the installer doesn't understand that the extension has a prerequisite. - // - // On top of this sometimes the SQLite extension is compiled for a different version of PDO - // by some Linux distributions which causes phpBB to bomb out with a blank page. - // - // Net result we'll disable automatic inclusion of SQLite support - // - // See: r9618 and #56105 - if ($dll == 'sqlite') - { - return false; - } - return ((@ini_get('enable_dl') || strtolower(@ini_get('enable_dl')) == 'on') && (!@ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'off') && function_exists('dl') && @dl($dll . '.' . PHP_SHLIB_SUFFIX)) ? true : false; -} - -/** * Returns an array of available DBMS with some data, if a DBMS is specified it will only * return data for that DBMS and will load its extension if necessary. */ @@ -45,16 +27,6 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 { global $lang; $available_dbms = array( - 'firebird' => array( - 'LABEL' => 'FireBird', - 'SCHEMA' => 'firebird', - 'MODULE' => 'interbase', - 'DELIM' => ';;', - 'COMMENTS' => 'remove_remarks', - 'DRIVER' => 'firebird', - 'AVAILABLE' => true, - '2.0.x' => false, - ), // Note: php 5.5 alpha 2 deprecated mysql. // Keep mysqli before mysql in this list. 'mysqli' => array( @@ -62,8 +34,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mysql_41', 'MODULE' => 'mysqli', 'DELIM' => ';', - 'COMMENTS' => 'remove_remarks', - 'DRIVER' => 'mysqli', + 'DRIVER' => 'phpbb\db\driver\mysqli', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -72,8 +43,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mysql', 'MODULE' => 'mysql', 'DELIM' => ';', - 'COMMENTS' => 'remove_remarks', - 'DRIVER' => 'mysql', + 'DRIVER' => 'phpbb\db\driver\mysql', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -82,8 +52,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mssql', 'MODULE' => 'mssql', 'DELIM' => 'GO', - 'COMMENTS' => 'remove_comments', - 'DRIVER' => 'mssql', + 'DRIVER' => 'phpbb\db\driver\mssql', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -92,8 +61,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mssql', 'MODULE' => 'odbc', 'DELIM' => 'GO', - 'COMMENTS' => 'remove_comments', - 'DRIVER' => 'mssql_odbc', + 'DRIVER' => 'phpbb\db\driver\mssql_odbc', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -102,28 +70,25 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mssql', 'MODULE' => 'sqlsrv', 'DELIM' => 'GO', - 'COMMENTS' => 'remove_comments', - 'DRIVER' => 'mssqlnative', + 'DRIVER' => 'phpbb\db\driver\mssqlnative', 'AVAILABLE' => true, '2.0.x' => false, - ), + ), 'oracle' => array( 'LABEL' => 'Oracle', 'SCHEMA' => 'oracle', 'MODULE' => 'oci8', 'DELIM' => '/', - 'COMMENTS' => 'remove_comments', - 'DRIVER' => 'oracle', + 'DRIVER' => 'phpbb\db\driver\oracle', 'AVAILABLE' => true, '2.0.x' => false, ), 'postgres' => array( - 'LABEL' => 'PostgreSQL 7.x/8.x', + 'LABEL' => 'PostgreSQL 8.3+', 'SCHEMA' => 'postgres', 'MODULE' => 'pgsql', 'DELIM' => ';', - 'COMMENTS' => 'remove_comments', - 'DRIVER' => 'postgres', + 'DRIVER' => 'phpbb\db\driver\postgres', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -132,8 +97,16 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'sqlite', 'MODULE' => 'sqlite', 'DELIM' => ';', - 'COMMENTS' => 'remove_remarks', - 'DRIVER' => 'sqlite', + 'DRIVER' => 'phpbb\db\driver\sqlite', + 'AVAILABLE' => true, + '2.0.x' => false, + ), + 'sqlite3' => array( + 'LABEL' => 'SQLite3', + 'SCHEMA' => 'sqlite', + 'MODULE' => 'sqlite3', + 'DELIM' => ';', + 'DRIVER' => 'phpbb\db\driver\sqlite3', 'AVAILABLE' => true, '2.0.x' => false, ), @@ -171,18 +144,15 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 if (!@extension_loaded($dll)) { - if (!can_load_dll($dll)) + if ($return_unavailable) { - if ($return_unavailable) - { - $available_dbms[$db_name]['AVAILABLE'] = false; - } - else - { - unset($available_dbms[$db_name]); - } - continue; + $available_dbms[$db_name]['AVAILABLE'] = false; + } + else + { + unset($available_dbms[$db_name]); } + continue; } $any_db_support = true; } @@ -218,13 +188,7 @@ function dbms_select($default = '', $only_20x_options = false) */ function get_tables(&$db) { - if (!class_exists('phpbb_db_tools')) - { - global $phpbb_root_path, $phpEx; - require($phpbb_root_path . 'includes/db/db_tools.' . $phpEx); - } - - $db_tools = new phpbb_db_tools($db); + $db_tools = new \phpbb\db\tools($db); return $db_tools->sql_list_tables(); } @@ -241,26 +205,19 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, $dbms = $dbms_details['DRIVER']; - if ($load_dbal) - { - // Include the DB layer - include($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); - } - // Instantiate it and set return on error true - $sql_db = 'dbal_' . $dbms; - $db = new $sql_db(); + $db = new $dbms(); $db->sql_return_on_error(true); // Check that we actually have a database name before going any further..... - if ($dbms_details['DRIVER'] != 'sqlite' && $dbms_details['DRIVER'] != 'oracle' && $dbname === '') + if ($dbms_details['DRIVER'] != 'phpbb\db\driver\sqlite' && $dbms_details['DRIVER'] != 'phpbb\db\driver\sqlite3' && $dbms_details['DRIVER'] != 'phpbb\db\driver\oracle' && $dbname === '') { $error[] = $lang['INST_ERR_DB_NO_NAME']; return false; } // Make sure we don't have a daft user who thinks having the SQLite database in the forum directory is a good idea - if ($dbms_details['DRIVER'] == 'sqlite' && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0) + if (($dbms_details['DRIVER'] == 'phpbb\db\driver\sqlite' || $dbms_details['DRIVER'] == 'phpbb\db\driver\sqlite3') && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0) { $error[] = $lang['INST_ERR_DB_FORUM_PATH']; return false; @@ -269,8 +226,8 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, // Check the prefix length to ensure that index names are not too long and does not contain invalid characters switch ($dbms_details['DRIVER']) { - case 'mysql': - case 'mysqli': + case 'phpbb\db\driver\mysql': + case 'phpbb\db\driver\mysqli': if (strspn($table_prefix, '-./\\') !== 0) { $error[] = $lang['INST_ERR_PREFIX_INVALID']; @@ -279,22 +236,22 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, // no break; - case 'postgres': + case 'phpbb\db\driver\postgres': $prefix_length = 36; break; - case 'mssql': - case 'mssql_odbc': - case 'mssqlnative': + case 'phpbb\db\driver\mssql': + case 'phpbb\db\driver\mssql_odbc': + case 'phpbb\db\driver\mssqlnative': $prefix_length = 90; break; - case 'sqlite': + case 'phpbb\db\driver\sqlite': + case 'phpbb\db\driver\sqlite3': $prefix_length = 200; break; - case 'firebird': - case 'oracle': + case 'phpbb\db\driver\oracle': $prefix_length = 6; break; } @@ -332,102 +289,29 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, // Make sure that the user has selected a sensible DBAL for the DBMS actually installed switch ($dbms_details['DRIVER']) { - case 'mysqli': - if (version_compare(mysqli_get_server_info($db->db_connect_id), '4.1.3', '<')) + case 'phpbb\db\driver\mysqli': + if (version_compare(mysqli_get_server_info($db->get_db_connect_id()), '4.1.3', '<')) { $error[] = $lang['INST_ERR_DB_NO_MYSQLI']; } break; - case 'sqlite': + case 'phpbb\db\driver\sqlite': if (version_compare(sqlite_libversion(), '2.8.2', '<')) { $error[] = $lang['INST_ERR_DB_NO_SQLITE']; } break; - case 'firebird': - // check the version of FB, use some hackery if we can't get access to the server info - if ($db->service_handle !== false && function_exists('ibase_server_info')) - { - $val = @ibase_server_info($db->service_handle, IBASE_SVC_SERVER_VERSION); - preg_match('#V([\d.]+)#', $val, $match); - if ($match[1] < 2) - { - $error[] = $lang['INST_ERR_DB_NO_FIREBIRD']; - } - $db_info = @ibase_db_info($db->service_handle, $dbname, IBASE_STS_HDR_PAGES); - - preg_match('/^\\s*Page size\\s*(\\d+)/m', $db_info, $regs); - $page_size = intval($regs[1]); - if ($page_size < 8192) - { - $error[] = $lang['INST_ERR_DB_NO_FIREBIRD_PS']; - } - } - else + case 'phpbb\db\driver\sqlite3': + $version = \SQLite3::version(); + if (version_compare($version['versionString'], '3.6.15', '<')) { - $sql = "SELECT * - FROM RDB$FUNCTIONS - WHERE RDB$SYSTEM_FLAG IS NULL - AND RDB$FUNCTION_NAME = 'CHAR_LENGTH'"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // if its a UDF, its too old - if ($row) - { - $error[] = $lang['INST_ERR_DB_NO_FIREBIRD']; - } - else - { - $sql = 'SELECT 1 FROM RDB$DATABASE - WHERE BIN_AND(10, 1) = 0'; - $result = $db->sql_query($sql); - if (!$result) // This can only fail if BIN_AND is not defined - { - $error[] = $lang['INST_ERR_DB_NO_FIREBIRD']; - } - $db->sql_freeresult($result); - } - - // Setup the stuff for our random table - $char_array = array_merge(range('A', 'Z'), range('0', '9')); - $char_len = mt_rand(7, 9); - $char_array_len = sizeof($char_array) - 1; - - $final = ''; - - for ($i = 0; $i < $char_len; $i++) - { - $final .= $char_array[mt_rand(0, $char_array_len)]; - } - - // Create some random table - $sql = 'CREATE TABLE ' . $final . " ( - FIELD1 VARCHAR(255) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE, - FIELD2 INTEGER DEFAULT 0 NOT NULL);"; - $db->sql_query($sql); - - // Create an index that should fail if the page size is less than 8192 - $sql = 'CREATE INDEX ' . $final . ' ON ' . $final . '(FIELD1, FIELD2);'; - $db->sql_query($sql); - - if (ibase_errmsg() !== false) - { - $error[] = $lang['INST_ERR_DB_NO_FIREBIRD_PS']; - } - else - { - // Kill the old table - $db->sql_query('DROP TABLE ' . $final . ';'); - } - unset($final); + $error[] = $lang['INST_ERR_DB_NO_SQLITE3']; } break; - case 'oracle': + case 'phpbb\db\driver\oracle': if ($unicode_check) { $sql = "SELECT * @@ -449,7 +333,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, } break; - case 'postgres': + case 'phpbb\db\driver\postgres': if ($unicode_check) { $sql = "SHOW server_encoding;"; @@ -475,19 +359,6 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, } /** -* Removes comments from schema files -* -* @deprecated Use phpbb_remove_comments() instead. -*/ -function remove_remarks(&$sql) -{ - // Remove # style comments - $sql = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $sql)); - - // Return by reference -} - -/** * Removes "/* style" as well as "# style" comments from $input. * * @param string $input Input string @@ -496,17 +367,11 @@ function remove_remarks(&$sql) */ function phpbb_remove_comments($input) { - if (!function_exists('remove_comments')) - { - global $phpbb_root_path, $phpEx; - require($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } - - // Remove /* */ comments - remove_comments($input); + // Remove /* */ comments (http://ostermiller.org/findcomment.html) + $input = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $input); // Remove # style comments - remove_remarks($input); + $input = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $input)); return $input; } @@ -551,19 +416,18 @@ function adjust_language_keys_callback($matches) * * @param array $data Array containing the database connection information * @param string $dbms The name of the DBAL class to use -* @param array $load_extensions Array of additional extensions that should be loaded * @param bool $debug If the debug constants should be enabled by default or not +* @param bool $debug_container If the container should be compiled on +* every page load or not * @param bool $debug_test If the DEBUG_TEST constant should be added * NOTE: Only for use within the testing framework * * @return string The output to write to the file */ -function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = false, $debug_test = false) +function phpbb_create_config_file_data($data, $dbms, $debug = false, $debug_container = false, $debug_test = false) { - $load_extensions = implode(',', $load_extensions); - $config_data = "<?php\n"; - $config_data .= "// phpBB 3.0.x auto-generated configuration file\n// Do not change anything in this file!\n"; + $config_data .= "// phpBB 3.1.x auto-generated configuration file\n// Do not change anything in this file!\n"; $config_data_array = array( 'dbms' => $dbms, @@ -573,8 +437,10 @@ function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = 'dbuser' => $data['dbuser'], 'dbpasswd' => htmlspecialchars_decode($data['dbpasswd']), 'table_prefix' => $data['table_prefix'], - 'acm_type' => 'file', - 'load_extensions' => $load_extensions, + + 'phpbb_adm_relative_path' => 'adm/', + + 'acm_type' => 'phpbb\cache\driver\file', ); foreach ($config_data_array as $key => $value) @@ -583,16 +449,24 @@ function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = } $config_data .= "\n@define('PHPBB_INSTALLED', true);\n"; + $config_data .= "// @define('PHPBB_DISPLAY_LOAD_TIME', true);\n"; if ($debug) { $config_data .= "@define('DEBUG', true);\n"; - $config_data .= "@define('DEBUG_EXTRA', true);\n"; } else { $config_data .= "// @define('DEBUG', true);\n"; - $config_data .= "// @define('DEBUG_EXTRA', true);\n"; + } + + if ($debug_container) + { + $config_data .= "@define('DEBUG_CONTAINER', true);\n"; + } + else + { + $config_data .= "// @define('DEBUG_CONTAINER', true);\n"; } if ($debug_test) @@ -603,4 +477,69 @@ function phpbb_create_config_file_data($data, $dbms, $load_extensions, $debug = return $config_data; } -?>
\ No newline at end of file +/** +* Check whether a file should be ignored on update +* +* We ignore new files in some circumstances: +* 1. The file is a language file, but the language is not installed +* 2. The file is a style file, but the style is not installed +* 3. The file is a style language file, but the language is not installed +* +* @param string $phpbb_root_path phpBB root path +* @param string $file File including path from phpbb root +* @return bool Should we ignore the new file or add it to the board? +*/ +function phpbb_ignore_new_file_on_update($phpbb_root_path, $file) +{ + $ignore_new_file = false; + + // We ignore new files in some circumstances: + // 1. The file is a language file, but the language is not installed + if (!$ignore_new_file && strpos($file, 'language/') === 0) + { + list($language_dir, $language_iso) = explode('/', $file); + $ignore_new_file = !file_exists($phpbb_root_path . $language_dir . '/' . $language_iso); + } + + // 2. The file is a style file, but the style is not installed + if (!$ignore_new_file && strpos($file, 'styles/') === 0) + { + list($styles_dir, $style_name) = explode('/', $file); + $ignore_new_file = !file_exists($phpbb_root_path . $styles_dir . '/' . $style_name); + } + + // 3. The file is a style language file, but the language is not installed + if (!$ignore_new_file && strpos($file, 'styles/') === 0) + { + $dirs = explode('/', $file); + if (sizeof($dirs) >= 5) + { + list($styles_dir, $style_name, $template_component, $language_iso) = explode('/', $file); + if ($template_component == 'theme' && $language_iso !== 'images') + { + $ignore_new_file = !file_exists($phpbb_root_path . 'language/' . $language_iso); + } + } + } + + return $ignore_new_file; +} + +/** +* Check whether phpBB is installed. +* +* @param string $phpbb_root_path Path to the phpBB board root. +* @param string $php_ext PHP file extension. +* +* @return bool Returns true if phpBB is installed. +*/ +function phpbb_check_installation_exists($phpbb_root_path, $php_ext) +{ + // Try opening config file + if (file_exists($phpbb_root_path . 'config.' . $php_ext)) + { + include($phpbb_root_path . 'config.' . $php_ext); + } + + return defined('PHPBB_INSTALLED'); +} diff --git a/phpBB/includes/functions_jabber.php b/phpBB/includes/functions_jabber.php index 2054124a4e..bd2e9e93ac 100644 --- a/phpBB/includes/functions_jabber.php +++ b/phpBB/includes/functions_jabber.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2007 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -25,8 +28,6 @@ if (!defined('IN_PHPBB')) * @author Florian Schmitz (floele) * * Only slightly modified by Acyd Burn -* -* @package phpBB3 */ class jabber { @@ -69,7 +70,7 @@ class jabber } $this->password = $password; - $this->use_ssl = ($use_ssl && $this->can_use_ssl()) ? true : false; + $this->use_ssl = ($use_ssl && self::can_use_ssl()) ? true : false; // Change port if we use SSL if ($this->port == 5222 && $this->use_ssl) @@ -84,7 +85,7 @@ class jabber /** * Able to use the SSL functionality? */ - function can_use_ssl() + static public function can_use_ssl() { // Will not work with PHP >= 5.2.1 or < 5.2.3RC2 until timeout problem with ssl hasn't been fixed (http://bugs.php.net/41236) return ((version_compare(PHP_VERSION, '5.2.1', '<') || version_compare(PHP_VERSION, '5.2.3RC2', '>=')) && @extension_loaded('openssl')) ? true : false; @@ -93,7 +94,7 @@ class jabber /** * Able to use TLS? */ - function can_use_tls() + static public function can_use_tls() { if (!@extension_loaded('openssl') || !function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('socket_set_blocking') || !function_exists('stream_get_wrappers')) { @@ -443,7 +444,7 @@ class jabber } // Let's use TLS if SSL is not enabled and we can actually use it - if (!$this->session['ssl'] && $this->can_use_tls() && $this->can_use_ssl() && isset($xml['stream:features'][0]['#']['starttls'])) + if (!$this->session['ssl'] && self::can_use_tls() && self::can_use_ssl() && isset($xml['stream:features'][0]['#']['starttls'])) { $this->add_to_log('Switching to TLS.'); $this->send("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n"); @@ -869,5 +870,3 @@ class jabber return $children; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_mcp.php b/phpBB/includes/functions_mcp.php new file mode 100644 index 0000000000..ed96dcf338 --- /dev/null +++ b/phpBB/includes/functions_mcp.php @@ -0,0 +1,725 @@ +<?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. +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Functions used to generate additional URL paramters +*/ +function phpbb_module__url($mode, &$module_row) +{ + return phpbb_extra_url(); +} + +function phpbb_module_notes_url($mode, &$module_row) +{ + if ($mode == 'front') + { + return ''; + } + + global $user_id; + return ($user_id) ? "&u=$user_id" : ''; +} + +function phpbb_module_warn_url($mode, &$module_row) +{ + if ($mode == 'front' || $mode == 'list') + { + global $forum_id; + + return ($forum_id) ? "&f=$forum_id" : ''; + } + + if ($mode == 'warn_post') + { + global $forum_id, $post_id; + + $url_extra = ($forum_id) ? "&f=$forum_id" : ''; + $url_extra .= ($post_id) ? "&p=$post_id" : ''; + + return $url_extra; + } + else + { + global $user_id; + + return ($user_id) ? "&u=$user_id" : ''; + } +} + +function phpbb_module_main_url($mode, &$module_row) +{ + return phpbb_extra_url(); +} + +function phpbb_module_logs_url($mode, &$module_row) +{ + return phpbb_extra_url(); +} + +function phpbb_module_ban_url($mode, &$module_row) +{ + return phpbb_extra_url(); +} + +function phpbb_module_queue_url($mode, &$module_row) +{ + return phpbb_extra_url(); +} + +function phpbb_module_reports_url($mode, &$module_row) +{ + return phpbb_extra_url(); +} + +function phpbb_extra_url() +{ + global $forum_id, $topic_id, $post_id, $report_id, $user_id; + + $url_extra = ''; + $url_extra .= ($forum_id) ? "&f=$forum_id" : ''; + $url_extra .= ($topic_id) ? "&t=$topic_id" : ''; + $url_extra .= ($post_id) ? "&p=$post_id" : ''; + $url_extra .= ($user_id) ? "&u=$user_id" : ''; + $url_extra .= ($report_id) ? "&r=$report_id" : ''; + + return $url_extra; +} + +/** +* Get simple topic data +*/ +function phpbb_get_topic_data($topic_ids, $acl_list = false, $read_tracking = false) +{ + global $auth, $db, $config, $user; + static $rowset = array(); + + $topics = array(); + + if (!sizeof($topic_ids)) + { + return array(); + } + + // cache might not contain read tracking info, so we can't use it if read + // tracking information is requested + if (!$read_tracking) + { + $cache_topic_ids = array_intersect($topic_ids, array_keys($rowset)); + $topic_ids = array_diff($topic_ids, array_keys($rowset)); + } + else + { + $cache_topic_ids = array(); + } + + if (sizeof($topic_ids)) + { + $sql_array = array( + 'SELECT' => 't.*, f.*', + + 'FROM' => array( + TOPICS_TABLE => 't', + ), + + 'LEFT_JOIN' => array( + array( + 'FROM' => array(FORUMS_TABLE => 'f'), + 'ON' => 'f.forum_id = t.forum_id' + ) + ), + + 'WHERE' => $db->sql_in_set('t.topic_id', $topic_ids) + ); + + if ($read_tracking && $config['load_db_lastread']) + { + $sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as forum_mark_time'; + + $sql_array['LEFT_JOIN'][] = array( + 'FROM' => array(TOPICS_TRACK_TABLE => 'tt'), + 'ON' => 'tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id' + ); + + $sql_array['LEFT_JOIN'][] = array( + 'FROM' => array(FORUMS_TRACK_TABLE => 'ft'), + 'ON' => 'ft.user_id = ' . $user->data['user_id'] . ' AND t.forum_id = ft.forum_id' + ); + } + + $sql = $db->sql_build_query('SELECT', $sql_array); + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $rowset[$row['topic_id']] = $row; + + if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id'])) + { + continue; + } + + $topics[$row['topic_id']] = $row; + } + $db->sql_freeresult($result); + } + + foreach ($cache_topic_ids as $id) + { + if (!$acl_list || $auth->acl_gets($acl_list, $rowset[$id]['forum_id'])) + { + $topics[$id] = $rowset[$id]; + } + } + + return $topics; +} + +/** +* Get simple post data +*/ +function phpbb_get_post_data($post_ids, $acl_list = false, $read_tracking = false) +{ + global $db, $auth, $config, $user; + + $rowset = array(); + + if (!sizeof($post_ids)) + { + return array(); + } + + $sql_array = array( + 'SELECT' => 'p.*, u.*, t.*, f.*', + + 'FROM' => array( + USERS_TABLE => 'u', + POSTS_TABLE => 'p', + TOPICS_TABLE => 't', + ), + + 'LEFT_JOIN' => array( + array( + 'FROM' => array(FORUMS_TABLE => 'f'), + 'ON' => 'f.forum_id = t.forum_id' + ) + ), + + 'WHERE' => $db->sql_in_set('p.post_id', $post_ids) . ' + AND u.user_id = p.poster_id + AND t.topic_id = p.topic_id', + ); + + if ($read_tracking && $config['load_db_lastread']) + { + $sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as forum_mark_time'; + + $sql_array['LEFT_JOIN'][] = array( + 'FROM' => array(TOPICS_TRACK_TABLE => 'tt'), + 'ON' => 'tt.user_id = ' . $user->data['user_id'] . ' AND t.topic_id = tt.topic_id' + ); + + $sql_array['LEFT_JOIN'][] = array( + 'FROM' => array(FORUMS_TRACK_TABLE => 'ft'), + 'ON' => 'ft.user_id = ' . $user->data['user_id'] . ' AND t.forum_id = ft.forum_id' + ); + } + + $sql = $db->sql_build_query('SELECT', $sql_array); + $result = $db->sql_query($sql); + unset($sql_array); + + while ($row = $db->sql_fetchrow($result)) + { + if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id'])) + { + continue; + } + + if ($row['post_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $row['forum_id'])) + { + // Moderators without the permission to approve post should at least not see them. ;) + continue; + } + + $rowset[$row['post_id']] = $row; + } + $db->sql_freeresult($result); + + return $rowset; +} + +/** +* Get simple forum data +*/ +function phpbb_get_forum_data($forum_id, $acl_list = 'f_list', $read_tracking = false) +{ + global $auth, $db, $user, $config, $phpbb_container; + + $rowset = array(); + + if (!is_array($forum_id)) + { + $forum_id = array($forum_id); + } + + if (!sizeof($forum_id)) + { + return array(); + } + + if ($read_tracking && $config['load_db_lastread']) + { + $read_tracking_join = ' LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.user_id = ' . $user->data['user_id'] . ' + AND ft.forum_id = f.forum_id)'; + $read_tracking_select = ', ft.mark_time'; + } + else + { + $read_tracking_join = $read_tracking_select = ''; + } + + $sql = "SELECT f.* $read_tracking_select + FROM " . FORUMS_TABLE . " f$read_tracking_join + WHERE " . $db->sql_in_set('f.forum_id', $forum_id); + $result = $db->sql_query($sql); + + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + + while ($row = $db->sql_fetchrow($result)) + { + if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id'])) + { + continue; + } + + $row['forum_topics_approved'] = $phpbb_content_visibility->get_count('forum_topics', $row, $row['forum_id']); + + $rowset[$row['forum_id']] = $row; + } + $db->sql_freeresult($result); + + return $rowset; +} + +/** +* Get simple pm data +*/ +function phpbb_get_pm_data($pm_ids) +{ + global $db; + + $rowset = array(); + + if (!sizeof($pm_ids)) + { + return array(); + } + + $sql_array = array( + 'SELECT' => 'p.*, u.*', + + 'FROM' => array( + USERS_TABLE => 'u', + PRIVMSGS_TABLE => 'p', + ), + + 'WHERE' => $db->sql_in_set('p.msg_id', $pm_ids) . ' + AND u.user_id = p.author_id', + ); + + $sql = $db->sql_build_query('SELECT', $sql_array); + $result = $db->sql_query($sql); + unset($sql_array); + + while ($row = $db->sql_fetchrow($result)) + { + $rowset[$row['msg_id']] = $row; + } + $db->sql_freeresult($result); + + return $rowset; +} + +/** +* sorting in mcp +* +* @param string $where_sql should either be WHERE (default if ommited) or end with AND or OR +* +* $mode reports and reports_closed: the $where parameters uses aliases p for posts table and r for report table +* $mode unapproved_posts: the $where parameters uses aliases p for posts table and t for topic table +*/ +function phpbb_mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by_sql, &$sort_order_sql, &$total, $forum_id = 0, $topic_id = 0, $where_sql = 'WHERE') +{ + global $db, $user, $auth, $template, $phpbb_dispatcher; + + $sort_days = request_var('st', 0); + $min_time = ($sort_days) ? time() - ($sort_days * 86400) : 0; + + switch ($mode) + { + case 'viewforum': + $type = 'topics'; + $default_key = 't'; + $default_dir = 'd'; + + $sql = 'SELECT COUNT(topic_id) AS total + FROM ' . TOPICS_TABLE . " + $where_sql forum_id = $forum_id + AND topic_type NOT IN (" . POST_ANNOUNCE . ', ' . POST_GLOBAL . ") + AND topic_last_post_time >= $min_time"; + + if (!$auth->acl_get('m_approve', $forum_id)) + { + $sql .= 'AND topic_visibility = ' . ITEM_APPROVED; + } + break; + + case 'viewtopic': + $type = 'posts'; + $default_key = 't'; + $default_dir = 'a'; + + $sql = 'SELECT COUNT(post_id) AS total + FROM ' . POSTS_TABLE . " + $where_sql topic_id = $topic_id + AND post_time >= $min_time"; + + if (!$auth->acl_get('m_approve', $forum_id)) + { + $sql .= 'AND post_visibility = ' . ITEM_APPROVED; + } + break; + + case 'unapproved_posts': + case 'deleted_posts': + $visibility_const = ($mode == 'unapproved_posts') ? array(ITEM_UNAPPROVED, ITEM_REAPPROVE) : ITEM_DELETED; + $type = 'posts'; + $default_key = 't'; + $default_dir = 'd'; + $where_sql .= ($topic_id) ? ' p.topic_id = ' . $topic_id . ' AND' : ''; + + $sql = 'SELECT COUNT(p.post_id) AS total + FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t + $where_sql " . $db->sql_in_set('p.forum_id', ($forum_id) ? array($forum_id) : array_intersect(get_forum_list('f_read'), get_forum_list('m_approve'))) . ' + AND ' . $db->sql_in_set('p.post_visibility', $visibility_const) .' + AND t.topic_id = p.topic_id + AND t.topic_visibility <> p.post_visibility'; + + if ($min_time) + { + $sql .= ' AND post_time >= ' . $min_time; + } + break; + + case 'unapproved_topics': + case 'deleted_topics': + $visibility_const = ($mode == 'unapproved_topics') ? array(ITEM_UNAPPROVED, ITEM_REAPPROVE) : ITEM_DELETED; + $type = 'topics'; + $default_key = 't'; + $default_dir = 'd'; + + $sql = 'SELECT COUNT(topic_id) AS total + FROM ' . TOPICS_TABLE . " + $where_sql " . $db->sql_in_set('forum_id', ($forum_id) ? array($forum_id) : array_intersect(get_forum_list('f_read'), get_forum_list('m_approve'))) . ' + AND ' . $db->sql_in_set('topic_visibility', $visibility_const); + + if ($min_time) + { + $sql .= ' AND topic_time >= ' . $min_time; + } + break; + + case 'pm_reports': + case 'pm_reports_closed': + case 'reports': + case 'reports_closed': + $pm = (strpos($mode, 'pm_') === 0) ? true : false; + + $type = ($pm) ? 'pm_reports' : 'reports'; + $default_key = 't'; + $default_dir = 'd'; + $limit_time_sql = ($min_time) ? "AND r.report_time >= $min_time" : ''; + + if ($topic_id) + { + $where_sql .= ' p.topic_id = ' . $topic_id . ' AND '; + } + else if ($forum_id) + { + $where_sql .= ' p.forum_id = ' . $forum_id . ' AND '; + } + else if (!$pm) + { + $where_sql .= ' ' . $db->sql_in_set('p.forum_id', get_forum_list(array('!f_read', '!m_report')), true, true) . ' AND '; + } + + if ($mode == 'reports' || $mode == 'pm_reports') + { + $where_sql .= ' r.report_closed = 0 AND '; + } + else + { + $where_sql .= ' r.report_closed = 1 AND '; + } + + if ($pm) + { + $sql = 'SELECT COUNT(r.report_id) AS total + FROM ' . REPORTS_TABLE . ' r, ' . PRIVMSGS_TABLE . " p + $where_sql r.post_id = 0 + AND p.msg_id = r.pm_id + $limit_time_sql"; + } + else + { + $sql = 'SELECT COUNT(r.report_id) AS total + FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . " p + $where_sql r.pm_id = 0 + AND p.post_id = r.post_id + $limit_time_sql"; + } + break; + + case 'viewlogs': + $type = 'logs'; + $default_key = 't'; + $default_dir = 'd'; + + $sql = 'SELECT COUNT(log_id) AS total + FROM ' . LOG_TABLE . " + $where_sql " . $db->sql_in_set('forum_id', ($forum_id) ? array($forum_id) : array_intersect(get_forum_list('f_read'), get_forum_list('m_'))) . ' + AND log_time >= ' . $min_time . ' + AND log_type = ' . LOG_MOD; + break; + } + + $sort_key = request_var('sk', $default_key); + $sort_dir = request_var('sd', $default_dir); + $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); + + switch ($type) + { + case 'topics': + $limit_days = array(0 => $user->lang['ALL_TOPICS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); + $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 'tt' => $user->lang['TOPIC_TIME'], 'r' => $user->lang['REPLIES'], 's' => $user->lang['SUBJECT'], 'v' => $user->lang['VIEWS']); + + $sort_by_sql = array('a' => 't.topic_first_poster_name', 't' => array('t.topic_last_post_time', 't.topic_last_post_id'), 'tt' => 't.topic_time', 'r' => (($auth->acl_get('m_approve', $forum_id)) ? 't.topic_posts_approved + t.topic_posts_unapproved + t.topic_posts_softdeleted' : 't.topic_posts_approved'), 's' => 't.topic_title', 'v' => 't.topic_views'); + $limit_time_sql = ($min_time) ? "AND t.topic_last_post_time >= $min_time" : ''; + break; + + case 'posts': + $limit_days = array(0 => $user->lang['ALL_POSTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); + $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); + $sort_by_sql = array('a' => 'u.username_clean', 't' => array('p.post_time', 'p.post_id'), 's' => 'p.post_subject'); + $limit_time_sql = ($min_time) ? "AND p.post_time >= $min_time" : ''; + break; + + case 'reports': + $limit_days = array(0 => $user->lang['ALL_REPORTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); + $sort_by_text = array('a' => $user->lang['AUTHOR'], 'r' => $user->lang['REPORTER'], 'p' => $user->lang['POST_TIME'], 't' => $user->lang['REPORT_TIME'], 's' => $user->lang['SUBJECT']); + $sort_by_sql = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => array('p.post_time', 'p.post_id'), 't' => 'r.report_time', 's' => 'p.post_subject'); + break; + + case 'pm_reports': + $limit_days = array(0 => $user->lang['ALL_REPORTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); + $sort_by_text = array('a' => $user->lang['AUTHOR'], 'r' => $user->lang['REPORTER'], 'p' => $user->lang['POST_TIME'], 't' => $user->lang['REPORT_TIME'], 's' => $user->lang['SUBJECT']); + $sort_by_sql = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => 'p.message_time', 't' => 'r.report_time', 's' => 'p.message_subject'); + break; + + case 'logs': + $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); + $sort_by_text = array('u' => $user->lang['SORT_USERNAME'], 't' => $user->lang['SORT_DATE'], 'i' => $user->lang['SORT_IP'], 'o' => $user->lang['SORT_ACTION']); + + $sort_by_sql = array('u' => 'u.username_clean', 't' => 'l.log_time', 'i' => 'l.log_ip', 'o' => 'l.log_operation'); + $limit_time_sql = ($min_time) ? "AND l.log_time >= $min_time" : ''; + break; + } + + // Default total to -1 to allow editing by the event + $total = -1; + + /** + * This event allows you to control the SQL query used to get the total number + * of reports the user can access. + * + * This total is used for the pagination and for displaying the total number + * of reports to the user + * + * + * @event core.mcp_sorting_query_before + * @var string sql The current SQL search string + * @var string mode An id related to the module(s) the user is viewing + * @var string type Which kind of information is this being used for displaying. Posts, topics, etc... + * @var int forum_id The forum id of the posts the user is trying to access, if not 0 + * @var int topic_id The topic id of the posts the user is trying to access, if not 0 + * @var int sort_days The max age of the oldest report to be shown, in days + * @var string sort_key The way the user has decided to sort the data. + * The valid values must be in the keys of the sort_by_* variables + * @var string sort_dir Either 'd' for "DESC" or 'a' for 'ASC' in the SQL query + * @var int limit_days The possible max ages of the oldest report for the user to choose, in days. + * @var array sort_by_sql SQL text (values) for the possible names of the ways of sorting data (keys). + * @var array sort_by_text Language text (values) for the possible names of the ways of sorting data (keys). + * @var int min_time Integer with the minimum post time that the user is searching for + * @var int limit_time_sql Time limiting options used in the SQL query. + * @var int total The total number of reports that exist. Only set if you want to override the result + * @var string where_sql Extra information included in the WHERE clause. It must end with "WHERE" or "AND" or "OR". + * Set to "WHERE" and set total above -1 to override the total value + * @since 3.1.4-RC1 + */ + $vars = array( + 'sql', + 'mode', + 'type', + 'forum_id', + 'topic_id', + 'sort_days', + 'sort_key', + 'sort_dir', + 'limit_days', + 'sort_by_sql', + 'sort_by_text', + 'min_time', + 'limit_time_sql', + 'total', + 'where_sql', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_sorting_query_before', compact($vars))); + + if (!isset($sort_by_sql[$sort_key])) + { + $sort_key = $default_key; + } + + $direction = ($sort_dir == 'd') ? 'DESC' : 'ASC'; + + if (is_array($sort_by_sql[$sort_key])) + { + $sort_order_sql = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction; + } + else + { + $sort_order_sql = $sort_by_sql[$sort_key] . ' ' . $direction; + } + + $s_limit_days = $s_sort_key = $s_sort_dir = $sort_url = ''; + gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $sort_url); + + $template->assign_vars(array( + 'S_SELECT_SORT_DIR' => $s_sort_dir, + 'S_SELECT_SORT_KEY' => $s_sort_key, + 'S_SELECT_SORT_DAYS' => $s_limit_days) + ); + + if (($sort_days && $mode != 'viewlogs') || in_array($mode, array('reports', 'unapproved_topics', 'unapproved_posts', 'deleted_topics', 'deleted_posts')) || $where_sql != 'WHERE') + { + $result = $db->sql_query($sql); + $total = (int) $db->sql_fetchfield('total'); + $db->sql_freeresult($result); + } + else if ($total < -1) + { + $total = -1; + } +} + +/** +* Validate ids +* +* @param array &$ids The relevant ids to check +* @param string $table The table to find the ids in +* @param string $sql_id The ids relevant column name +* @param array $acl_list A list of permissions the user need to have +* @param mixed $singe_forum Limit to one forum id (int) or the first forum found (true) +* +* @return mixed False if no ids were able to be retrieved, true if at least one id left. +* Additionally, this value can be the forum_id assigned if $single_forum was set. +* Therefore checking the result for with !== false is the best method. +*/ +function phpbb_check_ids(&$ids, $table, $sql_id, $acl_list = false, $single_forum = false) +{ + global $db, $auth; + + if (!is_array($ids) || empty($ids)) + { + return false; + } + + $sql = "SELECT $sql_id, forum_id FROM $table + WHERE " . $db->sql_in_set($sql_id, $ids); + $result = $db->sql_query($sql); + + $ids = array(); + $forum_id = false; + + while ($row = $db->sql_fetchrow($result)) + { + if ($acl_list && $row['forum_id'] && !$auth->acl_gets($acl_list, $row['forum_id'])) + { + continue; + } + + if ($acl_list && !$row['forum_id'] && !$auth->acl_getf_global($acl_list)) + { + continue; + } + + // Limit forum? If not, just assign the id. + if ($single_forum === false) + { + $ids[] = $row[$sql_id]; + continue; + } + + // Limit forum to a specific forum id? + // This can get really tricky, because we do not want to create a failure on global topics. :) + if ($row['forum_id']) + { + if ($single_forum !== true && $row['forum_id'] == (int) $single_forum) + { + $forum_id = (int) $single_forum; + } + else if ($forum_id === false) + { + $forum_id = $row['forum_id']; + } + + if ($row['forum_id'] == $forum_id) + { + $ids[] = $row[$sql_id]; + } + } + else + { + // Always add a global topic + $ids[] = $row[$sql_id]; + } + } + $db->sql_freeresult($result); + + if (!sizeof($ids)) + { + return false; + } + + // If forum id is false and ids populated we may have only global announcements selected (returning 0 because of (int) $forum_id) + + return ($single_forum === false) ? true : (int) $forum_id; +} diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index db2dea33e8..fbac3e6f1d 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,18 +21,18 @@ if (!defined('IN_PHPBB')) /** * Messenger -* @package phpBB3 */ class messenger { - var $vars, $msg, $extra_headers, $replyto, $from, $subject; + var $msg, $extra_headers, $replyto, $from, $subject; var $addresses = array(); var $mail_priority = MAIL_NORMAL_PRIORITY; var $use_queue = true; - var $tpl_obj = NULL; - var $tpl_msg = array(); + /** @var \phpbb\template\template */ + protected $template; + var $eol = "\n"; /** @@ -53,11 +56,29 @@ class messenger function reset() { $this->addresses = $this->extra_headers = array(); - $this->vars = $this->msg = $this->replyto = $this->from = ''; + $this->msg = $this->replyto = $this->from = ''; $this->mail_priority = MAIL_NORMAL_PRIORITY; } /** + * Set addresses for to/im as available + * + * @param array $user User row + */ + function set_addresses($user) + { + if (isset($user['user_email']) && $user['user_email']) + { + $this->to($user['user_email'], (isset($user['username']) ? $user['username'] : '')); + } + + if (isset($user['user_jabber']) && $user['user_jabber']) + { + $this->im($user['user_jabber'], (isset($user['username']) ? $user['username'] : '')); + } + } + + /** * Sets an email address to send to */ function to($address, $realname = '') @@ -191,7 +212,9 @@ class messenger */ function template($template_file, $template_lang = '', $template_path = '') { - global $config, $phpbb_root_path, $user; + global $config, $phpbb_root_path, $phpEx, $user, $phpbb_extension_manager; + + $this->setup_template(); if (!trim($template_file)) { @@ -202,42 +225,46 @@ class messenger { // fall back to board default language if the user's language is // missing $template_file. If this does not exist either, - // $tpl->set_custom_template will do a trigger_error + // $this->template->set_filenames will do a trigger_error $template_lang = basename($config['default_lang']); } - // tpl_msg now holds a template object we can use to parse the template file - if (!isset($this->tpl_msg[$template_lang . $template_file])) + if ($template_path) { - $this->tpl_msg[$template_lang . $template_file] = new template(); - $tpl = &$this->tpl_msg[$template_lang . $template_file]; + $template_paths = array( + $template_path, + ); + } + else + { + $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; + $template_path .= $template_lang . '/email'; - $fallback_template_path = false; + $template_paths = array( + $template_path, + ); - if (!$template_path) + // we can only specify default language fallback when the path is not a custom one for which we + // do not know the default language alternative + if ($template_lang !== basename($config['default_lang'])) { - $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $template_path .= $template_lang . '/email'; + $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; + $fallback_template_path .= basename($config['default_lang']) . '/email'; - // we can only specify default language fallback when the path is not a custom one for which we - // do not know the default language alternative - if ($template_lang !== basename($config['default_lang'])) - { - $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $fallback_template_path .= basename($config['default_lang']) . '/email'; - } + $template_paths[] = $fallback_template_path; } - - $tpl->set_custom_template($template_path, $template_lang . '_email', $fallback_template_path); - - $tpl->set_filenames(array( - 'body' => $template_file . '.txt', - )); } - $this->tpl_obj = &$this->tpl_msg[$template_lang . $template_file]; - $this->vars = &$this->tpl_obj->_rootref; - $this->tpl_msg = ''; + $this->set_template_paths(array( + array( + 'name' => $template_lang . '_email', + 'ext_path' => 'language/' . $template_lang . '/email' + ), + ), $template_paths); + + $this->template->set_filenames(array( + 'body' => $template_file . '.txt', + )); return true; } @@ -247,22 +274,16 @@ class messenger */ function assign_vars($vars) { - if (!is_object($this->tpl_obj)) - { - return; - } + $this->setup_template(); - $this->tpl_obj->assign_vars($vars); + $this->template->assign_vars($vars); } function assign_block_vars($blockname, $vars) { - if (!is_object($this->tpl_obj)) - { - return; - } + $this->setup_template(); - $this->tpl_obj->assign_block_vars($blockname, $vars); + $this->template->assign_block_vars($blockname, $vars); } /** @@ -273,29 +294,14 @@ class messenger global $config, $user; // We add some standard variables we always use, no need to specify them always - if (!isset($this->vars['U_BOARD'])) - { - $this->assign_vars(array( - 'U_BOARD' => generate_board_url(), - )); - } - - if (!isset($this->vars['EMAIL_SIG'])) - { - $this->assign_vars(array( - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])), - )); - } - - if (!isset($this->vars['SITENAME'])) - { - $this->assign_vars(array( - 'SITENAME' => htmlspecialchars_decode($config['sitename']), - )); - } + $this->assign_vars(array( + 'U_BOARD' => generate_board_url(), + 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])), + 'SITENAME' => htmlspecialchars_decode($config['sitename']), + )); // Parse message through template - $this->msg = trim($this->tpl_obj->assign_display('body')); + $this->msg = trim($this->template->assign_display('body')); // Because we use \n for newlines in the body message we need to fix line encoding errors for those admins who uploaded email template files in the wrong encoding $this->msg = str_replace("\r\n", "\n", $this->msg); @@ -349,7 +355,7 @@ class messenger */ function error($type, $msg) { - global $user, $phpEx, $phpbb_root_path, $config; + global $user, $phpEx, $phpbb_root_path, $config, $request; // Session doesn't exist, create it if (!isset($user->session_id) || $user->session_id === '') @@ -357,7 +363,7 @@ class messenger $user->session_begin(); } - $calling_page = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']; + $calling_page = htmlspecialchars_decode($request->server('PHP_SELF')); $message = ''; switch ($type) @@ -396,17 +402,9 @@ class messenger */ function generate_message_id() { - global $config; + global $config, $request; - $domain = 'phpbb.generated'; - if ($config['server_name']) - { - $domain = $config['server_name']; - } - else if (!empty($_SERVER['SERVER_NAME'])) - { - $domain = $_SERVER['SERVER_NAME']; - } + $domain = ($config['server_name']) ?: $request->server('SERVER_NAME', 'phpbb.generated'); return md5(unique_id(time())) . '@' . $domain; } @@ -486,14 +484,17 @@ class messenger $use_queue = true; } + $contact_name = htmlspecialchars_decode($config['board_contact_name']); + $board_contact = (($contact_name !== '') ? '"' . mail_encode($contact_name) . '" ' : '') . '<' . $config['board_contact'] . '>'; + if (empty($this->replyto)) { - $this->replyto = '<' . $config['board_contact'] . '>'; + $this->replyto = $board_contact; } if (empty($this->from)) { - $this->from = '<' . $config['board_contact'] . '>'; + $this->from = $board_contact; } $encode_eol = ($config['smtp_delivery']) ? "\r\n" : $this->eol; @@ -509,7 +510,7 @@ class messenger foreach ($address_ary as $which_ary) { - $$type .= (($$type != '') ? ', ' : '') . (($which_ary['name'] != '') ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']); + ${$type} .= ((${$type} != '') ? ', ' : '') . (($which_ary['name'] != '') ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']); } } @@ -622,11 +623,35 @@ class messenger unset($addresses); return true; } + + /** + * Setup template engine + */ + protected function setup_template() + { + global $config, $phpbb_path_helper, $user, $phpbb_extension_manager; + + if ($this->template instanceof \phpbb\template\template) + { + return; + } + + $this->template = new \phpbb\template\twig\twig($phpbb_path_helper, $config, $user, new \phpbb\template\context(), $phpbb_extension_manager); + } + + /** + * Set template paths to load + */ + protected function set_template_paths($path_name, $paths) + { + $this->setup_template(); + + $this->template->set_custom_style($path_name, $paths); + } } /** * handling email and jabber queue -* @package phpBB3 */ class queue { @@ -670,64 +695,6 @@ class queue } /** - * Obtains exclusive lock on queue cache file. - * Returns resource representing the lock - */ - function lock() - { - // For systems that can't have two processes opening - // one file for writing simultaneously - if (file_exists($this->cache_file . '.lock')) - { - $mode = 'rb'; - } - else - { - $mode = 'wb'; - } - - $lock_fp = @fopen($this->cache_file . '.lock', $mode); - - if ($mode == 'wb') - { - if (!$lock_fp) - { - // Two processes may attempt to create lock file at the same time. - // Have the losing process try opening the lock file again for reading - // on the assumption that the winning process created it - $mode = 'rb'; - $lock_fp = @fopen($this->cache_file . '.lock', $mode); - } - else - { - // Only need to set mode when the lock file is written - @chmod($this->cache_file . '.lock', 0666); - } - } - - if ($lock_fp) - { - @flock($lock_fp, LOCK_EX); - } - - return $lock_fp; - } - - /** - * Releases lock on queue cache file, using resource obtained from lock() - */ - function unlock($lock_fp) - { - // lock() will return null if opening lock file, and thus locking, failed. - // Accept null values here so that client code does not need to check them - if ($lock_fp) - { - @flock($lock_fp, LOCK_UN); - fclose($lock_fp); - } - } - - /** * Process queue * Using lock file */ @@ -735,7 +702,8 @@ class queue { global $db, $config, $phpEx, $phpbb_root_path, $user; - $lock_fp = $this->lock(); + $lock = new \phpbb\lock\flock($this->cache_file); + $lock->acquire(); // avoid races, check file existence once $have_cache_file = file_exists($this->cache_file); @@ -746,7 +714,7 @@ class queue set_config('last_queue_run', time(), true); } - $this->unlock($lock_fp); + $lock->release(); return; } @@ -802,20 +770,22 @@ class queue if (!$this->jabber->connect()) { - messenger::error('JABBER', $user->lang['ERR_JAB_CONNECT']); + $messenger = new messenger(); + $messenger->error('JABBER', $user->lang['ERR_JAB_CONNECT']); continue 2; } if (!$this->jabber->login()) { - messenger::error('JABBER', $user->lang['ERR_JAB_AUTH']); + $messenger = new messenger(); + $messenger->error('JABBER', $user->lang['ERR_JAB_AUTH']); continue 2; } break; default: - $this->unlock($lock_fp); + $lock->release(); return; } @@ -841,7 +811,8 @@ class queue if (!$result) { - messenger::error('EMAIL', $err_msg); + $messenger = new messenger(); + $messenger->error('EMAIL', $err_msg); continue 2; } break; @@ -851,7 +822,8 @@ class queue { if ($this->jabber->send_message($address, $msg, $subject) === false) { - messenger::error('JABBER', $this->jabber->get_log()); + $messenger = new messenger(); + $messenger->error('JABBER', $this->jabber->get_log()); continue 3; } } @@ -891,7 +863,7 @@ class queue } } - $this->unlock($lock_fp); + $lock->release(); } /** @@ -904,7 +876,8 @@ class queue return; } - $lock_fp = $this->lock(); + $lock = new \phpbb\lock\flock($this->cache_file); + $lock->acquire(); if (file_exists($this->cache_file)) { @@ -931,7 +904,7 @@ class queue phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); } - $this->unlock($lock_fp); + $lock->release(); } } @@ -1020,12 +993,12 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false) $smtp->add_backtrace('Connecting to ' . $config['smtp_host'] . ':' . $config['smtp_port']); // Ok we have error checked as much as we can to this point let's get on it already. - if (!class_exists('phpbb_error_collector')) + if (!class_exists('\phpbb\error_collector')) { global $phpbb_root_path, $phpEx; include($phpbb_root_path . 'includes/error_collector.' . $phpEx); } - $collector = new phpbb_error_collector; + $collector = new \phpbb\error_collector; $collector->install(); $smtp->socket = fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 20); $collector->uninstall(); @@ -1158,12 +1131,12 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false) * SMTP Class * Auth Mechanisms originally taken from the AUTH Modules found within the PHP Extension and Application Repository (PEAR) * See docs/AUTHORS for more details -* @package phpBB3 */ class smtp_class { var $server_response = ''; var $socket = 0; + protected $socket_tls = false; var $responses = array(); var $commands = array(); var $numeric_response_code = 0; @@ -1314,30 +1287,29 @@ class smtp_class } } - // Try EHLO first - $this->server_send("EHLO {$local_host}"); - if ($err_msg = $this->server_parse('250', __LINE__)) + $hello_result = $this->hello($local_host); + if (!is_null($hello_result)) { - // a 503 response code means that we're already authenticated - if ($this->numeric_response_code == 503) - { - return false; - } - - // If EHLO fails, we try HELO - $this->server_send("HELO {$local_host}"); - if ($err_msg = $this->server_parse('250', __LINE__)) - { - return ($this->numeric_response_code == 503) ? false : $err_msg; - } + return $hello_result; } - foreach ($this->responses as $response) + // SMTP STARTTLS (RFC 3207) + if (!$this->socket_tls) { - $response = explode(' ', $response); - $response_code = $response[0]; - unset($response[0]); - $this->commands[$response_code] = implode(' ', $response); + $this->socket_tls = $this->starttls(); + + if ($this->socket_tls) + { + // Switched to TLS + // RFC 3207: "The client MUST discard any knowledge obtained from the server, [...]" + // So say hello again + $hello_result = $this->hello($local_host); + + if (!is_null($hello_result)) + { + return $hello_result; + } + } } // If we are not authenticated yet, something might be wrong if no username and passwd passed @@ -1384,6 +1356,79 @@ class smtp_class } /** + * SMTP EHLO/HELO + * + * @return mixed Null if the authentication process is supposed to continue + * False if already authenticated + * Error message (string) otherwise + */ + protected function hello($hostname) + { + // Try EHLO first + $this->server_send("EHLO $hostname"); + if ($err_msg = $this->server_parse('250', __LINE__)) + { + // a 503 response code means that we're already authenticated + if ($this->numeric_response_code == 503) + { + return false; + } + + // If EHLO fails, we try HELO + $this->server_send("HELO $hostname"); + if ($err_msg = $this->server_parse('250', __LINE__)) + { + return ($this->numeric_response_code == 503) ? false : $err_msg; + } + } + + foreach ($this->responses as $response) + { + $response = explode(' ', $response); + $response_code = $response[0]; + unset($response[0]); + $this->commands[$response_code] = implode(' ', $response); + } + } + + /** + * SMTP STARTTLS (RFC 3207) + * + * @return bool Returns true if TLS was started + * Otherwise false + */ + protected function starttls() + { + if (!function_exists('stream_socket_enable_crypto')) + { + return false; + } + + if (!isset($this->commands['STARTTLS'])) + { + return false; + } + + $this->server_send('STARTTLS'); + + if ($err_msg = $this->server_parse('220', __LINE__)) + { + return false; + } + + $result = false; + $stream_meta = stream_get_meta_data($this->socket); + + if (socket_set_blocking($this->socket, 1)) + { + $result = stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); + socket_set_blocking($this->socket, (int) $stream_meta['blocked']); + } + + return $result; + } + + /** * Pop before smtp authentication */ function pop_before_smtp($hostname, $username, $password) @@ -1666,12 +1711,12 @@ function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg) // Reference: http://bugs.php.net/bug.php?id=15841 $headers = implode($eol, $headers); - if (!class_exists('phpbb_error_collector')) + if (!class_exists('\phpbb\error_collector')) { include($phpbb_root_path . 'includes/error_collector.' . $phpEx); } - $collector = new phpbb_error_collector; + $collector = new \phpbb\error_collector; $collector->install(); // On some PHP Versions mail() *may* fail if there are newlines within the subject. @@ -1684,5 +1729,3 @@ function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg) return $result; } - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_module.php b/phpBB/includes/functions_module.php index 0cc2425b28..fe9bcdb9d1 100644 --- a/phpBB/includes/functions_module.php +++ b/phpBB/includes/functions_module.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,7 +21,6 @@ if (!defined('IN_PHPBB')) /** * Class handling all types of 'plugins' (a future term) -* @package phpBB3 */ class p_master { @@ -81,7 +83,7 @@ class p_master function list_modules($p_class) { global $auth, $db, $user, $cache; - global $config, $phpbb_root_path, $phpEx; + global $config, $phpbb_root_path, $phpEx, $phpbb_dispatcher; // Sanitise for future path use, it's escaped as appropriate for queries $this->p_class = str_replace(array('.', '/', '\\'), '', basename($p_class)); @@ -126,10 +128,19 @@ class p_master // Clean up module cache array to only let survive modules the user can access $right_id = false; + + $hide_categories = array(); foreach ($this->module_cache['modules'] as $key => $row) { + // When the module has no mode (category) we check whether it has visible children + // before listing it as well. + if (!$row['module_mode']) + { + $hide_categories[(int) $row['module_id']] = $key; + } + // Not allowed to view module? - if (!$this->module_auth($row['module_auth'])) + if (!$this->module_auth_self($row['module_auth'])) { unset($this->module_cache['modules'][$key]); continue; @@ -162,6 +173,22 @@ class p_master $right_id = $row['right_id']; continue; } + + if ($row['module_mode']) + { + // The parent category has a visible child + // So remove it and all its parents from the hide array + unset($hide_categories[(int) $row['parent_id']]); + foreach ($this->module_cache['parents'][$row['module_id']] as $module_id => $row_id) + { + unset($hide_categories[$module_id]); + } + } + } + + foreach ($hide_categories as $module_id => $row_id) + { + unset($this->module_cache['modules'][$row_id]); } // Re-index (this is needed, else we are not able to array_slice later) @@ -221,13 +248,27 @@ class p_master // We need to prefix the functions to not create a naming conflict // Function for building 'url_extra' - $url_func = '_module_' . $row['module_basename'] . '_url'; + $short_name = $this->get_short_name($row['module_basename']); + + $url_func = 'phpbb_module_' . $short_name . '_url'; + if (!function_exists($url_func)) + { + $url_func = '_module_' . $short_name . '_url'; + } // Function for building the language name - $lang_func = '_module_' . $row['module_basename'] . '_lang'; + $lang_func = 'phpbb_module_' . $short_name . '_lang'; + if (!function_exists($lang_func)) + { + $lang_func = '_module_' . $short_name . '_lang'; + } // Custom function for calling parameters on module init (for example assigning template variables) - $custom_func = '_module_' . $row['module_basename']; + $custom_func = 'phpbb_module_' . $short_name; + if (!function_exists($custom_func)) + { + $custom_func = '_module_' . $short_name; + } $names[$row['module_basename'] . '_' . $row['module_mode']][] = true; @@ -258,6 +299,20 @@ class p_master $custom_func($row['module_mode'], $module_row); } + /** + * This event allows to modify parameters for building modules list + * + * @event core.modify_module_row + * @var string url_func Function for building 'url_extra' + * @var string lang_func Function for building the language name + * @var string custom_func Custom function for calling parameters on module init + * @var array row Array holding the basic module data + * @var array module_row Array holding the module display parameters + * @since 3.1.0-b3 + */ + $vars = array('url_func', 'lang_func', 'custom_func', 'row', 'module_row'); + extract($phpbb_dispatcher->trigger_event('core.modify_module_row', compact($vars))); + $this->module_ary[] = $module_row; } @@ -275,6 +330,11 @@ class p_master */ function loaded($module_basename, $module_mode = false) { + if (!$this->is_full_class($module_basename)) + { + $module_basename = $this->p_class . '_' . $module_basename; + } + if (empty($this->loaded_cache)) { $this->loaded_cache = array(); @@ -309,11 +369,26 @@ class p_master } /** - * Check module authorisation + * Check module authorisation. + * + * This is a non-static version that uses $this->acl_forum_id + * for the forum id. + */ + function module_auth_self($module_auth) + { + return self::module_auth($module_auth, $this->acl_forum_id); + } + + /** + * Check module authorisation. + * + * This is a static version, it must be given $forum_id. + * See also module_auth_self. */ - function module_auth($module_auth, $forum_id = false) + static function module_auth($module_auth, $forum_id) { global $auth, $config; + global $request, $phpbb_extension_manager, $phpbb_dispatcher; $module_auth = trim($module_auth); @@ -330,6 +405,31 @@ class p_master [(),] | [^\s(),]+)/x', $module_auth, $match); + // Valid tokens for auth and their replacements + $valid_tokens = array( + 'acl_([a-z0-9_]+)(,\$id)?' => '(int) $auth->acl_get(\'\\1\'\\2)', + '\$id' => '(int) $forum_id', + 'aclf_([a-z0-9_]+)' => '(int) $auth->acl_getf_global(\'\\1\')', + 'cfg_([a-z0-9_]+)' => '(int) $config[\'\\1\']', + 'request_([a-zA-Z0-9_]+)' => '$request->variable(\'\\1\', false)', + 'ext_([a-zA-Z0-9_/]+)' => 'array_key_exists(\'\\1\', $phpbb_extension_manager->all_enabled())', + 'authmethod_([a-z0-9_\\\\]+)' => '($config[\'auth_method\'] === \'\\1\')', + ); + + /** + * Alter tokens for module authorisation check + * + * @event core.module_auth + * @var array valid_tokens Valid tokens and their auth check + * replacements + * @var string module_auth The module_auth of the current + * module + * @var int forum_id The current forum_id + * @since 3.1.0-a3 + */ + $vars = array('valid_tokens', 'module_auth', 'forum_id'); + extract($phpbb_dispatcher->trigger_event('core.module_auth', compact($vars))); + $tokens = $match[0]; for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) { @@ -345,7 +445,7 @@ class p_master break; default: - if (!preg_match('#(?:acl_([a-z0-9_]+)(,\$id)?)|(?:\$id)|(?:aclf_([a-z0-9_]+))|(?:cfg_([a-z0-9_]+))|(?:request_([a-zA-Z0-9_]+))#', $token)) + if (!preg_match('#(?:' . implode(array_keys($valid_tokens), ')|(?:') . ')#', $token)) { $token = ''; } @@ -355,13 +455,22 @@ class p_master $module_auth = implode(' ', $tokens); - // Make sure $id seperation is working fine + // Make sure $id separation is working fine $module_auth = str_replace(' , ', ',', $module_auth); - $forum_id = ($forum_id === false) ? $this->acl_forum_id : $forum_id; + $module_auth = preg_replace( + // Array keys with # prepended/appended + array_map(function($value) { + return '#' . $value . '#'; + }, array_keys($valid_tokens)), + array_values($valid_tokens), + $module_auth + ); $is_auth = false; - eval('$is_auth = (int) (' . preg_replace(array('#acl_([a-z0-9_]+)(,\$id)?#', '#\$id#', '#aclf_([a-z0-9_]+)#', '#cfg_([a-z0-9_]+)#', '#request_([a-zA-Z0-9_]+)#'), array('(int) $auth->acl_get(\'\\1\'\\2)', '(int) $forum_id', '(int) $auth->acl_getf_global(\'\\1\')', '(int) $config[\'\\1\']', '!empty($_REQUEST[\'\\1\'])'), $module_auth) . ');'); + // @codingStandardsIgnoreStart + eval('$is_auth = (int) (' . $module_auth . ');'); + // @codingStandardsIgnoreEnd return $is_auth; } @@ -380,6 +489,17 @@ class p_master $id = request_var('icat', ''); } + // Restore the backslashes in class names + if (strpos($id, '-') !== false) + { + $id = str_replace('-', '\\', $id); + } + + if ($id && !is_numeric($id) && !$this->is_full_class($id)) + { + $id = $this->p_class . '_' . $id; + } + $category = false; foreach ($this->module_ary as $row_id => $item_ary) { @@ -388,9 +508,9 @@ class p_master // If this is a module and no mode selected, select first mode // If no category or module selected, go active for first module in first category if ( - (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && (($item_ary['mode'] == $mode && !$item_ary['cat']) || ($icat && $item_ary['cat']))) || + (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (($item_ary['mode'] == $mode && !$item_ary['cat']) || ($icat && $item_ary['cat']))) || ($item_ary['parent'] === $category && !$item_ary['cat'] && !$icat && $item_ary['display']) || - (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && !$mode && !$item_ary['cat']) || + (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && !$mode && !$item_ary['cat']) || (!$id && !$mode && !$item_ary['cat'] && $item_ary['display']) ) { @@ -426,10 +546,14 @@ class p_master * Loads currently active module * * This method loads a given module, passing it the relevant id and mode. + * + * @param string|false $mode mode, as passed through to the module + * @param string|false $module_url If supplied, we use this module url + * @param bool $execute_module If true, at the end we execute the main method for the new instance */ function load_active($mode = false, $module_url = false, $execute_module = true) { - global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user; + global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user, $template; $module_path = $this->include_path . $this->p_class; $icat = request_var('icat', ''); @@ -439,75 +563,115 @@ class p_master trigger_error('MODULE_NOT_ACCESS', E_USER_ERROR); } - if (!class_exists("{$this->p_class}_$this->p_name")) + // new modules use the full class names, old ones are always called <type>_<name>, e.g. acp_board + if (!class_exists($this->p_name)) { - if (!file_exists("$module_path/{$this->p_class}_$this->p_name.$phpEx")) + if (!file_exists("$module_path/{$this->p_name}.$phpEx")) { - trigger_error($user->lang('MODULE_NOT_FIND', "$module_path/{$this->p_class}_$this->p_name.$phpEx"), E_USER_ERROR); + trigger_error($user->lang('MODULE_NOT_FIND', "$module_path/{$this->p_name}.$phpEx"), E_USER_ERROR); } - include("$module_path/{$this->p_class}_$this->p_name.$phpEx"); + include("$module_path/{$this->p_name}.$phpEx"); - if (!class_exists("{$this->p_class}_$this->p_name")) + if (!class_exists($this->p_name)) { - trigger_error($user->lang('MODULE_FILE_INCORRECT_CLASS', "$module_path/{$this->p_class}_$this->p_name.$phpEx", "{$this->p_class}_$this->p_name"), E_USER_ERROR); + trigger_error($user->lang('MODULE_FILE_INCORRECT_CLASS', "$module_path/{$this->p_name}.$phpEx", $this->p_name), E_USER_ERROR); } + } - if (!empty($mode)) - { - $this->p_mode = $mode; - } + if (!empty($mode)) + { + $this->p_mode = $mode; + } - // Create a new instance of the desired module ... if it has a - // constructor it will of course be executed - $instance = "{$this->p_class}_$this->p_name"; + // Create a new instance of the desired module ... + $class_name = $this->p_name; - $this->module = new $instance($this); + $this->module = new $class_name($this); - // We pre-define the action parameter we are using all over the place - if (defined('IN_ADMIN')) + // We pre-define the action parameter we are using all over the place + if (defined('IN_ADMIN')) + { + /* + * If this is an extension module, we'll try to automatically set + * the style paths for the extension (the ext author can change them + * if necessary). + */ + $module_dir = explode('\\', get_class($this->module)); + + // 0 vendor, 1 extension name, ... + if (isset($module_dir[1])) { - // Is first module automatically enabled a duplicate and the category not passed yet? - if (!$icat && $this->module_ary[$this->active_module_row_id]['is_duplicate']) + $module_style_dir = $phpbb_root_path . 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/adm/style'; + + if (is_dir($module_style_dir)) { - $icat = $this->module_ary[$this->active_module_row_id]['parent']; + $template->set_custom_style(array( + array( + 'name' => 'adm', + 'ext_path' => 'adm/style/', + ), + ), array($module_style_dir, $phpbb_admin_path . 'style')); } + } - // Not being able to overwrite ;) - $this->module->u_action = append_sid("{$phpbb_admin_path}index.$phpEx", "i={$this->p_name}") . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; + // Is first module automatically enabled a duplicate and the category not passed yet? + if (!$icat && $this->module_ary[$this->active_module_row_id]['is_duplicate']) + { + $icat = $this->module_ary[$this->active_module_row_id]['parent']; } - else + + // Not being able to overwrite ;) + $this->module->u_action = append_sid("{$phpbb_admin_path}index.$phpEx", 'i=' . $this->get_module_identifier($this->p_name)) . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; + } + else + { + /* + * If this is an extension module, we'll try to automatically set + * the style paths for the extension (the ext author can change them + * if necessary). + */ + $module_dir = explode('\\', get_class($this->module)); + + // 0 vendor, 1 extension name, ... + if (isset($module_dir[1])) { - // If user specified the module url we will use it... - if ($module_url !== false) - { - $this->module->u_action = $module_url; - } - else + $module_style_dir = 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/styles'; + + if (is_dir($phpbb_root_path . $module_style_dir)) { - $this->module->u_action = $phpbb_root_path . (($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '') . $user->page['page_name']; + $template->set_style(array($module_style_dir, 'styles')); } - - $this->module->u_action = append_sid($this->module->u_action, "i={$this->p_name}") . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; } - // Add url_extra parameter to u_action url - if (!empty($this->module_ary) && $this->active_module !== false && $this->module_ary[$this->active_module_row_id]['url_extra']) + // If user specified the module url we will use it... + if ($module_url !== false) { - $this->module->u_action .= $this->module_ary[$this->active_module_row_id]['url_extra']; + $this->module->u_action = $module_url; } - - // Assign the module path for re-usage - $this->module->module_path = $module_path . '/'; - - // Execute the main method for the new instance, we send the module id and mode as parameters - // Users are able to call the main method after this function to be able to assign additional parameters manually - if ($execute_module) + else { - $this->module->main($this->p_name, $this->p_mode); + $this->module->u_action = $phpbb_root_path . (($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '') . $user->page['page_name']; } - return; + $this->module->u_action = append_sid($this->module->u_action, 'i=' . $this->get_module_identifier($this->p_name)) . (($icat) ? '&icat=' . $icat : '') . "&mode={$this->p_mode}"; + } + + // Add url_extra parameter to u_action url + if (!empty($this->module_ary) && $this->active_module !== false && $this->module_ary[$this->active_module_row_id]['url_extra']) + { + $this->module->u_action .= $this->module_ary[$this->active_module_row_id]['url_extra']; + } + + // Assign the module path for re-usage + $this->module->module_path = $module_path . '/'; + + // Execute the main method for the new instance, we send the module id and mode as parameters + // Users are able to call the main method after this function to be able to assign additional parameters manually + if ($execute_module) + { + $short_name = preg_replace("#^{$this->p_class}_#", '', $this->p_name); + $this->module->main($short_name, $this->p_mode); } } @@ -546,7 +710,7 @@ class p_master // If we find a name by this id and being enabled we have our active one... foreach ($this->module_ary as $row_id => $item_ary) { - if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && $item_ary['display']) + if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && $item_ary['display'] || $item_ary['name'] === $this->p_class . '_' . $id) { if ($mode === false || $mode === $item_ary['mode']) { @@ -734,7 +898,26 @@ class p_master } } - $u_title = $module_url . $delim . 'i=' . (($item_ary['cat']) ? $item_ary['id'] : $item_ary['name'] . (($item_ary['is_duplicate']) ? '&icat=' . $current_id : '') . '&mode=' . $item_ary['mode']); + $u_title = $module_url . $delim . 'i='; + // if the item has a name use it, else use its id + if (empty($item_ary['name'])) + { + $u_title .= $item_ary['id']; + } + else + { + // if the category has a name, then use it. + $u_title .= $this->get_module_identifier($item_ary['name']); + } + // If the item is not a category append the mode + if (!$item_ary['cat']) + { + if ($item_ary['is_duplicate']) + { + $u_title .= '&icat=' . $current_id; + } + $u_title .= '&mode=' . $item_ary['mode']; + } // Was not allowed in categories before - /*!$item_ary['cat'] && */ $u_title .= (isset($item_ary['url_extra'])) ? $item_ary['url_extra'] : ''; @@ -790,9 +973,22 @@ class p_master /** * Load module as the current active one without the need for registering it + * + * @param string $class module class (acp/mcp/ucp) + * @param string $name module name (class name of the module, or its basename + * phpbb_ext_foo_acp_bar_module, ucp_zebra or zebra) + * @param string $mode mode, as passed through to the module + * */ function load($class, $name, $mode = false) { + // new modules use the full class names, old ones are always called <class>_<name>, e.g. acp_board + // in the latter case this function may be called as load('acp', 'board') + if (!class_exists($name) && substr($name, 0, strlen($class) + 1) !== $class . '_') + { + $name = $class . '_' . $name; + } + $this->p_class = $class; $this->p_name = $name; @@ -805,7 +1001,7 @@ class p_master /** * Display module */ - function display($page_title, $display_online_list = true) + function display($page_title, $display_online_list = false) { global $template, $user; @@ -840,7 +1036,7 @@ class p_master { foreach ($this->module_ary as $row_id => $item_ary) { - if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && (!$mode || $item_ary['mode'] === $mode)) + if (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (!$mode || $item_ary['mode'] === $mode)) { $this->module_ary[$row_id]['display'] = (int) $display; } @@ -852,32 +1048,98 @@ class p_master */ function add_mod_info($module_class) { - global $user, $phpEx; + global $config, $user, $phpEx, $phpbb_extension_manager; + + $finder = $phpbb_extension_manager->get_finder(); - if (file_exists($user->lang_path . $user->lang_name . '/mods')) + // We grab the language files from the default, English and user's language. + // So we can fall back to the other files like we do when using add_lang() + $default_lang_files = $english_lang_files = $user_lang_files = array(); + + // Search for board default language if it's not the user language + if ($config['default_lang'] != $user->lang_name) { - $add_files = array(); + $default_lang_files = $finder + ->prefix('info_' . strtolower($module_class) . '_') + ->suffix(".$phpEx") + ->extension_directory('/language/' . basename($config['default_lang'])) + ->core_path('language/' . basename($config['default_lang']) . '/mods/') + ->find(); + } - $dir = @opendir($user->lang_path . $user->lang_name . '/mods'); + // Search for english, if its not the default or user language + if ($config['default_lang'] != 'en' && $user->lang_name != 'en') + { + $english_lang_files = $finder + ->prefix('info_' . strtolower($module_class) . '_') + ->suffix(".$phpEx") + ->extension_directory('/language/en') + ->core_path('language/en/mods/') + ->find(); + } - if ($dir) - { - while (($entry = readdir($dir)) !== false) - { - if (strpos($entry, 'info_' . strtolower($module_class) . '_') === 0 && substr(strrchr($entry, '.'), 1) == $phpEx) - { - $add_files[] = 'mods/' . substr(basename($entry), 0, -(strlen($phpEx) + 1)); - } - } - closedir($dir); - } + // Find files in the user's language + $user_lang_files = $finder + ->prefix('info_' . strtolower($module_class) . '_') + ->suffix(".$phpEx") + ->extension_directory('/language/' . $user->lang_name) + ->core_path('language/' . $user->lang_name . '/mods/') + ->find(); - if (sizeof($add_files)) - { - $user->add_lang($add_files); - } + $lang_files = array_unique(array_merge($user_lang_files, $english_lang_files, $default_lang_files)); + foreach ($lang_files as $lang_file => $ext_name) + { + $user->add_lang_ext($ext_name, $lang_file); } } -} -?>
\ No newline at end of file + /** + * Retrieve shortened module basename for legacy basenames (with xcp_ prefix) + * + * @param string $basename A module basename + * @return string The basename if it starts with phpbb_ or the basename with + * the current p_class (e.g. acp_) stripped. + */ + protected function get_short_name($basename) + { + if (substr($basename, 0, 6) === 'phpbb\\' || strpos($basename, '\\') !== false) + { + return $basename; + } + + // strip xcp_ prefix from old classes + return substr($basename, strlen($this->p_class) + 1); + } + + /** + * If the basename contains a \ we don't use that for the URL. + * + * Firefox is currently unable to correctly copy a urlencoded \ + * so users will be unable to post links to modules. + * However we can replace them with dashes and re-replace them later + * + * @param string $basename Basename of the module + * @return string Identifier that should be used for + * module link creation + */ + protected function get_module_identifier($basename) + { + if (strpos($basename, '\\') === false) + { + return $basename; + } + + return str_replace('\\', '-', $basename); + } + + /** + * Checks whether the given module basename is a correct class name + * + * @param string $basename A module basename + * @return bool True if the basename starts with phpbb_ or (x)cp_, false otherwise + */ + protected function is_full_class($basename) + { + return (strpos($basename, '\\') !== false || preg_match('/^(ucp|mcp|acp)_/', $basename)); + } +} diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 3f0a78a7cb..a06d6f4c35 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -21,9 +24,11 @@ if (!defined('IN_PHPBB')) */ function generate_smilies($mode, $forum_id) { - global $auth, $db, $user, $config, $template; - global $phpEx, $phpbb_root_path; + global $db, $user, $config, $template, $phpbb_dispatcher; + global $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_path_helper; + $base_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id); + $pagination = $phpbb_container->get('pagination'); $start = request_var('start', 0); if ($mode == 'window') @@ -62,10 +67,8 @@ function generate_smilies($mode, $forum_id) 'body' => 'posting_smilies.html') ); - $template->assign_var('PAGINATION', - generate_pagination(append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id), - $smiley_count, $config['smilies_per_page'], $start, true) - ); + $start = $pagination->validate_start($start, $config['smilies_per_page'], $smiley_count); + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $smiley_count, $config['smilies_per_page'], $start); } $display_link = false; @@ -112,7 +115,7 @@ function generate_smilies($mode, $forum_id) if (sizeof($smilies)) { - $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; + $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_path_helper->get_web_root_path(); foreach ($smilies as $row) { @@ -127,12 +130,24 @@ function generate_smilies($mode, $forum_id) } } + /** + * This event is called after the smilies are populated + * + * @event core.generate_smilies_after + * @var string mode Mode of the smilies: window|inline + * @var int forum_id The forum ID we are currently in + * @var bool display_link Shall we display the "more smilies" link? + * @since 3.1.0-a1 + */ + $vars = array('mode', 'forum_id', 'display_link'); + extract($phpbb_dispatcher->trigger_event('core.generate_smilies_after', compact($vars))); + if ($mode == 'inline' && $display_link) { $template->assign_vars(array( 'S_SHOW_SMILEY_LINK' => true, - 'U_MORE_SMILIES' => append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id)) - ); + 'U_MORE_SMILIES' => $base_url, + )); } if ($mode == 'window') @@ -162,13 +177,12 @@ function update_post_information($type, $ids, $return_update_sql = false) $ids = array($ids); } - $update_sql = $empty_forums = $not_empty_forums = array(); if ($type != 'topic') { $topic_join = ', ' . TOPICS_TABLE . ' t'; - $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_approved = 1'; + $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_visibility = ' . ITEM_APPROVED; } else { @@ -182,7 +196,7 @@ function update_post_information($type, $ids, $return_update_sql = false) FROM ' . POSTS_TABLE . " p $topic_join WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . " $topic_condition - AND p.post_approved = 1"; + AND p.post_visibility = " . ITEM_APPROVED; } else { @@ -190,7 +204,7 @@ function update_post_information($type, $ids, $return_update_sql = false) FROM ' . POSTS_TABLE . " p $topic_join WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . " $topic_condition - AND p.post_approved = 1 + AND p.post_visibility = " . ITEM_APPROVED . " GROUP BY p.{$type}_id"; } $result = $db->sql_query($sql); @@ -340,7 +354,7 @@ function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL) $topic_type_array[] = array( 'VALUE' => $topic_value['const'], - 'S_CHECKED' => ($cur_topic_type == $topic_value['const'] || ($forum_id == 0 && $topic_value['const'] == POST_GLOBAL)) ? ' checked="checked"' : '', + 'S_CHECKED' => ($cur_topic_type == $topic_value['const']) ? ' checked="checked"' : '', 'L_TOPIC_TYPE' => $user->lang[$topic_value['lang']] ); } @@ -377,11 +391,22 @@ function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL) /** * Upload Attachment - filedata is generated here * Uses upload class +* +* @param string $form_name The form name of the file upload input +* @param int $forum_id The id of the forum +* @param bool $local Whether the file is local or not +* @param string $local_storage The path to the local file +* @param bool $is_message Whether it is a PM or not +* @param \filespec $local_filedata A filespec object created for the local file +* @param \phpbb\mimetype\guesser $mimetype_guesser The mimetype guesser object if used +* @param \phpbb\plupload\plupload $plupload The plupload object if one is being used +* +* @return object filespec */ -function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false) +function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null) { global $auth, $user, $config, $db, $cache; - global $phpbb_root_path, $phpEx; + global $phpbb_root_path, $phpEx, $phpbb_dispatcher; $filedata = array( 'error' => array() @@ -399,14 +424,7 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage $upload->set_disallowed_content(array()); } - if (!$local) - { - $filedata['post_attach'] = ($upload->is_valid($form_name)) ? true : false; - } - else - { - $filedata['post_attach'] = true; - } + $filedata['post_attach'] = $local || $upload->is_valid($form_name); if (!$filedata['post_attach']) { @@ -417,7 +435,7 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage $extensions = $cache->obtain_attach_extensions((($is_message) ? false : (int) $forum_id)); $upload->set_allowed_extensions(array_keys($extensions['_allowed_'])); - $file = ($local) ? $upload->local_upload($local_storage, $local_filedata) : $upload->form_upload($form_name); + $file = ($local) ? $upload->local_upload($local_storage, $local_filedata, $mimetype_guesser) : $upload->form_upload($form_name, $mimetype_guesser, $plupload); if ($file->init_error) { @@ -425,20 +443,18 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage return $filedata; } - $cat_id = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] : ATTACHMENT_CATEGORY_NONE; + // Whether the uploaded file is in the image category + $is_image = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE : false; - // Do we have to create a thumbnail? - $filedata['thumbnail'] = ($cat_id == ATTACHMENT_CATEGORY_IMAGE && $config['img_create_thumbnail']) ? 1 : 0; - - // Check Image Size, if it is an image - if (!$auth->acl_get('a_') && !$auth->acl_get('m_', $forum_id) && $cat_id == ATTACHMENT_CATEGORY_IMAGE) - { - $file->upload->set_allowed_dimensions(0, 0, $config['img_max_width'], $config['img_max_height']); - } - - // Admins and mods are allowed to exceed the allowed filesize if (!$auth->acl_get('a_') && !$auth->acl_get('m_', $forum_id)) { + // Check Image Size, if it is an image + if ($is_image) + { + $file->upload->set_allowed_dimensions(0, 0, $config['img_max_width'], $config['img_max_height']); + } + + // Admins and mods are allowed to exceed the allowed filesize if (!empty($extensions[$file->get('extension')]['max_filesize'])) { $allowed_filesize = $extensions[$file->get('extension')]['max_filesize']; @@ -453,10 +469,12 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage $file->clean_filename('unique', $user->data['user_id'] . '_'); - // Are we uploading an image *and* this image being within the image category? Only then perform additional image checks. - $no_image = ($cat_id == ATTACHMENT_CATEGORY_IMAGE) ? false : true; + // Are we uploading an image *and* this image being within the image category? + // Only then perform additional image checks. + $file->move_file($config['upload_path'], false, !$is_image); - $file->move_file($config['upload_path'], false, $no_image); + // Do we have to create a thumbnail? + $filedata['thumbnail'] = ($is_image && $config['img_create_thumbnail']) ? 1 : 0; if (sizeof($file->error)) { @@ -468,10 +486,15 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage } // Make sure the image category only holds valid images... - if ($cat_id == ATTACHMENT_CATEGORY_IMAGE && !$file->is_image()) + if ($is_image && !$file->is_image()) { $file->remove(); + if ($plupload && $plupload->is_active()) + { + $plupload->emit_error(104, 'ATTACHED_IMAGE_NOT_IMAGE'); + } + // If this error occurs a user tried to exploit an IE Bug by renaming extensions // Since the image category is displaying content inline we need to catch this. trigger_error($user->lang['ATTACHED_IMAGE_NOT_IMAGE']); @@ -484,6 +507,20 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage $filedata['real_filename'] = $file->get('uploadname'); $filedata['filetime'] = time(); + /** + * Event to modify uploaded file before submit to the post + * + * @event core.modify_uploaded_file + * @var array filedata Array containing uploaded file data + * @var bool is_image Flag indicating if the file is an image + * @since 3.1.0-RC3 + */ + $vars = array( + 'filedata', + 'is_image', + ); + extract($phpbb_dispatcher->trigger_event('core.modify_uploaded_file', compact($vars))); + // Check our complete quota if ($config['attachment_quota']) { @@ -573,30 +610,30 @@ function get_supported_image_types($type = false) if ($type !== false) { // Type is one of the IMAGETYPE constants - it is fetched from getimagesize() - // We do not use the constants here, because some were not available in PHP 4.3.x switch ($type) { // GIF - case 1: + case IMAGETYPE_GIF: $new_type = ($format & IMG_GIF) ? IMG_GIF : false; break; // JPG, JPC, JP2 - case 2: - case 9: - case 10: - case 11: - case 12: + case IMAGETYPE_JPEG: + case IMAGETYPE_JPC: + case IMAGETYPE_JPEG2000: + case IMAGETYPE_JP2: + case IMAGETYPE_JPX: + case IMAGETYPE_JB2: $new_type = ($format & IMG_JPG) ? IMG_JPG : false; break; // PNG - case 3: + case IMAGETYPE_PNG: $new_type = ($format & IMG_PNG) ? IMG_PNG : false; break; // WBMP - case 15: + case IMAGETYPE_WBMP: $new_type = ($format & IMG_WBMP) ? IMG_WBMP : false; break; } @@ -816,7 +853,7 @@ function posting_gen_inline_attachments(&$attachment_data) */ function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true) { - global $template, $config, $phpbb_root_path, $phpEx, $user, $auth; + global $template, $config, $phpbb_root_path, $phpEx, $user; // Some default template variables $template->assign_vars(array( @@ -850,6 +887,7 @@ function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_a 'ATTACH_ID' => $attach_row['attach_id'], 'S_IS_ORPHAN' => $attach_row['is_orphan'], 'ASSOC_INDEX' => $count, + 'FILESIZE' => get_formatted_filesize($attach_row['filesize']), 'U_VIEW_ATTACHMENT' => $download_link, 'S_HIDDEN' => $hidden) @@ -870,7 +908,7 @@ function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_a function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $msg_id = 0) { global $user, $db, $template, $auth; - global $phpbb_root_path, $phpEx; + global $phpbb_root_path, $phpbb_dispatcher, $phpEx; $topic_ids = $forum_ids = $draft_rows = array(); @@ -913,7 +951,7 @@ function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $ms $topic_rows = array(); if (sizeof($topic_ids)) { - $sql = 'SELECT topic_id, forum_id, topic_title + $sql = 'SELECT topic_id, forum_id, topic_title, topic_poster FROM ' . TOPICS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', array_unique($topic_ids)); $result = $db->sql_query($sql); @@ -924,6 +962,20 @@ function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $ms } $db->sql_freeresult($result); } + + /** + * Drafts found and their topics + * Edit $draft_rows in order to add or remove drafts loaded + * + * @event core.load_drafts_draft_list_result + * @var array draft_rows The drafts query result. Includes its forum id and everything about the draft + * @var array topic_ids The list of topics got from the topics table + * @var array topic_rows The topics that draft_rows references + * @since 3.1.0-RC3 + */ + $vars = array('draft_rows', 'topic_ids', 'topic_rows'); + extract($phpbb_dispatcher->trigger_event('core.load_drafts_draft_list_result', compact($vars))); + unset($topic_ids); $template->assign_var('S_SHOW_DRAFTS', true); @@ -984,18 +1036,20 @@ function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $ms */ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id = 0, $show_quote_button = true) { - global $user, $auth, $db, $template, $bbcode, $cache; - global $config, $phpbb_root_path, $phpEx; + global $user, $auth, $db, $template, $cache; + global $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher; + + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + $sql_sort = ($mode == 'post_review') ? 'ASC' : 'DESC'; // Go ahead and pull all data for this topic $sql = 'SELECT p.post_id FROM ' . POSTS_TABLE . ' p' . " WHERE p.topic_id = $topic_id - " . ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND p.post_approved = 1' : '') . ' + AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . ' ' . (($mode == 'post_review') ? " AND p.post_id > $cur_post_id" : '') . ' ' . (($mode == 'post_review_edit') ? " AND p.post_id = $cur_post_id" : '') . ' - ORDER BY p.post_time '; - $sql .= ($mode == 'post_review') ? 'ASC' : 'DESC'; + ORDER BY p.post_time ' . $sql_sort . ', p.post_id ' . $sql_sort; $result = $db->sql_query_limit($sql, $config['posts_per_page']); $post_list = array(); @@ -1018,7 +1072,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id $mode = 'post_review'; } - $sql = $db->sql_build_query('SELECT', array( + $sql_ary = array( 'SELECT' => 'u.username, u.user_id, u.user_colour, p.*, z.friend, z.foe', 'FROM' => array( @@ -1029,23 +1083,22 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id 'LEFT_JOIN' => array( array( 'FROM' => array(ZEBRA_TABLE => 'z'), - 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id' - ) + 'ON' => 'z.user_id = ' . $user->data['user_id'] . ' AND z.zebra_id = p.poster_id', + ), ), 'WHERE' => $db->sql_in_set('p.post_id', $post_list) . ' - AND u.user_id = p.poster_id' - )); + AND u.user_id = p.poster_id', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); $result = $db->sql_query($sql); - $bbcode_bitfield = ''; $rowset = array(); $has_attachments = false; while ($row = $db->sql_fetchrow($result)) { $rowset[$row['post_id']] = $row; - $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']); if ($row['post_attachment']) { @@ -1054,13 +1107,6 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id } $db->sql_freeresult($result); - // Instantiate BBCode class - if (!isset($bbcode) && $bbcode_bitfield !== '') - { - include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode(base64_encode($bbcode_bitfield)); - } - // Grab extensions $extensions = $attachments = array(); if ($has_attachments && $auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id)) @@ -1091,29 +1137,24 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id continue; } - $row =& $rowset[$post_list[$i]]; + $row = $rowset[$post_list[$i]]; $poster_id = $row['user_id']; $post_subject = $row['post_subject']; - $message = censor_text($row['post_text']); $decoded_message = false; if ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) { - $decoded_message = $message; + $decoded_message = censor_text($row['post_text']); decode_message($decoded_message, $row['bbcode_uid']); $decoded_message = bbcode_nl2br($decoded_message); } - if ($row['bbcode_bitfield']) - { - $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']); - } - - $message = bbcode_nl2br($message); - $message = smiley_text($message, !$row['enable_smilies']); + $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0); + $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0); + $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true); if (!empty($attachments[$row['post_id']])) { @@ -1126,7 +1167,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id $post_anchor = ($mode == 'post_review') ? 'ppr' . $row['post_id'] : 'pr' . $row['post_id']; $u_show_post = append_sid($phpbb_root_path . 'viewtopic.' . $phpEx, "f=$forum_id&t=$topic_id&p={$row['post_id']}&view=show#p{$row['post_id']}"); - $template->assign_block_vars($mode . '_row', array( + $post_row = array( 'POST_AUTHOR_FULL' => get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), 'POST_AUTHOR_COLOUR' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), 'POST_AUTHOR' => get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), @@ -1135,7 +1176,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id 'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false, 'S_FRIEND' => ($row['friend']) ? true : false, 'S_IGNORE_POST' => ($row['foe']) ? true : false, - 'L_IGNORE_POST' => ($row['foe']) ? sprintf($user->lang['POST_BY_FOE'], get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), "<a href=\"{$u_show_post}\" onclick=\"dE('{$post_anchor}', 1); return false;\">", '</a>') : '', + 'L_IGNORE_POST' => ($row['foe']) ? sprintf($user->lang['POST_BY_FOE'], get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), "<a href=\"{$u_show_post}\" onclick=\"phpbb.toggleDisplay('{$post_anchor}', 1); return false;\">", '</a>') : '', 'POST_SUBJECT' => $post_subject, 'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['POST']), @@ -1145,8 +1186,36 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id 'POST_ID' => $row['post_id'], 'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'], 'U_MCP_DETAILS' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=post_details&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', - 'POSTER_QUOTE' => ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) ? addslashes(get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '') + 'POSTER_QUOTE' => ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) ? addslashes(get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '', + ); + + $current_row_number = $i; + + /** + * Event to modify the template data block for topic reviews + * + * @event core.topic_review_modify_row + * @var string mode The review mode + * @var int topic_id The topic that is being reviewed + * @var int forum_id The topic's forum + * @var int cur_post_id Post offset id + * @var int current_row_number Number of the current row being iterated + * @var array post_row Template block array of the current post + * @var array row Array with original post and user data + * @since 3.1.4-RC1 + */ + $vars = array( + 'mode', + 'topic_id', + 'forum_id', + 'cur_post_id', + 'current_row_number', + 'post_row', + 'row', ); + extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_row', compact($vars))); + + $template->assign_block_vars($mode . '_row', $post_row); // Display not already displayed Attachments for this post, we already parsed them. ;) if (!empty($attachments[$row['post_id']])) @@ -1170,238 +1239,6 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id return true; } -/** -* User Notification -*/ -function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id, $topic_id, $post_id, $author_name = '') -{ - global $db, $user, $config, $phpbb_root_path, $phpEx, $auth; - - $topic_notification = ($mode == 'reply' || $mode == 'quote') ? true : false; - $forum_notification = ($mode == 'post') ? true : false; - - if (!$topic_notification && !$forum_notification) - { - trigger_error('NO_MODE'); - } - - if (($topic_notification && !$config['allow_topic_notify']) || ($forum_notification && !$config['allow_forum_notify'])) - { - return; - } - - $topic_title = ($topic_notification) ? $topic_title : $subject; - $topic_title = censor_text($topic_title); - - // Exclude guests, current user and banned users from notifications - if (!function_exists('phpbb_get_banned_user_ids')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - $sql_ignore_users = phpbb_get_banned_user_ids(); - $sql_ignore_users[ANONYMOUS] = ANONYMOUS; - $sql_ignore_users[$user->data['user_id']] = $user->data['user_id']; - - $notify_rows = array(); - - // -- get forum_userids || topic_userids - $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber - FROM ' . (($topic_notification) ? TOPICS_WATCH_TABLE : FORUMS_WATCH_TABLE) . ' w, ' . USERS_TABLE . ' u - WHERE w.' . (($topic_notification) ? 'topic_id' : 'forum_id') . ' = ' . (($topic_notification) ? $topic_id : $forum_id) . ' - AND ' . $db->sql_in_set('w.user_id', $sql_ignore_users, true) . ' - AND w.notify_status = ' . NOTIFY_YES . ' - AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ') - AND u.user_id = w.user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $notify_user_id = (int) $row['user_id']; - $notify_rows[$notify_user_id] = array( - 'user_id' => $notify_user_id, - 'username' => $row['username'], - 'user_email' => $row['user_email'], - 'user_jabber' => $row['user_jabber'], - 'user_lang' => $row['user_lang'], - 'notify_type' => ($topic_notification) ? 'topic' : 'forum', - 'template' => ($topic_notification) ? 'topic_notify' : 'newtopic_notify', - 'method' => $row['user_notify_type'], - 'allowed' => false - ); - - // Add users who have been already notified to ignore list - $sql_ignore_users[$notify_user_id] = $notify_user_id; - } - $db->sql_freeresult($result); - - // forum notification is sent to those not already receiving topic notifications - if ($topic_notification) - { - $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber - FROM ' . FORUMS_WATCH_TABLE . ' fw, ' . USERS_TABLE . " u - WHERE fw.forum_id = $forum_id - AND " . $db->sql_in_set('fw.user_id', $sql_ignore_users, true) . ' - AND fw.notify_status = ' . NOTIFY_YES . ' - AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ') - AND u.user_id = fw.user_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $notify_user_id = (int) $row['user_id']; - $notify_rows[$notify_user_id] = array( - 'user_id' => $notify_user_id, - 'username' => $row['username'], - 'user_email' => $row['user_email'], - 'user_jabber' => $row['user_jabber'], - 'user_lang' => $row['user_lang'], - 'notify_type' => 'forum', - 'template' => 'forum_notify', - 'method' => $row['user_notify_type'], - 'allowed' => false - ); - } - $db->sql_freeresult($result); - } - - if (!sizeof($notify_rows)) - { - return; - } - - // Make sure users are allowed to read the forum - foreach ($auth->acl_get_list(array_keys($notify_rows), 'f_read', $forum_id) as $forum_id => $forum_ary) - { - foreach ($forum_ary as $auth_option => $user_ary) - { - foreach ($user_ary as $user_id) - { - $notify_rows[$user_id]['allowed'] = true; - } - } - } - - // Now, we have to do a little step before really sending, we need to distinguish our users a little bit. ;) - $msg_users = $delete_ids = $update_notification = array(); - foreach ($notify_rows as $user_id => $row) - { - if (!$row['allowed'] || !trim($row['user_email'])) - { - $delete_ids[$row['notify_type']][] = $row['user_id']; - } - else - { - $msg_users[] = $row; - $update_notification[$row['notify_type']][] = $row['user_id']; - - /* - * We also update the forums watch table for this user when we are - * sending out a topic notification to prevent sending out another - * notification in case this user is also subscribed to the forum - * this topic was posted in. - * Since an UPDATE query is used, this has no effect on users only - * subscribed to the topic (i.e. no row is created) and should not - * be a performance issue. - */ - if ($row['notify_type'] === 'topic') - { - $update_notification['forum'][] = $row['user_id']; - } - } - } - unset($notify_rows); - - // Now, we are able to really send out notifications - if (sizeof($msg_users)) - { - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $messenger = new messenger(); - - $msg_list_ary = array(); - foreach ($msg_users as $row) - { - $pos = (!isset($msg_list_ary[$row['template']])) ? 0 : sizeof($msg_list_ary[$row['template']]); - - $msg_list_ary[$row['template']][$pos]['method'] = $row['method']; - $msg_list_ary[$row['template']][$pos]['email'] = $row['user_email']; - $msg_list_ary[$row['template']][$pos]['jabber'] = $row['user_jabber']; - $msg_list_ary[$row['template']][$pos]['name'] = $row['username']; - $msg_list_ary[$row['template']][$pos]['lang'] = $row['user_lang']; - $msg_list_ary[$row['template']][$pos]['user_id']= $row['user_id']; - } - unset($msg_users); - - foreach ($msg_list_ary as $email_template => $email_list) - { - foreach ($email_list as $addr) - { - $messenger->template($email_template, $addr['lang']); - - $messenger->to($addr['email'], $addr['name']); - $messenger->im($addr['jabber'], $addr['name']); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($addr['name']), - 'TOPIC_TITLE' => htmlspecialchars_decode($topic_title), - 'FORUM_NAME' => htmlspecialchars_decode($forum_name), - 'AUTHOR_NAME' => htmlspecialchars_decode($author_name), - - 'U_FORUM' => generate_board_url() . "/viewforum.$phpEx?f=$forum_id", - 'U_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t=$topic_id", - 'U_NEWEST_POST' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t=$topic_id&p=$post_id&e=$post_id", - 'U_STOP_WATCHING_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?uid={$addr['user_id']}&f=$forum_id&t=$topic_id&unwatch=topic", - 'U_STOP_WATCHING_FORUM' => generate_board_url() . "/viewforum.$phpEx?uid={$addr['user_id']}&f=$forum_id&unwatch=forum", - )); - - $messenger->send($addr['method']); - } - } - unset($msg_list_ary); - - $messenger->save_queue(); - } - - // Handle the DB updates - $db->sql_transaction('begin'); - - if (!empty($update_notification['topic'])) - { - $sql = 'UPDATE ' . TOPICS_WATCH_TABLE . ' - SET notify_status = ' . NOTIFY_NO . " - WHERE topic_id = $topic_id - AND " . $db->sql_in_set('user_id', $update_notification['topic']); - $db->sql_query($sql); - } - - if (!empty($update_notification['forum'])) - { - $sql = 'UPDATE ' . FORUMS_WATCH_TABLE . ' - SET notify_status = ' . NOTIFY_NO . " - WHERE forum_id = $forum_id - AND " . $db->sql_in_set('user_id', $update_notification['forum']); - $db->sql_query($sql); - } - - // Now delete the user_ids not authorised to receive notifications on this topic/forum - if (!empty($delete_ids['topic'])) - { - $sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . " - WHERE topic_id = $topic_id - AND " . $db->sql_in_set('user_id', $delete_ids['topic']); - $db->sql_query($sql); - } - - if (!empty($delete_ids['forum'])) - { - $sql = 'DELETE FROM ' . FORUMS_WATCH_TABLE . " - WHERE forum_id = $forum_id - AND " . $db->sql_in_set('user_id', $delete_ids['forum']); - $db->sql_query($sql); - } - - $db->sql_transaction('commit'); -} - // // Post handling functions // @@ -1409,14 +1246,14 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id /** * Delete Post */ -function delete_post($forum_id, $topic_id, $post_id, &$data) +function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $softdelete_reason = '') { - global $db, $user, $auth; + global $db, $user, $auth, $phpbb_container; global $config, $phpEx, $phpbb_root_path; // Specify our post mode $post_mode = 'delete'; - if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && $data['topic_replies_real'] == 0) + if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1)) { $post_mode = 'delete_topic'; } @@ -1458,20 +1295,30 @@ function delete_post($forum_id, $topic_id, $post_id, &$data) $db->sql_freeresult($result); } - if (!delete_posts('post_id', array($post_id), false, false)) + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + + // (Soft) delete the post + if ($is_soft && ($post_mode != 'delete_topic')) { - // Try to delete topic, we may had an previous error causing inconsistency - if ($post_mode == 'delete_topic') + $phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $post_id, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason, ($data['topic_first_post_id'] == $post_id), ($data['topic_last_post_id'] == $post_id)); + } + else if (!$is_soft) + { + if (!delete_posts('post_id', array($post_id), false, false, false)) { - delete_topics('topic_id', array($topic_id), false); + // Try to delete topic, we may had an previous error causing inconsistency + if ($post_mode == 'delete_topic') + { + delete_topics('topic_id', array($topic_id), false); + } + trigger_error('ALREADY_DELETED'); } - trigger_error('ALREADY_DELETED'); } $db->sql_transaction('commit'); // Collect the necessary information for updating the tables - $sql_data[FORUMS_TABLE] = ''; + $sql_data[FORUMS_TABLE] = $sql_data[TOPICS_TABLE] = ''; switch ($post_mode) { case 'delete_topic': @@ -1480,24 +1327,32 @@ function delete_post($forum_id, $topic_id, $post_id, &$data) { // counting is fun! we only have to do sizeof($forum_ids) number of queries, // even if the topic is moved back to where its shadow lives (we count how many times it is in a forum) - $db->sql_query('UPDATE ' . FORUMS_TABLE . ' SET forum_topics_real = forum_topics_real - ' . $topic_count . ', forum_topics = forum_topics - ' . $topic_count . ' WHERE forum_id = ' . $updated_forum); + $sql = 'UPDATE ' . FORUMS_TABLE . ' + SET forum_topics_approved = forum_topics_approved - ' . $topic_count . ' + WHERE forum_id = ' . $updated_forum; + $db->sql_query($sql); update_post_information('forum', $updated_forum); } - delete_topics('topic_id', array($topic_id), false); - - if ($data['topic_type'] != POST_GLOBAL) + if ($is_soft) { - $sql_data[FORUMS_TABLE] .= 'forum_topics_real = forum_topics_real - 1'; - $sql_data[FORUMS_TABLE] .= ($data['topic_approved']) ? ', forum_posts = forum_posts - 1, forum_topics = forum_topics - 1' : ''; + $topic_row = array(); + $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason); } - - $update_sql = update_post_information('forum', $forum_id, true); - if (sizeof($update_sql)) + else { - $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : ''; - $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]); + delete_topics('topic_id', array($topic_id), false); + + $phpbb_content_visibility->remove_topic_from_statistic($data, $sql_data); + + $update_sql = update_post_information('forum', $forum_id, true); + if (sizeof($update_sql)) + { + $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : ''; + $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]); + } } + break; case 'delete_first_post': @@ -1505,82 +1360,88 @@ function delete_post($forum_id, $topic_id, $post_id, &$data) FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u WHERE p.topic_id = $topic_id AND p.poster_id = u.user_id - ORDER BY p.post_time ASC"; + AND p.post_visibility = " . ITEM_APPROVED . ' + ORDER BY p.post_time ASC, p.post_id ASC'; $result = $db->sql_query_limit($sql, 1); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if ($data['topic_type'] != POST_GLOBAL) + if (!$row) { - $sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : ''; + // No approved post, so the first is a not-approved post (unapproved or soft deleted) + $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour + FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u + WHERE p.topic_id = $topic_id + AND p.poster_id = u.user_id + ORDER BY p.post_time ASC, p.post_id ASC"; + $result = $db->sql_query_limit($sql, 1); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); } - $sql_data[TOPICS_TABLE] = 'topic_poster = ' . intval($row['poster_id']) . ', topic_first_post_id = ' . intval($row['post_id']) . ", topic_first_poster_colour = '" . $db->sql_escape($row['user_colour']) . "', topic_first_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "', topic_time = " . (int) $row['post_time']; - - // Decrementing topic_replies here is fine because this case only happens if there is more than one post within the topic - basically removing one "reply" - $sql_data[TOPICS_TABLE] .= ', topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : ''); - $next_post_id = (int) $row['post_id']; + + $sql_data[TOPICS_TABLE] = $db->sql_build_array('UPDATE', array( + 'topic_poster' => (int) $row['poster_id'], + 'topic_first_post_id' => (int) $row['post_id'], + 'topic_first_poster_colour' => $row['user_colour'], + 'topic_first_poster_name' => ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'], + 'topic_time' => (int) $row['post_time'], + )); break; case 'delete_last_post': - if ($data['topic_type'] != POST_GLOBAL) - { - $sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : ''; - } - - $update_sql = update_post_information('forum', $forum_id, true); - if (sizeof($update_sql)) + if (!$is_soft) { - $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : ''; - $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]); - } + // Update last post information when hard deleting. Soft delete already did that by itself. + $update_sql = update_post_information('forum', $forum_id, true); + if (sizeof($update_sql)) + { + $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . implode(', ', $update_sql[$forum_id]); + } - $sql_data[TOPICS_TABLE] = 'topic_bumped = 0, topic_bumper = 0, topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : ''); + $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_bumped = 0, topic_bumper = 0'; - $update_sql = update_post_information('topic', $topic_id, true); - if (sizeof($update_sql)) - { - $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]); - $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]); + $update_sql = update_post_information('topic', $topic_id, true); + if (!empty($update_sql)) + { + $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]); + $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]); + } } - else + + if (!$next_post_id) { $sql = 'SELECT MAX(post_id) as last_post_id FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id " . - ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND post_approved = 1' : ''); + WHERE topic_id = $topic_id + AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id); $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); + $next_post_id = (int) $db->sql_fetchfield('last_post_id'); $db->sql_freeresult($result); - - $next_post_id = (int) $row['last_post_id']; } break; case 'delete': $sql = 'SELECT post_id FROM ' . POSTS_TABLE . " - WHERE topic_id = $topic_id " . - ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND post_approved = 1' : '') . ' + WHERE topic_id = $topic_id + AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . ' AND post_time > ' . $data['post_time'] . ' - ORDER BY post_time ASC'; + ORDER BY post_time ASC, post_id ASC'; $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); + $next_post_id = (int) $db->sql_fetchfield('post_id'); $db->sql_freeresult($result); - - if ($data['topic_type'] != POST_GLOBAL) - { - $sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : ''; - } - - $sql_data[TOPICS_TABLE] = 'topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : ''); - $next_post_id = (int) $row['post_id']; break; } if (($post_mode == 'delete') || ($post_mode == 'delete_last_post') || ($post_mode == 'delete_first_post')) { + if (!$is_soft) + { + $phpbb_content_visibility->remove_post_from_statistic($data, $sql_data); + } + $sql = 'SELECT 1 AS has_attachments FROM ' . ATTACHMENTS_TABLE . ' WHERE topic_id = ' . $topic_id; @@ -1590,18 +1451,16 @@ function delete_post($forum_id, $topic_id, $post_id, &$data) if (!$has_attachments) { - $sql_data[TOPICS_TABLE] .= ', topic_attachment = 0'; + $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_attachment = 0'; } } -// $sql_data[USERS_TABLE] = ($data['post_postcount']) ? 'user_posts = user_posts - 1' : ''; - $db->sql_transaction('begin'); $where_sql = array( FORUMS_TABLE => "forum_id = $forum_id", TOPICS_TABLE => "topic_id = $topic_id", - USERS_TABLE => 'user_id = ' . $data['poster_id'] + USERS_TABLE => 'user_id = ' . $data['poster_id'], ); foreach ($sql_data as $table => $update_sql) @@ -1649,7 +1508,33 @@ function delete_post($forum_id, $topic_id, $post_id, &$data) */ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $update_message = true, $update_search_index = true) { - global $db, $auth, $user, $config, $phpEx, $template, $phpbb_root_path; + global $db, $auth, $user, $config, $phpEx, $template, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher; + + /** + * Modify the data for post submitting + * + * @event core.modify_submit_post_data + * @var string mode Variable containing posting mode value + * @var string subject Variable containing post subject value + * @var string username Variable containing post author name + * @var int topic_type Variable containing topic type value + * @var array poll Array with the poll data for the post + * @var array data Array with the data for the post + * @var bool update_message Flag indicating if the post will be updated + * @var bool update_search_index Flag indicating if the search index will be updated + * @since 3.1.0-a4 + */ + $vars = array( + 'mode', + 'subject', + 'username', + 'topic_type', + 'poll', + 'data', + 'update_message', + 'update_search_index', + ); + extract($phpbb_dispatcher->trigger_event('core.modify_submit_post_data', compact($vars))); // We do not handle erasing posts here if ($mode == 'delete') @@ -1671,22 +1556,22 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } else if ($mode == 'edit') { - $post_mode = ($data['topic_replies_real'] == 0) ? 'edit_topic' : (($data['topic_first_post_id'] == $data['post_id']) ? 'edit_first_post' : (($data['topic_last_post_id'] == $data['post_id']) ? 'edit_last_post' : 'edit')); + $post_mode = ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1) ? 'edit_topic' : (($data['topic_first_post_id'] == $data['post_id']) ? 'edit_first_post' : (($data['topic_last_post_id'] == $data['post_id']) ? 'edit_last_post' : 'edit')); } // First of all make sure the subject and topic title are having the correct length. // To achieve this without cutting off between special chars we convert to an array and then count the elements. - $subject = truncate_string($subject); - $data['topic_title'] = truncate_string($data['topic_title']); + $subject = truncate_string($subject, 120); + $data['topic_title'] = truncate_string($data['topic_title'], 120); // Collect some basic information about which tables and which rows to update/insert $sql_data = $topic_row = array(); $poster_id = ($mode == 'edit') ? $data['poster_id'] : (int) $user->data['user_id']; // Retrieve some additional information if not present - if ($mode == 'edit' && (!isset($data['post_approved']) || !isset($data['topic_approved']) || $data['post_approved'] === false || $data['topic_approved'] === false)) + if ($mode == 'edit' && (!isset($data['post_visibility']) || !isset($data['topic_visibility']) || $data['post_visibility'] === false || $data['topic_visibility'] === false)) { - $sql = 'SELECT p.post_approved, t.topic_type, t.topic_replies, t.topic_replies_real, t.topic_approved + $sql = 'SELECT p.post_visibility, t.topic_type, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_visibility FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p WHERE t.topic_id = p.topic_id AND p.post_id = ' . $data['post_id']; @@ -1694,26 +1579,38 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u $topic_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - $data['topic_approved'] = $topic_row['topic_approved']; - $data['post_approved'] = $topic_row['post_approved']; + $data['topic_visibility'] = $topic_row['topic_visibility']; + $data['post_visibility'] = $topic_row['post_visibility']; } - // This variable indicates if the user is able to post or put into the queue - it is used later for all code decisions regarding approval - // The variable name should be $post_approved, because it indicates if the post is approved or not - $post_approval = 1; + // This variable indicates if the user is able to post or put into the queue + $post_visibility = ITEM_APPROVED; // Check the permissions for post approval. // Moderators must go through post approval like ordinary users. if (!$auth->acl_get('f_noapprove', $data['forum_id'])) { // Post not approved, but in queue - $post_approval = 0; + $post_visibility = ITEM_UNAPPROVED; + switch ($post_mode) + { + case 'edit_first_post': + case 'edit': + case 'edit_last_post': + case 'edit_topic': + $post_visibility = ITEM_REAPPROVE; + break; + } } - // Mods are able to force approved/unapproved posts. True means the post is approved, false the post is unapproved + // MODs/Extensions are able to force any visibility on posts if (isset($data['force_approved_state'])) { - $post_approval = ($data['force_approved_state']) ? 1 : 0; + $post_visibility = (in_array((int) $data['force_approved_state'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data['force_approved_state'] : $post_visibility; + } + if (isset($data['force_visibility'])) + { + $post_visibility = (in_array((int) $data['force_visibility'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data['force_visibility'] : $post_visibility; } // Start the transaction here @@ -1725,12 +1622,12 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u case 'post': case 'reply': $sql_data[POSTS_TABLE]['sql'] = array( - 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'], + 'forum_id' => $data['forum_id'], 'poster_id' => (int) $user->data['user_id'], 'icon_id' => $data['icon_id'], 'poster_ip' => $user->ip, 'post_time' => $current_time, - 'post_approved' => $post_approval, + 'post_visibility' => $post_visibility, 'enable_bbcode' => $data['enable_bbcode'], 'enable_smilies' => $data['enable_smilies'], 'enable_magic_url' => $data['enable_urls'], @@ -1784,7 +1681,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u if ($user->data['user_id'] != $poster_id) { $log_subject = ($subject) ? $subject : $data['topic_title']; - add_log('mod', $data['forum_id'], $data['topic_id'], 'LOG_POST_EDITED', $log_subject, (!empty($username)) ? $username : $user->lang['GUEST']); + add_log('mod', $data['forum_id'], $data['topic_id'], 'LOG_POST_EDITED', $log_subject, (!empty($username)) ? $username : $user->lang['GUEST'], $data['post_edit_reason']); } if (!isset($sql_data[POSTS_TABLE]['sql'])) @@ -1793,10 +1690,11 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array( - 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'], + 'forum_id' => $data['forum_id'], 'poster_id' => $data['poster_id'], 'icon_id' => $data['icon_id'], - 'post_approved' => (!$post_approval) ? 0 : $data['post_approved'], + // We will change the visibility later + //'post_visibility' => $post_visibility, 'enable_bbcode' => $data['enable_bbcode'], 'enable_smilies' => $data['enable_smilies'], 'enable_magic_url' => $data['enable_urls'], @@ -1817,8 +1715,6 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u break; } - - $post_approved = $sql_data[POSTS_TABLE]['sql']['post_approved']; $topic_row = array(); // And the topic ladies and gentlemen @@ -1829,9 +1725,13 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u 'topic_poster' => (int) $user->data['user_id'], 'topic_time' => $current_time, 'topic_last_view_time' => $current_time, - 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'], + 'forum_id' => $data['forum_id'], 'icon_id' => $data['icon_id'], - 'topic_approved' => $post_approval, + 'topic_posts_approved' => ($post_visibility == ITEM_APPROVED) ? 1 : 0, + 'topic_posts_softdeleted' => ($post_visibility == ITEM_DELETED) ? 1 : 0, + 'topic_posts_unapproved' => ($post_visibility == ITEM_UNAPPROVED) ? 1 : 0, + 'topic_visibility' => $post_visibility, + 'topic_delete_user' => ($post_visibility != ITEM_APPROVED) ? (int) $user->data['user_id'] : 0, 'topic_title' => $subject, 'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''), 'topic_first_poster_colour' => $user->data['user_colour'], @@ -1863,31 +1763,47 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u ); } - $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_approval) ? ', user_posts = user_posts + 1' : ''); + $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : ''); - if ($topic_type != POST_GLOBAL) + if ($post_visibility == ITEM_APPROVED) { - if ($post_approval) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1'; - } - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_real = forum_topics_real + 1' . (($post_approval) ? ', forum_topics = forum_topics + 1' : ''); + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_approved = forum_topics_approved + 1'; + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1'; + } + else if ($post_visibility == ITEM_UNAPPROVED) + { + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_unapproved = forum_topics_unapproved + 1'; + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1'; + } + else if ($post_visibility == ITEM_DELETED) + { + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_softdeleted = forum_topics_softdeleted + 1'; + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1'; } break; case 'reply': $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_view_time = ' . $current_time . ', - topic_replies_real = topic_replies_real + 1, topic_bumped = 0, topic_bumper = 0' . - (($post_approval) ? ', topic_replies = topic_replies + 1' : '') . + (($post_visibility == ITEM_APPROVED) ? ', topic_posts_approved = topic_posts_approved + 1' : '') . + (($post_visibility == ITEM_UNAPPROVED) ? ', topic_posts_unapproved = topic_posts_unapproved + 1' : '') . + (($post_visibility == ITEM_DELETED) ? ', topic_posts_softdeleted = topic_posts_softdeleted + 1' : '') . ((!empty($data['attachment_data']) || (isset($data['topic_attachment']) && $data['topic_attachment'])) ? ', topic_attachment = 1' : ''); - $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_approval) ? ', user_posts = user_posts + 1' : ''); + $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : ''); - if ($post_approval && $topic_type != POST_GLOBAL) + if ($post_visibility == ITEM_APPROVED) + { + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1'; + } + else if ($post_visibility == ITEM_UNAPPROVED) { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1'; + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1'; + } + else if ($post_visibility == ITEM_DELETED) + { + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1'; } break; @@ -1909,9 +1825,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } $sql_data[TOPICS_TABLE]['sql'] = array( - 'forum_id' => ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id'], + 'forum_id' => $data['forum_id'], 'icon_id' => $data['icon_id'], - 'topic_approved' => (!$post_approval) ? 0 : $data['topic_approved'], 'topic_title' => $subject, 'topic_first_poster_name' => $username, 'topic_type' => $topic_type, @@ -1926,59 +1841,33 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u 'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : (isset($data['topic_attachment']) ? $data['topic_attachment'] : 0), ); - // Correctly set back the topic replies and forum posts... only if the topic was approved before and now gets disapproved - if (!$post_approval && $data['topic_approved']) - { - // Do we need to grab some topic informations? - if (!sizeof($topic_row)) - { - $sql = 'SELECT topic_type, topic_replies, topic_replies_real, topic_approved - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $data['topic_id']; - $result = $db->sql_query($sql); - $topic_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - // If this is the only post remaining we do not need to decrement topic_replies. - // Also do not decrement if first post - then the topic_replies will not be adjusted if approving the topic again. - - // If this is an edited topic or the first post the topic gets completely disapproved later on... - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics = forum_topics - 1'; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - ' . ($topic_row['topic_replies'] + 1); - - set_config_count('num_topics', -1, true); - set_config_count('num_posts', ($topic_row['topic_replies'] + 1) * (-1), true); - - // Only decrement this post, since this is the one non-approved now - if ($auth->acl_get('f_postcount', $data['forum_id'])) - { - $sql_data[USERS_TABLE]['stat'][] = 'user_posts = user_posts - 1'; - } - } - - break; - - case 'edit': - case 'edit_last_post': - - // Correctly set back the topic replies and forum posts... but only if the post was approved before. - if (!$post_approval && $data['post_approved']) - { - $sql_data[TOPICS_TABLE]['stat'][] = 'topic_replies = topic_replies - 1, topic_last_view_time = ' . $current_time; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - 1'; - - set_config_count('num_posts', -1, true); - - if ($auth->acl_get('f_postcount', $data['forum_id'])) - { - $sql_data[USERS_TABLE]['stat'][] = 'user_posts = user_posts - 1'; - } - } - break; } + /** + * Modify sql query data for post submitting + * + * @event core.submit_post_modify_sql_data + * @var array data Array with the data for the post + * @var array poll Array with the poll data for the post + * @var string post_mode Variable containing posting mode value + * @var bool sql_data Array with the data for the posting SQL query + * @var string subject Variable containing post subject value + * @var int topic_type Variable containing topic type value + * @var string username Variable containing post author name + * @since 3.1.3-RC1 + */ + $vars = array( + 'data', + 'poll', + 'post_mode', + 'sql_data', + 'subject', + 'topic_type', + 'username', + ); + extract($phpbb_dispatcher->trigger_event('core.submit_post_modify_sql_data', compact($vars))); + // Submit new topic if ($post_mode == 'post') { @@ -2000,83 +1889,49 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u if ($post_mode == 'reply') { $sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array( - 'topic_id' => $data['topic_id']) - ); + 'topic_id' => $data['topic_id'], + )); } $sql = 'INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data[POSTS_TABLE]['sql']); $db->sql_query($sql); $data['post_id'] = $db->sql_nextid(); - if ($post_mode == 'post') + if ($post_mode == 'post' || $post_visibility == ITEM_APPROVED) { $sql_data[TOPICS_TABLE]['sql'] = array( - 'topic_first_post_id' => $data['post_id'], 'topic_last_post_id' => $data['post_id'], 'topic_last_post_time' => $current_time, - 'topic_last_poster_id' => (int) $user->data['user_id'], - 'topic_last_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''), + 'topic_last_poster_id' => $sql_data[POSTS_TABLE]['sql']['poster_id'], + 'topic_last_poster_name' => ($user->data['user_id'] == ANONYMOUS) ? $sql_data[POSTS_TABLE]['sql']['post_username'] : $user->data['username'], 'topic_last_poster_colour' => $user->data['user_colour'], 'topic_last_post_subject' => (string) $subject, ); } - unset($sql_data[POSTS_TABLE]['sql']); - } - - $make_global = false; - - // Are we globalising or unglobalising? - if ($post_mode == 'edit_first_post' || $post_mode == 'edit_topic') - { - if (!sizeof($topic_row)) + if ($post_mode == 'post') { - $sql = 'SELECT topic_type, topic_replies, topic_replies_real, topic_approved, topic_last_post_id - FROM ' . TOPICS_TABLE . ' - WHERE topic_id = ' . $data['topic_id']; - $result = $db->sql_query($sql); - $topic_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); + $sql_data[TOPICS_TABLE]['sql']['topic_first_post_id'] = $data['post_id']; } - // globalise/unglobalise? - if (($topic_row['topic_type'] != POST_GLOBAL && $topic_type == POST_GLOBAL) || ($topic_row['topic_type'] == POST_GLOBAL && $topic_type != POST_GLOBAL)) + // Update total post count and forum information + if ($post_visibility == ITEM_APPROVED) { - if (!empty($sql_data[FORUMS_TABLE]['stat']) && implode('', $sql_data[FORUMS_TABLE]['stat'])) + if ($post_mode == 'post') { - $db->sql_query('UPDATE ' . FORUMS_TABLE . ' SET ' . implode(', ', $sql_data[FORUMS_TABLE]['stat']) . ' WHERE forum_id = ' . $data['forum_id']); + set_config_count('num_topics', 1, true); } + set_config_count('num_posts', 1, true); - $make_global = true; - $sql_data[FORUMS_TABLE]['stat'] = array(); - } - - // globalise - if ($topic_row['topic_type'] != POST_GLOBAL && $topic_type == POST_GLOBAL) - { - // Decrement topic/post count - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - ' . ($topic_row['topic_replies_real'] + 1); - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_real = forum_topics_real - 1' . (($topic_row['topic_approved']) ? ', forum_topics = forum_topics - 1' : ''); - - // Update forum_ids for all posts - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET forum_id = 0 - WHERE topic_id = ' . $data['topic_id']; - $db->sql_query($sql); + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data['post_id']; + $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'"; + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . $current_time; + $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $user->data['user_id']; + $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'"; + $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'"; } - // unglobalise - else if ($topic_row['topic_type'] == POST_GLOBAL && $topic_type != POST_GLOBAL) - { - // Increment topic/post count - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + ' . ($topic_row['topic_replies_real'] + 1); - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_real = forum_topics_real + 1' . (($topic_row['topic_approved']) ? ', forum_topics = forum_topics + 1' : ''); - // Update forum_ids for all posts - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET forum_id = ' . $data['forum_id'] . ' - WHERE topic_id = ' . $data['topic_id']; - $db->sql_query($sql); - } + unset($sql_data[POSTS_TABLE]['sql']); } // Update the topics table @@ -2086,6 +1941,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u SET ' . $db->sql_build_array('UPDATE', $sql_data[TOPICS_TABLE]['sql']) . ' WHERE topic_id = ' . $data['topic_id']; $db->sql_query($sql); + + unset($sql_data[TOPICS_TABLE]['sql']); } // Update the posts table @@ -2095,6 +1952,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u SET ' . $db->sql_build_array('UPDATE', $sql_data[POSTS_TABLE]['sql']) . ' WHERE post_id = ' . $data['post_id']; $db->sql_query($sql); + + unset($sql_data[POSTS_TABLE]['sql']); } // Update Poll Tables @@ -2240,187 +2099,26 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } } - // we need to update the last forum information - // only applicable if the topic is not global and it is approved - // we also check to make sure we are not dealing with globaling the latest topic (pretty rare but still needs to be checked) - if ($topic_type != POST_GLOBAL && !$make_global && ($post_approved || !$data['post_approved'])) - { - // the last post makes us update the forum table. This can happen if... - // We make a new topic - // We reply to a topic - // We edit the last post in a topic and this post is the latest in the forum (maybe) - // We edit the only post in the topic - // We edit the first post in the topic and all the other posts are not approved - if (($post_mode == 'post' || $post_mode == 'reply') && $post_approved) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data['post_id']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . $current_time; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $user->data['user_id']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'"; - } - else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies'])) - { - // this does not _necessarily_ mean that we must update the info again, - // it just means that we might have to - $sql = 'SELECT forum_last_post_id, forum_last_post_subject - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . (int) $data['forum_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // this post is the latest post in the forum, better update - if ($row['forum_last_post_id'] == $data['post_id']) - { - // If post approved and subject changed, or poster is anonymous, we need to update the forum_last* rows - if ($post_approved && ($row['forum_last_post_subject'] !== $subject || $data['poster_id'] == ANONYMOUS)) - { - // the post's subject changed - if ($row['forum_last_post_subject'] !== $subject) - { - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_subject = \'' . $db->sql_escape($subject) . '\''; - } - - // Update the user name if poster is anonymous... just in case an admin changed it - if ($data['poster_id'] == ANONYMOUS) - { - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'"; - } - } - else if ($data['post_approved'] !== $post_approved) - { - // we need a fresh change of socks, everything has become invalidated - $sql = 'SELECT MAX(topic_last_post_id) as last_post_id - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = ' . (int) $data['forum_id'] . ' - AND topic_approved = 1'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // any posts left in this forum? - if (!empty($row['last_post_id'])) - { - $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE p.poster_id = u.user_id - AND p.post_id = ' . (int) $row['last_post_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // salvation, a post is found! jam it into the forums table - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . (int) $row['post_id']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . (int) $row['post_time']; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $row['poster_id']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'"; - } - else - { - // just our luck, the last topic in the forum has just been turned unapproved... - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = 0'; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = ''"; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = 0'; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = 0'; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = ''"; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = ''"; - } - } - } - } - } - else if ($make_global) + $first_post_has_topic_info = ($post_mode == 'edit_first_post' && + (($post_visibility == ITEM_DELETED && $data['topic_posts_softdeleted'] == 1) || + ($post_visibility == ITEM_UNAPPROVED && $data['topic_posts_unapproved'] == 1) || + ($post_visibility == ITEM_REAPPROVE && $data['topic_posts_unapproved'] == 1) || + ($post_visibility == ITEM_APPROVED && $data['topic_posts_approved'] == 1))); + // Fix the post's and topic's visibility and first/last post information, when the post is edited + if (($post_mode != 'post' && $post_mode != 'reply') && $data['post_visibility'] != $post_visibility) { - // somebody decided to be a party pooper, we must recalculate the whole shebang (maybe) - $sql = 'SELECT forum_last_post_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . (int) $data['forum_id']; - $result = $db->sql_query($sql); - $forum_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); + // If the post was not approved, it could also be the starter, + // so we sync the starter after approving/restoring, to ensure that the stats are correct + // Same applies for the last post + $is_starter = ($post_mode == 'edit_first_post' || $post_mode == 'edit_topic' || $data['post_visibility'] != ITEM_APPROVED); + $is_latest = ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $data['post_visibility'] != ITEM_APPROVED); - // we made a topic global, go get new data - if ($topic_row['topic_type'] != POST_GLOBAL && $topic_type == POST_GLOBAL && $forum_row['forum_last_post_id'] == $topic_row['topic_last_post_id']) - { - // we need a fresh change of socks, everything has become invalidated - $sql = 'SELECT MAX(topic_last_post_id) as last_post_id - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = ' . (int) $data['forum_id'] . ' - AND topic_approved = 1'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // any posts left in this forum? - if (!empty($row['last_post_id'])) - { - $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE p.poster_id = u.user_id - AND p.post_id = ' . (int) $row['last_post_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // salvation, a post is found! jam it into the forums table - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . (int) $row['post_id']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . (int) $row['post_time']; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $row['poster_id']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'"; - } - else - { - // just our luck, the last topic in the forum has just been globalized... - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = 0'; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = ''"; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = 0'; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = 0'; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = ''"; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = ''"; - } - } - else if ($topic_row['topic_type'] == POST_GLOBAL && $topic_type != POST_GLOBAL && $forum_row['forum_last_post_id'] < $topic_row['topic_last_post_id']) - { - // this post has a higher id, it is newer - $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE p.poster_id = u.user_id - AND p.post_id = ' . (int) $topic_row['topic_last_post_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // salvation, a post is found! jam it into the forums table - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . (int) $row['post_id']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . (int) $row['post_time']; - $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $row['poster_id']; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'"; - $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'"; - } + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + $phpbb_content_visibility->set_post_visibility($post_visibility, $data['post_id'], $data['topic_id'], $data['forum_id'], $user->data['user_id'], time(), '', $is_starter, $is_latest); } - - // topic sync time! - // simply, we update if it is a reply or the last post is edited - if ($post_approved) + else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $first_post_has_topic_info) { - // reply requires the whole thing - if ($post_mode == 'reply') - { - $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_id = ' . (int) $data['post_id']; - $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_poster_id = ' . (int) $user->data['user_id']; - $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'"; - $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_colour = '" . (($user->data['user_id'] != ANONYMOUS) ? $db->sql_escape($user->data['user_colour']) : '') . "'"; - $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'"; - $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_time = ' . (int) $current_time; - } - else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies'])) + if ($post_visibility == ITEM_APPROVED || $data['topic_visibility'] == $post_visibility) { // only the subject can be changed from edit $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'"; @@ -2430,57 +2128,44 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u { $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape($username) . "'"; } - } - } - else if (!$data['post_approved'] && ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies']))) - { - // like having the rug pulled from under us - $sql = 'SELECT MAX(post_id) as last_post_id - FROM ' . POSTS_TABLE . ' - WHERE topic_id = ' . (int) $data['topic_id'] . ' - AND post_approved = 1'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // any posts left in this forum? - if (!empty($row['last_post_id'])) - { - $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour - FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u - WHERE p.poster_id = u.user_id - AND p.post_id = ' . (int) $row['last_post_id']; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - // salvation, a post is found! jam it into the topics table - $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_id = ' . (int) $row['post_id']; - $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'"; - $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_time = ' . (int) $row['post_time']; - $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_poster_id = ' . (int) $row['poster_id']; - $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'"; - $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'"; - } - } + if ($post_visibility == ITEM_APPROVED) + { + // this does not _necessarily_ mean that we must update the info again, + // it just means that we might have to + $sql = 'SELECT forum_last_post_id, forum_last_post_subject + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . (int) $data['forum_id']; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); - // Update total post count, do not consider moderated posts/topics - if ($post_approval) - { - if ($post_mode == 'post') - { - set_config_count('num_topics', 1, true); - set_config_count('num_posts', 1, true); - } + // this post is the latest post in the forum, better update + if ($row['forum_last_post_id'] == $data['post_id'] && ($row['forum_last_post_subject'] !== $subject || $data['poster_id'] == ANONYMOUS)) + { + // the post's subject changed + if ($row['forum_last_post_subject'] !== $subject) + { + $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'"; + } - if ($post_mode == 'reply') - { - set_config_count('num_posts', 1, true); + // Update the user name if poster is anonymous... just in case a moderator changed it + if ($data['poster_id'] == ANONYMOUS) + { + $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'"; + } + } + } } } // Update forum stats - $where_sql = array(POSTS_TABLE => 'post_id = ' . $data['post_id'], TOPICS_TABLE => 'topic_id = ' . $data['topic_id'], FORUMS_TABLE => 'forum_id = ' . $data['forum_id'], USERS_TABLE => 'user_id = ' . $poster_id); + $where_sql = array( + POSTS_TABLE => 'post_id = ' . $data['post_id'], + TOPICS_TABLE => 'topic_id = ' . $data['topic_id'], + FORUMS_TABLE => 'forum_id = ' . $data['forum_id'], + USERS_TABLE => 'user_id = ' . $poster_id + ); foreach ($sql_data as $table => $update_ary) { @@ -2492,7 +2177,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } // Delete topic shadows (if any exist). We do not need a shadow topic for an global announcement - if ($make_global) + if ($topic_type == POST_GLOBAL) { $sql = 'DELETE FROM ' . TOPICS_TABLE . ' WHERE topic_moved_id = ' . $data['topic_id']; @@ -2516,27 +2201,22 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u if ($update_search_index && $data['enable_indexing']) { // Select the search method and do some additional checks to ensure it can actually be utilised - $search_type = basename($config['search_type']); - - if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } + $search_type = $config['search_type']; if (!class_exists($search_type)) { - include("{$phpbb_root_path}includes/search/$search_type.$phpEx"); + trigger_error('NO_SUCH_SEARCH_MODULE'); } $error = false; - $search = new $search_type($error); + $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user); if ($error) { trigger_error($error); } - $search->index($mode, $data['post_id'], $data['message'], $subject, $poster_id, ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']); + $search->index($mode, $data['post_id'], $data['message'], $subject, $poster_id, $data['forum_id']); } // Topic Notification, do not change if moderator is changing other users posts... @@ -2565,7 +2245,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u // Mark this topic as read // We do not use post_time here, this is intended (post_time can have a date in the past if editing a message) - markread('topic', (($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']), $data['topic_id'], time()); + markread('topic', $data['forum_id'], $data['topic_id'], time()); // if ($config['load_db_lastread'] && $user->data['is_registered']) @@ -2573,7 +2253,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u $sql = 'SELECT mark_time FROM ' . FORUMS_TRACK_TABLE . ' WHERE user_id = ' . $user->data['user_id'] . ' - AND forum_id = ' . (($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']); + AND forum_id = ' . $data['forum_id']; $result = $db->sql_query($sql); $f_mark_time = (int) $db->sql_fetchfield('mark_time'); $db->sql_freeresult($result); @@ -2586,38 +2266,135 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered']) { // Update forum info - if ($topic_type == POST_GLOBAL) - { - $sql = 'SELECT MAX(topic_last_post_time) as forum_last_post_time - FROM ' . TOPICS_TABLE . ' - WHERE forum_id = 0'; - } - else - { - $sql = 'SELECT forum_last_post_time - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $data['forum_id']; - } + $sql = 'SELECT forum_last_post_time + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . $data['forum_id']; $result = $db->sql_query($sql); $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time'); $db->sql_freeresult($result); - update_forum_tracking_info((($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']), $forum_last_post_time, $f_mark_time, false); + update_forum_tracking_info($data['forum_id'], $forum_last_post_time, $f_mark_time, false); } + // If a username was supplied or the poster is a guest, we will use the supplied username. + // Doing it this way we can use "...post by guest-username..." in notifications when + // "guest-username" is supplied or ommit the username if it is not. + $username = ($username !== '' || !$user->data['is_registered']) ? $username : $user->data['username']; + // Send Notifications - if (($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_approval) + $notification_data = array_merge($data, array( + 'topic_title' => (isset($data['topic_title'])) ? $data['topic_title'] : $subject, + 'post_username' => $username, + 'poster_id' => $poster_id, + 'post_text' => $data['message'], + 'post_time' => $current_time, + 'post_subject' => $subject, + )); + + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + if ($post_visibility == ITEM_APPROVED) { - // If a username was supplied or the poster is a guest, we will use the supplied username. - // Doing it this way we can use "...post by guest-username..." in notifications when - // "guest-username" is supplied or ommit the username if it is not. - $username = ($username !== '' || !$user->data['is_registered']) ? $username : $user->data['username']; - user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id'], $username); + switch ($mode) + { + case 'post': + $phpbb_notifications->add_notifications(array( + 'notification.type.quote', + 'notification.type.topic', + ), $notification_data); + break; + + case 'reply': + case 'quote': + $phpbb_notifications->add_notifications(array( + 'notification.type.quote', + 'notification.type.bookmark', + 'notification.type.post', + ), $notification_data); + break; + + case 'edit_topic': + case 'edit_first_post': + case 'edit': + case 'edit_last_post': + $phpbb_notifications->update_notifications(array( + 'notification.type.quote', + 'notification.type.bookmark', + 'notification.type.topic', + 'notification.type.post', + ), $notification_data); + break; + } + } + else if ($post_visibility == ITEM_UNAPPROVED) + { + switch ($mode) + { + case 'post': + $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data); + break; + + case 'reply': + case 'quote': + $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data); + break; + + case 'edit_topic': + case 'edit_first_post': + case 'edit': + case 'edit_last_post': + // Nothing to do here + break; + } + } + else if ($post_visibility == ITEM_REAPPROVE) + { + switch ($mode) + { + case 'edit_topic': + case 'edit_first_post': + $phpbb_notifications->add_notifications('notification.type.topic_in_queue', $notification_data); + + // Delete the approve_post notification so we can notify the user again, + // when his post got reapproved + $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']); + break; + + case 'edit': + case 'edit_last_post': + $phpbb_notifications->add_notifications('notification.type.post_in_queue', $notification_data); + + // Delete the approve_post notification so we can notify the user again, + // when his post got reapproved + $phpbb_notifications->delete_notifications('notification.type.approve_post', $notification_data['post_id']); + break; + + case 'post': + case 'reply': + case 'quote': + // Nothing to do here + break; + } + } + else if ($post_visibility == ITEM_DELETED) + { + switch ($mode) + { + case 'post': + case 'reply': + case 'quote': + case 'edit_topic': + case 'edit_first_post': + case 'edit': + case 'edit_last_post': + // Nothing to do here + break; + } } $params = $add_anchor = ''; - if ($post_approval) + if ($post_visibility == ITEM_APPROVED) { $params .= '&t=' . $data['topic_id']; @@ -2635,6 +2412,44 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u $url = (!$params) ? "{$phpbb_root_path}viewforum.$phpEx" : "{$phpbb_root_path}viewtopic.$phpEx"; $url = append_sid($url, 'f=' . $data['forum_id'] . $params) . $add_anchor; + /** + * This event is used for performing actions directly after a post or topic + * has been submitted. When a new topic is posted, the topic ID is + * available in the $data array. + * + * The only action that can be done by altering data made available to this + * event is to modify the return URL ($url). + * + * @event core.submit_post_end + * @var string mode Variable containing posting mode value + * @var string subject Variable containing post subject value + * @var string username Variable containing post author name + * @var int topic_type Variable containing topic type value + * @var array poll Array with the poll data for the post + * @var array data Array with the data for the post + * @var int post_visibility Variable containing up to date post visibility + * @var bool update_message Flag indicating if the post will be updated + * @var bool update_search_index Flag indicating if the search index will be updated + * @var string url The "Return to topic" URL + * + * @since 3.1.0-a3 + * @change 3.1.0-RC3 Added vars mode, subject, username, topic_type, + * poll, update_message, update_search_index + */ + $vars = array( + 'mode', + 'subject', + 'username', + 'topic_type', + 'poll', + 'data', + 'post_visibility', + 'update_message', + 'update_search_index', + 'url', + ); + extract($phpbb_dispatcher->trigger_event('core.submit_post_end', compact($vars))); + return $url; } @@ -2740,4 +2555,136 @@ function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false) return $url; } -?>
\ No newline at end of file +/** +* Show upload popup (progress bar) +*/ +function phpbb_upload_popup($forum_style = 0) +{ + global $template, $user; + + ($forum_style) ? $user->setup('posting', $forum_style) : $user->setup('posting'); + + page_header($user->lang['PROGRESS_BAR']); + + $template->set_filenames(array( + 'popup' => 'posting_progress_bar.html') + ); + + $template->assign_vars(array( + 'PROGRESS_BAR' => $user->img('upload_bar', $user->lang['UPLOAD_IN_PROGRESS'])) + ); + + $template->display('popup'); + + garbage_collection(); + exit_handler(); +} + +/** +* Do the various checks required for removing posts as well as removing it +*/ +function phpbb_handle_post_delete($forum_id, $topic_id, $post_id, &$post_data, $is_soft = false, $delete_reason = '') +{ + global $user, $auth, $config, $request; + global $phpbb_root_path, $phpEx; + + $perm_check = ($is_soft) ? 'softdelete' : 'delete'; + + // If moderator removing post or user itself removing post, present a confirmation screen + if ($auth->acl_get("m_$perm_check", $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get("f_$perm_check", $forum_id) && $post_id == $post_data['topic_last_post_id'] && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time']))) + { + $s_hidden_fields = array( + 'p' => $post_id, + 'f' => $forum_id, + 'mode' => ($is_soft) ? 'soft_delete' : 'delete', + ); + + if (confirm_box(true)) + { + $data = array( + 'topic_first_post_id' => $post_data['topic_first_post_id'], + 'topic_last_post_id' => $post_data['topic_last_post_id'], + 'topic_posts_approved' => $post_data['topic_posts_approved'], + 'topic_posts_unapproved' => $post_data['topic_posts_unapproved'], + 'topic_posts_softdeleted' => $post_data['topic_posts_softdeleted'], + 'topic_visibility' => $post_data['topic_visibility'], + 'topic_type' => $post_data['topic_type'], + 'post_visibility' => $post_data['post_visibility'], + 'post_reported' => $post_data['post_reported'], + 'post_time' => $post_data['post_time'], + 'poster_id' => $post_data['poster_id'], + 'post_postcount' => $post_data['post_postcount'], + ); + + $next_post_id = delete_post($forum_id, $topic_id, $post_id, $data, $is_soft, $delete_reason); + $post_username = ($post_data['poster_id'] == ANONYMOUS && !empty($post_data['post_username'])) ? $post_data['post_username'] : $post_data['username']; + + if ($next_post_id === false) + { + add_log('mod', $forum_id, $topic_id, (($is_soft) ? 'LOG_SOFTDELETE_TOPIC' : 'LOG_DELETE_TOPIC'), $post_data['topic_title'], $post_username, $delete_reason); + + $meta_info = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id"); + $message = $user->lang['POST_DELETED']; + } + else + { + add_log('mod', $forum_id, $topic_id, (($is_soft) ? 'LOG_SOFTDELETE_POST' : 'LOG_DELETE_POST'), $post_data['post_subject'], $post_username, $delete_reason); + + $meta_info = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&p=$next_post_id") . "#p$next_post_id"; + $message = $user->lang['POST_DELETED']; + + if (!$request->is_ajax()) + { + $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $meta_info . '">', '</a>'); + } + } + + meta_refresh(3, $meta_info); + if (!$request->is_ajax()) + { + $message .= '<br /><br />' . $user->lang('RETURN_FORUM', '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) . '">', '</a>'); + } + trigger_error($message); + } + else + { + global $user, $template, $request; + + $can_delete = $auth->acl_get('m_delete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_delete', $forum_id)); + $can_softdelete = $auth->acl_get('m_softdelete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_softdelete', $forum_id)); + + $template->assign_vars(array( + 'S_SOFTDELETED' => $post_data['post_visibility'] == ITEM_DELETED, + 'S_CHECKED_PERMANENT' => $request->is_set_post('delete_permanent') ? ' checked="checked"' : '', + 'S_ALLOWED_DELETE' => $can_delete, + 'S_ALLOWED_SOFTDELETE' => $can_softdelete, + )); + + $l_confirm = 'DELETE_POST'; + if ($post_data['post_visibility'] == ITEM_DELETED) + { + $l_confirm .= '_PERMANENTLY'; + $s_hidden_fields['delete_permanent'] = '1'; + } + else if (!$can_softdelete) + { + $s_hidden_fields['delete_permanent'] = '1'; + } + + confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html'); + } + } + + // If we are here the user is not able to delete - present the correct error message + if ($post_data['poster_id'] != $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id)) + { + trigger_error('DELETE_OWN_POSTS'); + } + + if ($post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && $post_id != $post_data['topic_last_post_id']) + { + trigger_error('CANNOT_DELETE_REPLIED'); + } + + trigger_error('USER_CANNOT_DELETE'); +} diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php index c99f40d453..8e1561b842 100644 --- a/phpBB/includes/functions_privmsgs.php +++ b/phpBB/includes/functions_privmsgs.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,8 @@ if (!defined('IN_PHPBB')) Ability to simply add own rules by doing three things: 1) Add an appropriate constant 2) Add a new check array to the global_privmsgs_rules variable and the condition array (if one is required) - 3) Add a new language variable to ucp.php + 3) Implement the rule logic in the check_rule() function + 4) Add a new language variable to ucp.php The user is then able to select the new rule. It will be checked against and handled as specified. To add new actions (yes, checks can be added here too) to the rule management, the core code has to be modified. @@ -57,42 +61,42 @@ define('CHECK_TO', 5); */ $global_privmsgs_rules = array( CHECK_SUBJECT => array( - RULE_IS_LIKE => array('check0' => 'message_subject', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0})'), - RULE_IS_NOT_LIKE => array('check0' => 'message_subject', 'function' => '!(preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0}))'), - RULE_IS => array('check0' => 'message_subject', 'function' => '{CHECK0} == {STRING}'), - RULE_IS_NOT => array('check0' => 'message_subject', 'function' => '{CHECK0} != {STRING}'), - RULE_BEGINS_WITH => array('check0' => 'message_subject', 'function' => 'preg_match("/^" . preg_quote({STRING}, "/") . "/i", {CHECK0})'), - RULE_ENDS_WITH => array('check0' => 'message_subject', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "$/i", {CHECK0})'), + RULE_IS_LIKE => array('check0' => 'message_subject'), + RULE_IS_NOT_LIKE => array('check0' => 'message_subject'), + RULE_IS => array('check0' => 'message_subject'), + RULE_IS_NOT => array('check0' => 'message_subject'), + RULE_BEGINS_WITH => array('check0' => 'message_subject'), + RULE_ENDS_WITH => array('check0' => 'message_subject'), ), CHECK_SENDER => array( - RULE_IS_LIKE => array('check0' => 'username', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0})'), - RULE_IS_NOT_LIKE => array('check0' => 'username', 'function' => '!(preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0}))'), - RULE_IS => array('check0' => 'username', 'function' => '{CHECK0} == {STRING}'), - RULE_IS_NOT => array('check0' => 'username', 'function' => '{CHECK0} != {STRING}'), - RULE_BEGINS_WITH => array('check0' => 'username', 'function' => 'preg_match("/^" . preg_quote({STRING}, "/") . "/i", {CHECK0})'), - RULE_ENDS_WITH => array('check0' => 'username', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "$/i", {CHECK0})'), - RULE_IS_FRIEND => array('check0' => 'friend', 'function' => '{CHECK0} == 1'), - RULE_IS_FOE => array('check0' => 'foe', 'function' => '{CHECK0} == 1'), - RULE_IS_USER => array('check0' => 'author_id', 'function' => '{CHECK0} == {USER_ID}'), - RULE_IS_GROUP => array('check0' => 'author_in_group', 'function' => 'in_array({GROUP_ID}, {CHECK0})'), + RULE_IS_LIKE => array('check0' => 'username'), + RULE_IS_NOT_LIKE => array('check0' => 'username'), + RULE_IS => array('check0' => 'username'), + RULE_IS_NOT => array('check0' => 'username'), + RULE_BEGINS_WITH => array('check0' => 'username'), + RULE_ENDS_WITH => array('check0' => 'username'), + RULE_IS_FRIEND => array('check0' => 'friend'), + RULE_IS_FOE => array('check0' => 'foe'), + RULE_IS_USER => array('check0' => 'author_id'), + RULE_IS_GROUP => array('check0' => 'author_in_group'), ), CHECK_MESSAGE => array( - RULE_IS_LIKE => array('check0' => 'message_text', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0})'), - RULE_IS_NOT_LIKE => array('check0' => 'message_text', 'function' => '!(preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0}))'), - RULE_IS => array('check0' => 'message_text', 'function' => '{CHECK0} == {STRING}'), - RULE_IS_NOT => array('check0' => 'message_text', 'function' => '{CHECK0} != {STRING}'), + RULE_IS_LIKE => array('check0' => 'message_text'), + RULE_IS_NOT_LIKE => array('check0' => 'message_text'), + RULE_IS => array('check0' => 'message_text'), + RULE_IS_NOT => array('check0' => 'message_text'), ), CHECK_STATUS => array( - RULE_ANSWERED => array('check0' => 'pm_replied', 'function' => '{CHECK0} == 1'), - RULE_FORWARDED => array('check0' => 'pm_forwarded', 'function' => '{CHECK0} == 1'), + RULE_ANSWERED => array('check0' => 'pm_replied'), + RULE_FORWARDED => array('check0' => 'pm_forwarded'), ), CHECK_TO => array( - RULE_TO_GROUP => array('check0' => 'to', 'check1' => 'bcc', 'check2' => 'user_in_group', 'function' => 'in_array("g_" . {CHECK2}, {CHECK0}) || in_array("g_" . {CHECK2}, {CHECK1})'), - RULE_TO_ME => array('check0' => 'to', 'check1' => 'bcc', 'function' => 'in_array("u_" . $user_id, {CHECK0}) || in_array("u_" . $user_id, {CHECK1})'), + RULE_TO_GROUP => array('check0' => 'to', 'check1' => 'bcc', 'check2' => 'user_in_group'), + RULE_TO_ME => array('check0' => 'to', 'check1' => 'bcc'), ) ); @@ -260,16 +264,59 @@ function check_rule(&$rules, &$rule_row, &$message_row, $user_id) $check_ary = $rules[$rule_row['rule_check']][$rule_row['rule_connection']]; - // Replace Check Literals - $evaluate = $check_ary['function']; - $evaluate = preg_replace('/{(CHECK[0-9])}/', '$message_row[$check_ary[strtolower("\1")]]', $evaluate); + $result = false; - // Replace Rule Literals - $evaluate = preg_replace('/{(STRING|USER_ID|GROUP_ID)}/', '$rule_row["rule_" . strtolower("\1")]', $evaluate); + $check0 = $message_row[$check_ary['check0']]; - // Evil Statement - $result = false; - eval('$result = (' . $evaluate . ') ? true : false;'); + switch ($rule_row['rule_connection']) + { + case RULE_IS_LIKE: + $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0); + break; + + case RULE_IS_NOT_LIKE: + $result = !preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0); + break; + + case RULE_IS: + $result = ($check0 == $rule_row['rule_string']); + break; + + case RULE_IS_NOT: + $result = ($check0 != $rule_row['rule_string']); + break; + + case RULE_BEGINS_WITH: + $result = preg_match("/^" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0); + break; + + case RULE_ENDS_WITH: + $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '$/i', $check0); + break; + + case RULE_IS_FRIEND: + case RULE_IS_FOE: + case RULE_ANSWERED: + case RULE_FORWARDED: + $result = ($check0 == 1); + break; + + case RULE_IS_USER: + $result = ($check0 == $rule_row['rule_user_id']); + break; + + case RULE_IS_GROUP: + $result = in_array($rule_row['rule_group_id'], $check0); + break; + + case RULE_TO_GROUP: + $result = (in_array('g_' . $message_row[$check_ary['check2']], $check0) || in_array('g_' . $message_row[$check_ary['check2']], $message_row[$check_ary['check1']])); + break; + + case RULE_TO_ME: + $result = (in_array('u_' . $user_id, $check0) || in_array('u_' . $user_id, $message_row[$check_ary['check1']])); + break; + } if (!$result) { @@ -299,7 +346,7 @@ function check_rule(&$rules, &$rule_row, &$message_row, $user_id) $userdata = $db->sql_fetchrow($result); $db->sql_freeresult($result); - $auth2 = new auth(); + $auth2 = new \phpbb\auth\auth(); $auth2->acl($userdata); if (!$auth2->acl_get('a_') && !$auth2->acl_get('m_') && !$auth2->acl_getf_global('m_')) @@ -832,7 +879,11 @@ function update_unread_status($unread, $msg_id, $user_id, $folder_id) return; } - global $db, $user; + global $db, $user, $phpbb_container; + + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + $phpbb_notifications->mark_notifications_read('notification.type.pm', $msg_id, $user_id); $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " SET pm_unread = 0 @@ -863,6 +914,24 @@ function update_unread_status($unread, $msg_id, $user_id, $folder_id) } } +function mark_folder_read($user_id, $folder_id) +{ + global $db; + + $sql = 'SELECT msg_id + FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE folder_id = ' . ((int) $folder_id) . ' + AND user_id = ' . ((int) $user_id) . ' + AND pm_unread = 1'; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + update_unread_status(true, $row['msg_id'], $user_id, $folder_id); + } + $db->sql_freeresult($result); +} + /** * Handle all actions possible with marked messages */ @@ -937,7 +1006,7 @@ function handle_mark_actions($user_id, $mark_action) */ function delete_pm($user_id, $msg_ids, $folder_id) { - global $db, $user, $phpbb_root_path, $phpEx; + global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher; $user_id = (int) $user_id; $folder_id = (int) $folder_id; @@ -961,6 +1030,18 @@ function delete_pm($user_id, $msg_ids, $folder_id) return false; } + /** + * Get all info for PM(s) before they are deleted + * + * @event core.delete_pm_before + * @var int user_id ID of the user requested the message delete + * @var array msg_ids array of all messages to be deleted + * @var int folder_id ID of the user folder where the messages are stored + * @since 3.1.0-b5 + */ + $vars = array('user_id', 'msg_ids', 'folder_id'); + extract($phpbb_dispatcher->trigger_event('core.delete_pm_before', compact($vars))); + // Get PM Information for later deleting $sql = 'SELECT msg_id, pm_unread, pm_new FROM ' . PRIVMSGS_TO_TABLE . ' @@ -1049,6 +1130,10 @@ function delete_pm($user_id, $msg_ids, $folder_id) $user->data['user_unread_privmsg'] -= $num_unread; } + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + $phpbb_notifications->delete_notifications('notification.type.pm', array_keys($delete_rows)); + // Now we have to check which messages we can delete completely $sql = 'SELECT msg_id FROM ' . PRIVMSGS_TO_TABLE . ' @@ -1101,6 +1186,23 @@ function phpbb_delete_user_pms($user_id) return false; } + return phpbb_delete_users_pms(array($user_id)); +} + +/** +* Delete all PM(s) for given users and delete the ones without references +* +* @param array $user_ids IDs of the users whose private messages we want to delete +* +* @return boolean False if there were no pms found, true otherwise. +*/ +function phpbb_delete_users_pms($user_ids) +{ + global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container; + + $user_id_sql = $db->sql_in_set('user_id', $user_ids); + $author_id_sql = $db->sql_in_set('author_id', $user_ids); + // Get PM Information for later deleting // The two queries where split, so we can use our indexes $undelivered_msg = $delete_ids = array(); @@ -1108,7 +1210,7 @@ function phpbb_delete_user_pms($user_id) // Part 1: get PMs the user received $sql = 'SELECT msg_id FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE user_id = ' . $user_id; + WHERE ' . $user_id_sql; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -1118,12 +1220,12 @@ function phpbb_delete_user_pms($user_id) } $db->sql_freeresult($result); - // Part 2: get PMs the user sent, but have yet to be received - // We cannot simply delete them. First we have to check, + // Part 2: get PMs the users sent, but are yet to be received. + // We cannot simply delete them. First we have to check // whether another user already received and read the message. $sql = 'SELECT msg_id FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE author_id = ' . $user_id . ' + WHERE ' . $author_id_sql . ' AND folder_id = ' . PRIVMSGS_NO_BOX; $result = $db->sql_query($sql); @@ -1141,6 +1243,8 @@ function phpbb_delete_user_pms($user_id) $db->sql_transaction('begin'); + $phpbb_notifications = $phpbb_container->get('notification_manager'); + if (!empty($undelivered_msg)) { // A pm is delivered, if for any recipient the message was moved @@ -1149,7 +1253,7 @@ function phpbb_delete_user_pms($user_id) // received them. $sql = 'SELECT msg_id FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE author_id = ' . $user_id . ' + WHERE ' . $author_id_sql . ' AND folder_id <> ' . PRIVMSGS_NO_BOX . ' AND folder_id <> ' . PRIVMSGS_OUTBOX . ' AND folder_id <> ' . PRIVMSGS_SENTBOX; @@ -1169,7 +1273,7 @@ function phpbb_delete_user_pms($user_id) // Count the messages we delete, so we can correct the user pm data $sql = 'SELECT user_id, COUNT(msg_id) as num_undelivered_privmsgs FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE author_id = ' . $user_id . ' + WHERE ' . $author_id_sql . ' AND folder_id = ' . PRIVMSGS_NO_BOX . ' AND ' . $db->sql_in_set('msg_id', array_merge($undelivered_msg, $delivered_msg)) . ' GROUP BY user_id'; @@ -1209,6 +1313,8 @@ function phpbb_delete_user_pms($user_id) WHERE folder_id = ' . PRIVMSGS_NO_BOX . ' AND ' . $db->sql_in_set('msg_id', $delivered_msg); $db->sql_query($sql); + + $phpbb_notifications->delete_notifications('notification.type.pm', $delivered_msg); } if (!empty($undelivered_msg)) @@ -1220,6 +1326,8 @@ function phpbb_delete_user_pms($user_id) $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . ' WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg); $db->sql_query($sql); + + $phpbb_notifications->delete_notifications('notification.type.pm', $undelivered_msg); } } @@ -1227,12 +1335,12 @@ function phpbb_delete_user_pms($user_id) $sql = 'UPDATE ' . USERS_TABLE . ' SET user_new_privmsg = 0, user_unread_privmsg = 0 - WHERE user_id = ' . $user_id; + WHERE ' . $user_id_sql; $db->sql_query($sql); // Delete private message data of the user $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' - WHERE user_id = ' . (int) $user_id; + WHERE ' . $user_id_sql; $db->sql_query($sql); if (!empty($delete_ids)) @@ -1262,6 +1370,8 @@ function phpbb_delete_user_pms($user_id) $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . ' WHERE ' . $db->sql_in_set('msg_id', $delete_ids); $db->sql_query($sql); + + $phpbb_notifications->delete_notifications('notification.type.pm', $delete_ids); } } @@ -1269,12 +1379,12 @@ function phpbb_delete_user_pms($user_id) // This way users are still able to read messages from users being removed $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' SET author_id = ' . ANONYMOUS . ' - WHERE author_id = ' . $user_id; + WHERE ' . $author_id_sql; $db->sql_query($sql); $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' SET author_id = ' . ANONYMOUS . ' - WHERE author_id = ' . $user_id; + WHERE ' . $author_id_sql; $db->sql_query($sql); $db->sql_transaction('commit'); @@ -1305,9 +1415,9 @@ function rebuild_header($check_ary) $_types = array('u', 'g'); foreach ($_types as $type) { - if (sizeof($$type)) + if (sizeof(${$type})) { - foreach ($$type as $id) + foreach (${$type} as $id) { $address[$type][$id] = $check_type; } @@ -1481,10 +1591,10 @@ function get_folder_status($folder_id, $folder) 'cur' => $folder['num_messages'], 'remaining' => ($user->data['message_limit']) ? $user->data['message_limit'] - $folder['num_messages'] : 0, 'max' => $user->data['message_limit'], - 'percent' => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? round(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0, + 'percent' => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? floor(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0, ); - $return['message'] = sprintf($user->lang['FOLDER_STATUS_MSG'], $return['percent'], $return['cur'], $return['max']); + $return['message'] = $user->lang('FOLDER_STATUS_MSG', $user->lang('MESSAGES_COUNT', (int) $return['max']), $return['cur'], $return['percent']); return $return; } @@ -1498,7 +1608,7 @@ function get_folder_status($folder_id, $folder) */ function submit_pm($mode, $subject, &$data, $put_in_outbox = true) { - global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path; + global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher; // We do not handle erasing pms here if ($mode == 'delete') @@ -1508,6 +1618,18 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true) $current_time = time(); + /** + * Get all parts of the PM that are to be submited to the DB. + * + * @event core.submit_pm_before + * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit + * @var string subject Subject of the private message + * @var array data The whole row data of the PM. + * @since 3.1.0-b3 + */ + $vars = array('mode', 'subject', 'data'); + extract($phpbb_dispatcher->trigger_event('core.submit_pm_before', compact($vars))); + // Collect some basic information about which tables and which rows to update/insert $sql_data = array(); $root_level = 0; @@ -1798,95 +1920,36 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true) $db->sql_transaction('commit'); // Send Notifications - if ($mode != 'edit') - { - pm_notification($mode, $data['from_username'], $recipients, $subject, $data['message'], $data['msg_id']); - } - - return $data['msg_id']; -} - -/** -* PM Notification -*/ -function pm_notification($mode, $author, $recipients, $subject, $message, $msg_id) -{ - global $db, $user, $config, $phpbb_root_path, $phpEx, $auth; - - $subject = censor_text($subject); - - // Exclude guests, current user and banned users from notifications - unset($recipients[ANONYMOUS], $recipients[$user->data['user_id']]); - - if (!sizeof($recipients)) - { - return; - } - - if (!function_exists('phpbb_get_banned_user_ids')) - { - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - $banned_users = phpbb_get_banned_user_ids(array_keys($recipients)); - $recipients = array_diff(array_keys($recipients), $banned_users); - - if (!sizeof($recipients)) - { - return; - } - - $sql = 'SELECT user_id, username, user_email, user_lang, user_notify_pm, user_notify_type, user_jabber - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $recipients); - $result = $db->sql_query($sql); + $pm_data = array_merge($data, array( + 'message_subject' => $subject, + 'recipients' => $recipients, + )); - $msg_list_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['user_notify_pm'] == 1 && trim($row['user_email'])) - { - $msg_list_ary[] = array( - 'method' => $row['user_notify_type'], - 'email' => $row['user_email'], - 'jabber' => $row['user_jabber'], - 'name' => $row['username'], - 'lang' => $row['user_lang'] - ); - } - } - $db->sql_freeresult($result); + $phpbb_notifications = $phpbb_container->get('notification_manager'); - if (!sizeof($msg_list_ary)) + if ($mode == 'edit') { - return; + $phpbb_notifications->update_notifications('notification.type.pm', $pm_data); } - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $messenger = new messenger(); - - foreach ($msg_list_ary as $pos => $addr) + else { - $messenger->template('privmsg_notify', $addr['lang']); - - $messenger->to($addr['email'], $addr['name']); - $messenger->im($addr['jabber'], $addr['name']); - - $messenger->assign_vars(array( - 'SUBJECT' => htmlspecialchars_decode($subject), - 'AUTHOR_NAME' => htmlspecialchars_decode($author), - 'USERNAME' => htmlspecialchars_decode($addr['name']), - - 'U_INBOX' => generate_board_url() . "/ucp.$phpEx?i=pm&folder=inbox", - 'U_VIEW_MESSAGE' => generate_board_url() . "/ucp.$phpEx?i=pm&mode=view&p=$msg_id", - )); - - $messenger->send($addr['method']); + $phpbb_notifications->add_notifications('notification.type.pm', $pm_data); } - unset($msg_list_ary); - $messenger->save_queue(); + /** + * Get PM message ID after submission to DB + * + * @event core.submit_pm_after + * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit + * @var string subject Subject of the private message + * @var array data The whole row data of the PM. + * @var array pm_data The data sent to notification class + * @since 3.1.0-b5 + */ + $vars = array('mode', 'subject', 'data', 'pm_data'); + extract($phpbb_dispatcher->trigger_event('core.submit_pm_after', compact($vars))); - unset($messenger); + return $data['msg_id']; } /** @@ -1894,7 +1957,7 @@ function pm_notification($mode, $author, $recipients, $subject, $message, $msg_i */ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false) { - global $db, $user, $config, $template, $phpbb_root_path, $phpEx, $auth, $bbcode; + global $db, $user, $config, $template, $phpbb_root_path, $phpEx, $auth; // Select all receipts and the author from the pm we currently view, to only display their pm-history $sql = 'SELECT author_id, user_id @@ -1946,7 +2009,6 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode $title = $row['message_subject']; $rowset = array(); - $bbcode_bitfield = ''; $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm') . '&folder='; do @@ -1962,7 +2024,6 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode else { $rowset[$row['msg_id']] = $row; - $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']); } } while ($row = $db->sql_fetchrow($result)); @@ -1973,16 +2034,6 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode return false; } - // Instantiate BBCode class - if ((empty($bbcode) || $bbcode === false) && $bbcode_bitfield !== '') - { - if (!class_exists('bbcode')) - { - include($phpbb_root_path . 'includes/bbcode.' . $phpEx); - } - $bbcode = new bbcode(base64_encode($bbcode_bitfield)); - } - $title = censor_text($title); $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm'); @@ -2014,13 +2065,10 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode $decoded_message = bbcode_nl2br($decoded_message); } - if ($row['bbcode_bitfield']) - { - $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']); - } + $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0); + $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0); - $message = bbcode_nl2br($message); - $message = smiley_text($message, !$row['enable_smilies']); + $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false); $subject = censor_text($subject); @@ -2040,7 +2088,7 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode 'SUBJECT' => $subject, 'SENT_DATE' => $user->format_date($row['message_time']), 'MESSAGE' => $message, - 'FOLDER' => implode(', ', $row['folder']), + 'FOLDER' => implode($user->lang['COMMA_SEPARATOR'], $row['folder']), 'DECODED_MESSAGE' => $decoded_message, 'S_CURRENT_MSG' => ($row['msg_id'] == $msg_id), @@ -2176,5 +2224,3 @@ function get_recipient_strings($pm_by_id) return $address_list; } - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php deleted file mode 100644 index a2c0656ca4..0000000000 --- a/phpBB/includes/functions_profile_fields.php +++ /dev/null @@ -1,1185 +0,0 @@ -<?php -/** -* -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Custom Profile Fields -* @package phpBB3 -*/ -class custom_profile -{ - var $profile_types = array(FIELD_INT => 'int', FIELD_STRING => 'string', FIELD_TEXT => 'text', FIELD_BOOL => 'bool', FIELD_DROPDOWN => 'dropdown', FIELD_DATE => 'date'); - var $profile_cache = array(); - var $options_lang = array(); - - /** - * Assign editable fields to template, mode can be profile (for profile change) or register (for registration) - * Called by ucp_profile and ucp_register - * @access public - */ - function generate_profile_fields($mode, $lang_id) - { - global $db, $template, $auth; - - $sql_where = ''; - switch ($mode) - { - case 'register': - // If the field is required we show it on the registration page - $sql_where .= ' AND f.field_show_on_reg = 1'; - break; - - case 'profile': - // Show hidden fields to moderators/admins - if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) - { - $sql_where .= ' AND f.field_show_profile = 1'; - } - break; - - default: - trigger_error('Wrong profile mode specified', E_USER_ERROR); - break; - } - - $sql = 'SELECT l.*, f.* - FROM ' . PROFILE_LANG_TABLE . ' l, ' . PROFILE_FIELDS_TABLE . " f - WHERE f.field_active = 1 - $sql_where - AND l.lang_id = $lang_id - AND l.field_id = f.field_id - ORDER BY f.field_order"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - // Return templated field - $tpl_snippet = $this->process_field_row('change', $row); - - // Some types are multivalue, we can't give them a field_id as we would not know which to pick - $type = (int) $row['field_type']; - - $template->assign_block_vars('profile_fields', array( - 'LANG_NAME' => $row['lang_name'], - 'LANG_EXPLAIN' => $row['lang_explain'], - 'FIELD' => $tpl_snippet, - 'FIELD_ID' => ($type == FIELD_DATE || ($type == FIELD_BOOL && $row['field_length'] == '1')) ? '' : 'pf_' . $row['field_ident'], - 'S_REQUIRED' => ($row['field_required']) ? true : false) - ); - } - $db->sql_freeresult($result); - } - - /** - * Validate entered profile field data - * @access public - */ - function validate_profile_field($field_type, &$field_value, $field_data) - { - switch ($field_type) - { - case FIELD_DATE: - $field_validate = explode('-', $field_value); - - $day = (isset($field_validate[0])) ? (int) $field_validate[0] : 0; - $month = (isset($field_validate[1])) ? (int) $field_validate[1] : 0; - $year = (isset($field_validate[2])) ? (int) $field_validate[2] : 0; - - if ((!$day || !$month || !$year) && !$field_data['field_required']) - { - return false; - } - - if ((!$day || !$month || !$year) && $field_data['field_required']) - { - return 'FIELD_REQUIRED'; - } - - if ($day < 0 || $day > 31 || $month < 0 || $month > 12 || ($year < 1901 && $year > 0) || $year > gmdate('Y', time()) + 50) - { - return 'FIELD_INVALID_DATE'; - } - - if (checkdate($month, $day, $year) === false) - { - return 'FIELD_INVALID_DATE'; - } - break; - - case FIELD_BOOL: - $field_value = (bool) $field_value; - - if (!$field_value && $field_data['field_required']) - { - return 'FIELD_REQUIRED'; - } - break; - - case FIELD_INT: - if (trim($field_value) === '' && !$field_data['field_required']) - { - return false; - } - - $field_value = (int) $field_value; - - if ($field_value < $field_data['field_minlen']) - { - return 'FIELD_TOO_SMALL'; - } - else if ($field_value > $field_data['field_maxlen']) - { - return 'FIELD_TOO_LARGE'; - } - break; - - case FIELD_DROPDOWN: - $field_value = (int) $field_value; - - // retrieve option lang data if necessary - if (!isset($this->options_lang[$field_data['field_id']]) || !isset($this->options_lang[$field_data['field_id']][$field_data['lang_id']]) || !sizeof($this->options_lang[$file_data['field_id']][$field_data['lang_id']])) - { - $this->get_option_lang($field_data['field_id'], $field_data['lang_id'], FIELD_DROPDOWN, false); - } - - if (!isset($this->options_lang[$field_data['field_id']][$field_data['lang_id']][$field_value])) - { - return 'FIELD_INVALID_VALUE'; - } - - if ($field_value == $field_data['field_novalue'] && $field_data['field_required']) - { - return 'FIELD_REQUIRED'; - } - break; - - case FIELD_STRING: - case FIELD_TEXT: - if (trim($field_value) === '' && !$field_data['field_required']) - { - return false; - } - else if (trim($field_value) === '' && $field_data['field_required']) - { - return 'FIELD_REQUIRED'; - } - - if ($field_data['field_minlen'] && utf8_strlen($field_value) < $field_data['field_minlen']) - { - return 'FIELD_TOO_SHORT'; - } - else if ($field_data['field_maxlen'] && utf8_strlen($field_value) > $field_data['field_maxlen']) - { - return 'FIELD_TOO_LONG'; - } - - if (!empty($field_data['field_validation']) && $field_data['field_validation'] != '.*') - { - $field_validate = ($field_type == FIELD_STRING) ? $field_value : bbcode_nl2br($field_value); - if (!preg_match('#^' . str_replace('\\\\', '\\', $field_data['field_validation']) . '$#i', $field_validate)) - { - return 'FIELD_INVALID_CHARS'; - } - } - break; - } - - return false; - } - - /** - * Build profile cache, used for display - * @access private - */ - function build_cache() - { - global $db, $user, $auth; - - $this->profile_cache = array(); - - // Display hidden/no_view fields for admin/moderator - $sql = 'SELECT l.*, f.* - FROM ' . PROFILE_LANG_TABLE . ' l, ' . PROFILE_FIELDS_TABLE . ' f - WHERE l.lang_id = ' . $user->get_iso_lang_id() . ' - AND f.field_active = 1 ' . - ((!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) ? ' AND f.field_hide = 0 ' : '') . ' - AND f.field_no_view = 0 - AND l.field_id = f.field_id - ORDER BY f.field_order'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $this->profile_cache[$row['field_ident']] = $row; - } - $db->sql_freeresult($result); - } - - /** - * Get language entries for options and store them here for later use - */ - function get_option_lang($field_id, $lang_id, $field_type, $preview) - { - global $db; - - if ($preview) - { - $lang_options = (!is_array($this->vars['lang_options'])) ? explode("\n", $this->vars['lang_options']) : $this->vars['lang_options']; - - foreach ($lang_options as $num => $var) - { - $this->options_lang[$field_id][$lang_id][($num + 1)] = $var; - } - } - else - { - $sql = 'SELECT option_id, lang_value - FROM ' . PROFILE_FIELDS_LANG_TABLE . " - WHERE field_id = $field_id - AND lang_id = $lang_id - AND field_type = $field_type - ORDER BY option_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $this->options_lang[$field_id][$lang_id][($row['option_id'] + 1)] = $row['lang_value']; - } - $db->sql_freeresult($result); - } - } - - /** - * Submit profile field for validation - * @access public - */ - function submit_cp_field($mode, $lang_id, &$cp_data, &$cp_error) - { - global $auth, $db, $user; - - $sql_where = ''; - switch ($mode) - { - case 'register': - // If the field is required we show it on the registration page - $sql_where .= ' AND f.field_show_on_reg = 1'; - break; - - case 'profile': - // Show hidden fields to moderators/admins - if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) - { - $sql_where .= ' AND f.field_show_profile = 1'; - } - break; - - default: - trigger_error('Wrong profile mode specified', E_USER_ERROR); - break; - } - - $sql = 'SELECT l.*, f.* - FROM ' . PROFILE_LANG_TABLE . ' l, ' . PROFILE_FIELDS_TABLE . " f - WHERE l.lang_id = $lang_id - AND f.field_active = 1 - $sql_where - AND l.field_id = f.field_id - ORDER BY f.field_order"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $cp_data['pf_' . $row['field_ident']] = $this->get_profile_field($row); - $check_value = $cp_data['pf_' . $row['field_ident']]; - - if (($cp_result = $this->validate_profile_field($row['field_type'], $check_value, $row)) !== false) - { - // If not and only showing common error messages, use this one - $error = ''; - switch ($cp_result) - { - case 'FIELD_INVALID_DATE': - case 'FIELD_INVALID_VALUE': - case 'FIELD_REQUIRED': - $error = sprintf($user->lang[$cp_result], $row['lang_name']); - break; - - case 'FIELD_TOO_SHORT': - case 'FIELD_TOO_SMALL': - $error = sprintf($user->lang[$cp_result], $row['lang_name'], $row['field_minlen']); - break; - - case 'FIELD_TOO_LONG': - case 'FIELD_TOO_LARGE': - $error = sprintf($user->lang[$cp_result], $row['lang_name'], $row['field_maxlen']); - break; - - case 'FIELD_INVALID_CHARS': - switch ($row['field_validation']) - { - case '[0-9]+': - $error = sprintf($user->lang[$cp_result . '_NUMBERS_ONLY'], $row['lang_name']); - break; - - case '[\w]+': - $error = sprintf($user->lang[$cp_result . '_ALPHA_ONLY'], $row['lang_name']); - break; - - case '[\w_\+\. \-\[\]]+': - $error = sprintf($user->lang[$cp_result . '_SPACERS_ONLY'], $row['lang_name']); - break; - } - break; - } - - if ($error != '') - { - $cp_error[] = $error; - } - } - } - $db->sql_freeresult($result); - } - - /** - * Update profile field data directly - */ - function update_profile_field_data($user_id, &$cp_data) - { - global $db; - - if (!sizeof($cp_data)) - { - return; - } - - switch ($db->sql_layer) - { - case 'oracle': - case 'firebird': - case 'postgres': - $right_delim = $left_delim = '"'; - break; - - case 'sqlite': - case 'mssql': - case 'mssql_odbc': - case 'mssqlnative': - $right_delim = ']'; - $left_delim = '['; - break; - - case 'mysql': - case 'mysql4': - case 'mysqli': - $right_delim = $left_delim = '`'; - break; - } - - // use new array for the UPDATE; changes in the key do not affect the original array - $cp_data_sql = array(); - foreach ($cp_data as $key => $value) - { - // Firebird is case sensitive with delimiter - $cp_data_sql[$left_delim . (($db->sql_layer == 'firebird' || $db->sql_layer == 'oracle') ? strtoupper($key) : $key) . $right_delim] = $value; - } - - $sql = 'UPDATE ' . PROFILE_FIELDS_DATA_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $cp_data_sql) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - if (!$db->sql_affectedrows()) - { - $cp_data_sql['user_id'] = (int) $user_id; - - $db->sql_return_on_error(true); - - $sql = 'INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $cp_data_sql); - $db->sql_query($sql); - - $db->sql_return_on_error(false); - } - } - - /** - * Assign fields to template, used for viewprofile, viewtopic and memberlist (if load setting is enabled) - * This is directly connected to the user -> mode == grab is to grab the user specific fields, mode == show is for assigning the row to the template - * @access public - */ - function generate_profile_fields_template($mode, $user_id = 0, $profile_row = false) - { - global $db; - - if ($mode == 'grab') - { - if (!is_array($user_id)) - { - $user_id = array($user_id); - } - - if (!sizeof($this->profile_cache)) - { - $this->build_cache(); - } - - if (!sizeof($user_id)) - { - return array(); - } - - $sql = 'SELECT * - FROM ' . PROFILE_FIELDS_DATA_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_map('intval', $user_id)); - $result = $db->sql_query($sql); - - $field_data = array(); - while ($row = $db->sql_fetchrow($result)) - { - $field_data[$row['user_id']] = $row; - } - $db->sql_freeresult($result); - - $user_fields = array(); - - $user_ids = $user_id; - - // Go through the fields in correct order - foreach (array_keys($this->profile_cache) as $used_ident) - { - foreach ($field_data as $user_id => $row) - { - $user_fields[$user_id][$used_ident]['value'] = $row['pf_' . $used_ident]; - $user_fields[$user_id][$used_ident]['data'] = $this->profile_cache[$used_ident]; - } - - foreach ($user_ids as $user_id) - { - if (!isset($user_fields[$user_id][$used_ident]) && $this->profile_cache[$used_ident]['field_show_novalue']) - { - $user_fields[$user_id][$used_ident]['value'] = ''; - $user_fields[$user_id][$used_ident]['data'] = $this->profile_cache[$used_ident]; - } - } - } - - return $user_fields; - } - else if ($mode == 'show') - { - // $profile_row == $user_fields[$row['user_id']]; - $tpl_fields = array(); - $tpl_fields['row'] = $tpl_fields['blockrow'] = array(); - - foreach ($profile_row as $ident => $ident_ary) - { - $value = $this->get_profile_value($ident_ary); - - if ($value === NULL) - { - continue; - } - - $tpl_fields['row'] += array( - 'PROFILE_' . strtoupper($ident) . '_VALUE' => $value, - 'PROFILE_' . strtoupper($ident) . '_TYPE' => $ident_ary['data']['field_type'], - 'PROFILE_' . strtoupper($ident) . '_NAME' => $ident_ary['data']['lang_name'], - 'PROFILE_' . strtoupper($ident) . '_EXPLAIN'=> $ident_ary['data']['lang_explain'], - - 'S_PROFILE_' . strtoupper($ident) => true - ); - - $tpl_fields['blockrow'][] = array( - 'PROFILE_FIELD_VALUE' => $value, - 'PROFILE_FIELD_TYPE' => $ident_ary['data']['field_type'], - 'PROFILE_FIELD_NAME' => $ident_ary['data']['lang_name'], - 'PROFILE_FIELD_EXPLAIN' => $ident_ary['data']['lang_explain'], - - 'S_PROFILE_' . strtoupper($ident) => true - ); - } - - return $tpl_fields; - } - else - { - trigger_error('Wrong mode for custom profile', E_USER_ERROR); - } - } - - /** - * Get Profile Value for display - */ - function get_profile_value($ident_ary) - { - $value = $ident_ary['value']; - $field_type = $ident_ary['data']['field_type']; - - switch ($this->profile_types[$field_type]) - { - case 'int': - if (($value === '' || $value === null) && !$ident_ary['data']['field_show_novalue']) - { - return NULL; - } - return (int) $value; - break; - - case 'string': - case 'text': - if (!$value && !$ident_ary['data']['field_show_novalue']) - { - return NULL; - } - - $value = make_clickable($value); - $value = censor_text($value); - $value = bbcode_nl2br($value); - return $value; - break; - - // case 'datetime': - case 'date': - $date = explode('-', $value); - $day = (isset($date[0])) ? (int) $date[0] : 0; - $month = (isset($date[1])) ? (int) $date[1] : 0; - $year = (isset($date[2])) ? (int) $date[2] : 0; - - if (!$day && !$month && !$year && !$ident_ary['data']['field_show_novalue']) - { - return NULL; - } - else if ($day && $month && $year) - { - global $user; - // Date should display as the same date for every user regardless of timezone, so remove offset - // to compensate for the offset added by user::format_date() - return $user->format_date(gmmktime(0, 0, 0, $month, $day, $year) - ($user->timezone + $user->dst), $user->lang['DATE_FORMAT'], true); - } - - return $value; - break; - - case 'dropdown': - $field_id = $ident_ary['data']['field_id']; - $lang_id = $ident_ary['data']['lang_id']; - if (!isset($this->options_lang[$field_id][$lang_id])) - { - $this->get_option_lang($field_id, $lang_id, FIELD_DROPDOWN, false); - } - - if ($value == $ident_ary['data']['field_novalue'] && !$ident_ary['data']['field_show_novalue']) - { - return NULL; - } - - $value = (int) $value; - - // User not having a value assigned - if (!isset($this->options_lang[$field_id][$lang_id][$value])) - { - if ($ident_ary['data']['field_show_novalue']) - { - $value = $ident_ary['data']['field_novalue']; - } - else - { - return NULL; - } - } - - return $this->options_lang[$field_id][$lang_id][$value]; - break; - - case 'bool': - $field_id = $ident_ary['data']['field_id']; - $lang_id = $ident_ary['data']['lang_id']; - if (!isset($this->options_lang[$field_id][$lang_id])) - { - $this->get_option_lang($field_id, $lang_id, FIELD_BOOL, false); - } - - if (!$value && $ident_ary['data']['field_show_novalue']) - { - $value = $ident_ary['data']['field_default_value']; - } - - if ($ident_ary['data']['field_length'] == 1) - { - return (isset($this->options_lang[$field_id][$lang_id][(int) $value])) ? $this->options_lang[$field_id][$lang_id][(int) $value] : NULL; - } - else if (!$value) - { - return NULL; - } - else - { - return $this->options_lang[$field_id][$lang_id][(int) ($value) + 1]; - } - break; - - default: - trigger_error('Unknown profile type', E_USER_ERROR); - break; - } - } - - /** - * Get field value for registration/profile - * @access private - */ - function get_var($field_validation, &$profile_row, $default_value, $preview) - { - global $user; - - $profile_row['field_ident'] = (isset($profile_row['var_name'])) ? $profile_row['var_name'] : 'pf_' . $profile_row['field_ident']; - $user_ident = $profile_row['field_ident']; - // checkbox - set the value to "true" if it has been set to 1 - if ($profile_row['field_type'] == FIELD_BOOL && $profile_row['field_length'] == 2) - { - $value = (isset($_REQUEST[$profile_row['field_ident']]) && request_var($profile_row['field_ident'], $default_value) == 1) ? true : ((!isset($user->profile_fields[$user_ident]) || $preview) ? $default_value : $user->profile_fields[$user_ident]); - } - else if ($profile_row['field_type'] == FIELD_INT) - { - if (isset($_REQUEST[$profile_row['field_ident']])) - { - $value = ($_REQUEST[$profile_row['field_ident']] === '') ? NULL : request_var($profile_row['field_ident'], $default_value); - } - else - { - if (!$preview && array_key_exists($user_ident, $user->profile_fields) && is_null($user->profile_fields[$user_ident])) - { - $value = NULL; - } - else if (!isset($user->profile_fields[$user_ident]) || $preview) - { - $value = $default_value; - } - else - { - $value = $user->profile_fields[$user_ident]; - } - } - - return (is_null($value) || $value === '') ? '' : (int) $value; - } - else - { - $value = (isset($_REQUEST[$profile_row['field_ident']])) ? request_var($profile_row['field_ident'], $default_value, true) : ((!isset($user->profile_fields[$user_ident]) || $preview) ? $default_value : $user->profile_fields[$user_ident]); - - if (gettype($value) == 'string') - { - $value = utf8_normalize_nfc($value); - } - } - - switch ($field_validation) - { - case 'int': - return (int) $value; - break; - } - - return $value; - } - - /** - * Process int-type - * @access private - */ - function generate_int($profile_row, $preview = false) - { - global $template; - - $profile_row['field_value'] = $this->get_var('int', $profile_row, $profile_row['field_default_value'], $preview); - $template->assign_block_vars($this->profile_types[$profile_row['field_type']], array_change_key_case($profile_row, CASE_UPPER)); - } - - /** - * Process date-type - * @access private - */ - function generate_date($profile_row, $preview = false) - { - global $user, $template; - - $profile_row['field_ident'] = (isset($profile_row['var_name'])) ? $profile_row['var_name'] : 'pf_' . $profile_row['field_ident']; - $user_ident = $profile_row['field_ident']; - - $now = getdate(); - - if (!isset($_REQUEST[$profile_row['field_ident'] . '_day'])) - { - if ($profile_row['field_default_value'] == 'now') - { - $profile_row['field_default_value'] = sprintf('%2d-%2d-%4d', $now['mday'], $now['mon'], $now['year']); - } - list($day, $month, $year) = explode('-', ((!isset($user->profile_fields[$user_ident]) || $preview) ? $profile_row['field_default_value'] : $user->profile_fields[$user_ident])); - } - else - { - if ($preview && $profile_row['field_default_value'] == 'now') - { - $profile_row['field_default_value'] = sprintf('%2d-%2d-%4d', $now['mday'], $now['mon'], $now['year']); - list($day, $month, $year) = explode('-', ((!isset($user->profile_fields[$user_ident]) || $preview) ? $profile_row['field_default_value'] : $user->profile_fields[$user_ident])); - } - else - { - $day = request_var($profile_row['field_ident'] . '_day', 0); - $month = request_var($profile_row['field_ident'] . '_month', 0); - $year = request_var($profile_row['field_ident'] . '_year', 0); - } - } - - $profile_row['s_day_options'] = '<option value="0"' . ((!$day) ? ' selected="selected"' : '') . '>--</option>'; - for ($i = 1; $i < 32; $i++) - { - $profile_row['s_day_options'] .= '<option value="' . $i . '"' . (($i == $day) ? ' selected="selected"' : '') . ">$i</option>"; - } - - $profile_row['s_month_options'] = '<option value="0"' . ((!$month) ? ' selected="selected"' : '') . '>--</option>'; - for ($i = 1; $i < 13; $i++) - { - $profile_row['s_month_options'] .= '<option value="' . $i . '"' . (($i == $month) ? ' selected="selected"' : '') . ">$i</option>"; - } - - $profile_row['s_year_options'] = '<option value="0"' . ((!$year) ? ' selected="selected"' : '') . '>--</option>'; - for ($i = $now['year'] - 100; $i <= $now['year'] + 100; $i++) - { - $profile_row['s_year_options'] .= '<option value="' . $i . '"' . (($i == $year) ? ' selected="selected"' : '') . ">$i</option>"; - } - unset($now); - - $profile_row['field_value'] = 0; - $template->assign_block_vars($this->profile_types[$profile_row['field_type']], array_change_key_case($profile_row, CASE_UPPER)); - } - - /** - * Process bool-type - * @access private - */ - function generate_bool($profile_row, $preview = false) - { - global $template; - - $value = $this->get_var('int', $profile_row, $profile_row['field_default_value'], $preview); - - $profile_row['field_value'] = $value; - $template->assign_block_vars($this->profile_types[$profile_row['field_type']], array_change_key_case($profile_row, CASE_UPPER)); - - if ($profile_row['field_length'] == 1) - { - if (!isset($this->options_lang[$profile_row['field_id']][$profile_row['lang_id']]) || !sizeof($this->options_lang[$profile_row['field_id']][$profile_row['lang_id']])) - { - $this->get_option_lang($profile_row['field_id'], $profile_row['lang_id'], FIELD_BOOL, $preview); - } - - foreach ($this->options_lang[$profile_row['field_id']][$profile_row['lang_id']] as $option_id => $option_value) - { - $template->assign_block_vars('bool.options', array( - 'OPTION_ID' => $option_id, - 'CHECKED' => ($value == $option_id) ? ' checked="checked"' : '', - 'VALUE' => $option_value) - ); - } - } - } - - /** - * Process string-type - * @access private - */ - function generate_string($profile_row, $preview = false) - { - global $template; - - $profile_row['field_value'] = $this->get_var('string', $profile_row, $profile_row['lang_default_value'], $preview); - $template->assign_block_vars($this->profile_types[$profile_row['field_type']], array_change_key_case($profile_row, CASE_UPPER)); - } - - /** - * Process text-type - * @access private - */ - function generate_text($profile_row, $preview = false) - { - global $template; - global $user, $phpEx, $phpbb_root_path; - - $field_length = explode('|', $profile_row['field_length']); - $profile_row['field_rows'] = $field_length[0]; - $profile_row['field_cols'] = $field_length[1]; - - $profile_row['field_value'] = $this->get_var('string', $profile_row, $profile_row['lang_default_value'], $preview); - $template->assign_block_vars($this->profile_types[$profile_row['field_type']], array_change_key_case($profile_row, CASE_UPPER)); - } - - /** - * Process dropdown-type - * @access private - */ - function generate_dropdown($profile_row, $preview = false) - { - global $user, $template; - - $value = $this->get_var('int', $profile_row, $profile_row['field_default_value'], $preview); - - if (!isset($this->options_lang[$profile_row['field_id']]) || !isset($this->options_lang[$profile_row['field_id']][$profile_row['lang_id']]) || !sizeof($this->options_lang[$profile_row['field_id']][$profile_row['lang_id']])) - { - $this->get_option_lang($profile_row['field_id'], $profile_row['lang_id'], FIELD_DROPDOWN, $preview); - } - - $profile_row['field_value'] = $value; - $template->assign_block_vars($this->profile_types[$profile_row['field_type']], array_change_key_case($profile_row, CASE_UPPER)); - - foreach ($this->options_lang[$profile_row['field_id']][$profile_row['lang_id']] as $option_id => $option_value) - { - $template->assign_block_vars('dropdown.options', array( - 'OPTION_ID' => $option_id, - 'SELECTED' => ($value == $option_id) ? ' selected="selected"' : '', - 'VALUE' => $option_value) - ); - } - } - - /** - * Return Templated value/field. Possible values for $mode are: - * change == user is able to set/enter profile values; preview == just show the value - * @access private - */ - function process_field_row($mode, $profile_row) - { - global $template; - - $preview = ($mode == 'preview') ? true : false; - - // set template filename - $template->set_filenames(array( - 'cp_body' => 'custom_profile_fields.html') - ); - - // empty previously filled blockvars - foreach ($this->profile_types as $field_case => $field_type) - { - $template->destroy_block_vars($field_type); - } - - // Assign template variables - $type_func = 'generate_' . $this->profile_types[$profile_row['field_type']]; - $this->$type_func($profile_row, $preview); - - // Return templated data - return $template->assign_display('cp_body'); - } - - /** - * Build Array for user insertion into custom profile fields table - */ - function build_insert_sql_array($cp_data) - { - global $db, $user, $auth; - - $sql_not_in = array(); - foreach ($cp_data as $key => $null) - { - $sql_not_in[] = (strncmp($key, 'pf_', 3) === 0) ? substr($key, 3) : $key; - } - - $sql = 'SELECT f.field_type, f.field_ident, f.field_default_value, l.lang_default_value - FROM ' . PROFILE_LANG_TABLE . ' l, ' . PROFILE_FIELDS_TABLE . ' f - WHERE l.lang_id = ' . $user->get_iso_lang_id() . ' - ' . ((sizeof($sql_not_in)) ? ' AND ' . $db->sql_in_set('f.field_ident', $sql_not_in, true) : '') . ' - AND l.field_id = f.field_id'; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($row['field_default_value'] == 'now' && $row['field_type'] == FIELD_DATE) - { - $now = getdate(); - $row['field_default_value'] = sprintf('%2d-%2d-%4d', $now['mday'], $now['mon'], $now['year']); - } - else if ($row['field_default_value'] === '' && $row['field_type'] == FIELD_INT) - { - // We cannot insert an empty string into an integer column. - $row['field_default_value'] = NULL; - } - - $cp_data['pf_' . $row['field_ident']] = (in_array($row['field_type'], array(FIELD_TEXT, FIELD_STRING))) ? $row['lang_default_value'] : $row['field_default_value']; - } - $db->sql_freeresult($result); - - return $cp_data; - } - - /** - * Get profile field value on submit - * @access private - */ - function get_profile_field($profile_row) - { - global $phpbb_root_path, $phpEx; - global $config; - - $var_name = 'pf_' . $profile_row['field_ident']; - - switch ($profile_row['field_type']) - { - case FIELD_DATE: - - if (!isset($_REQUEST[$var_name . '_day'])) - { - if ($profile_row['field_default_value'] == 'now') - { - $now = getdate(); - $profile_row['field_default_value'] = sprintf('%2d-%2d-%4d', $now['mday'], $now['mon'], $now['year']); - } - list($day, $month, $year) = explode('-', $profile_row['field_default_value']); - } - else - { - $day = request_var($var_name . '_day', 0); - $month = request_var($var_name . '_month', 0); - $year = request_var($var_name . '_year', 0); - } - - $var = sprintf('%2d-%2d-%4d', $day, $month, $year); - break; - - case FIELD_BOOL: - // Checkbox - if ($profile_row['field_length'] == 2) - { - $var = (isset($_REQUEST[$var_name])) ? 1 : 0; - } - else - { - $var = request_var($var_name, (int) $profile_row['field_default_value']); - } - break; - - case FIELD_STRING: - case FIELD_TEXT: - $var = utf8_normalize_nfc(request_var($var_name, (string) $profile_row['field_default_value'], true)); - break; - - case FIELD_INT: - if (isset($_REQUEST[$var_name]) && $_REQUEST[$var_name] === '') - { - $var = NULL; - } - else - { - $var = request_var($var_name, (int) $profile_row['field_default_value']); - } - break; - - case FIELD_DROPDOWN: - $var = request_var($var_name, (int) $profile_row['field_default_value']); - break; - - default: - $var = request_var($var_name, $profile_row['field_default_value']); - break; - } - - return $var; - } -} - -/** -* Custom Profile Fields ACP -* @package phpBB3 -*/ -class custom_profile_admin extends custom_profile -{ - var $vars = array(); - - /** - * Return possible validation options - */ - function validate_options() - { - global $user; - - $validate_ary = array('CHARS_ANY' => '.*', 'NUMBERS_ONLY' => '[0-9]+', 'ALPHA_ONLY' => '[\w]+', 'ALPHA_SPACERS' => '[\w_\+\. \-\[\]]+'); - - $validate_options = ''; - foreach ($validate_ary as $lang => $value) - { - $selected = ($this->vars['field_validation'] == $value) ? ' selected="selected"' : ''; - $validate_options .= '<option value="' . $value . '"' . $selected . '>' . $user->lang[$lang] . '</option>'; - } - - return $validate_options; - } - - /** - * Get string options for second step in ACP - */ - function get_string_options() - { - global $user; - - $options = array( - 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="text" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'), - 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'), - 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_maxlen" size="5" value="' . $this->vars['field_maxlen'] . '" />'), - 3 => array('TITLE' => $user->lang['FIELD_VALIDATION'], 'FIELD' => '<select name="field_validation">' . $this->validate_options() . '</select>') - ); - - return $options; - } - - /** - * Get text options for second step in ACP - */ - function get_text_options() - { - global $user; - - $options = array( - 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input name="rows" size="5" value="' . $this->vars['rows'] . '" /> ' . $user->lang['ROWS'] . '</dd><dd><input name="columns" size="5" value="' . $this->vars['columns'] . '" /> ' . $user->lang['COLUMNS'] . ' <input type="hidden" name="field_length" value="' . $this->vars['field_length'] . '" />'), - 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_minlen" size="10" value="' . $this->vars['field_minlen'] . '" />'), - 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_maxlen" size="10" value="' . $this->vars['field_maxlen'] . '" />'), - 3 => array('TITLE' => $user->lang['FIELD_VALIDATION'], 'FIELD' => '<select name="field_validation">' . $this->validate_options() . '</select>') - ); - - return $options; - } - - /** - * Get int options for second step in ACP - */ - function get_int_options() - { - global $user; - - $options = array( - 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="text" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'), - 1 => array('TITLE' => $user->lang['MIN_FIELD_NUMBER'], 'FIELD' => '<input type="text" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'), - 2 => array('TITLE' => $user->lang['MAX_FIELD_NUMBER'], 'FIELD' => '<input type="text" name="field_maxlen" size="5" value="' . $this->vars['field_maxlen'] . '" />'), - 3 => array('TITLE' => $user->lang['DEFAULT_VALUE'], 'FIELD' => '<input type="post" name="field_default_value" value="' . $this->vars['field_default_value'] . '" />') - ); - - return $options; - } - - /** - * Get bool options for second step in ACP - */ - function get_bool_options() - { - global $user, $config, $lang_defs; - - $default_lang_id = $lang_defs['iso'][$config['default_lang']]; - - $profile_row = array( - 'var_name' => 'field_default_value', - 'field_id' => 1, - 'lang_name' => $this->vars['lang_name'], - 'lang_explain' => $this->vars['lang_explain'], - 'lang_id' => $default_lang_id, - 'field_default_value' => $this->vars['field_default_value'], - 'field_ident' => 'field_default_value', - 'field_type' => FIELD_BOOL, - 'field_length' => $this->vars['field_length'], - 'lang_options' => $this->vars['lang_options'] - ); - - $options = array( - 0 => array('TITLE' => $user->lang['FIELD_TYPE'], 'EXPLAIN' => $user->lang['BOOL_TYPE_EXPLAIN'], 'FIELD' => '<label><input type="radio" class="radio" name="field_length" value="1"' . (($this->vars['field_length'] == 1) ? ' checked="checked"' : '') . ' onchange="document.getElementById(\'add_profile_field\').submit();" /> ' . $user->lang['RADIO_BUTTONS'] . '</label><label><input type="radio" class="radio" name="field_length" value="2"' . (($this->vars['field_length'] == 2) ? ' checked="checked"' : '') . ' onchange="document.getElementById(\'add_profile_field\').submit();" /> ' . $user->lang['CHECKBOX'] . '</label>'), - 1 => array('TITLE' => $user->lang['DEFAULT_VALUE'], 'FIELD' => $this->process_field_row('preview', $profile_row)) - ); - - return $options; - } - - /** - * Get dropdown options for second step in ACP - */ - function get_dropdown_options() - { - global $user, $config, $lang_defs; - - $default_lang_id = $lang_defs['iso'][$config['default_lang']]; - - $profile_row[0] = array( - 'var_name' => 'field_default_value', - 'field_id' => 1, - 'lang_name' => $this->vars['lang_name'], - 'lang_explain' => $this->vars['lang_explain'], - 'lang_id' => $default_lang_id, - 'field_default_value' => $this->vars['field_default_value'], - 'field_ident' => 'field_default_value', - 'field_type' => FIELD_DROPDOWN, - 'lang_options' => $this->vars['lang_options'] - ); - - $profile_row[1] = $profile_row[0]; - $profile_row[1]['var_name'] = 'field_novalue'; - $profile_row[1]['field_ident'] = 'field_novalue'; - $profile_row[1]['field_default_value'] = $this->vars['field_novalue']; - - $options = array( - 0 => array('TITLE' => $user->lang['DEFAULT_VALUE'], 'FIELD' => $this->process_field_row('preview', $profile_row[0])), - 1 => array('TITLE' => $user->lang['NO_VALUE_OPTION'], 'EXPLAIN' => $user->lang['NO_VALUE_OPTION_EXPLAIN'], 'FIELD' => $this->process_field_row('preview', $profile_row[1])) - ); - - return $options; - } - - /** - * Get date options for second step in ACP - */ - function get_date_options() - { - global $user, $config, $lang_defs; - - $default_lang_id = $lang_defs['iso'][$config['default_lang']]; - - $profile_row = array( - 'var_name' => 'field_default_value', - 'lang_name' => $this->vars['lang_name'], - 'lang_explain' => $this->vars['lang_explain'], - 'lang_id' => $default_lang_id, - 'field_default_value' => $this->vars['field_default_value'], - 'field_ident' => 'field_default_value', - 'field_type' => FIELD_DATE, - 'field_length' => $this->vars['field_length'] - ); - - $always_now = request_var('always_now', -1); - if ($always_now == -1) - { - $s_checked = ($this->vars['field_default_value'] == 'now') ? true : false; - } - else - { - $s_checked = ($always_now) ? true : false; - } - - $options = array( - 0 => array('TITLE' => $user->lang['DEFAULT_VALUE'], 'FIELD' => $this->process_field_row('preview', $profile_row)), - 1 => array('TITLE' => $user->lang['ALWAYS_TODAY'], 'FIELD' => '<label><input type="radio" class="radio" name="always_now" value="1"' . (($s_checked) ? ' checked="checked"' : '') . ' onchange="document.getElementById(\'add_profile_field\').submit();" /> ' . $user->lang['YES'] . '</label><label><input type="radio" class="radio" name="always_now" value="0"' . ((!$s_checked) ? ' checked="checked"' : '') . ' onchange="document.getElementById(\'add_profile_field\').submit();" /> ' . $user->lang['NO'] . '</label>'), - ); - - return $options; - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_template.php b/phpBB/includes/functions_template.php deleted file mode 100644 index 8636dfe010..0000000000 --- a/phpBB/includes/functions_template.php +++ /dev/null @@ -1,814 +0,0 @@ -<?php -/** -* -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Extension of template class - Functions needed for compiling templates only. -* -* psoTFX, phpBB Development Team - Completion of file caching, decompilation -* routines and implementation of conditionals/keywords and associated changes -* -* The interface was inspired by PHPLib templates, and the template file (formats are -* quite similar) -* -* The keyword/conditional implementation is currently based on sections of code from -* the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released -* (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code -* derived from an LGPL application may be relicenced under the GPL, this applies -* to this source -* -* DEFINE directive inspired by a request by Cyberalien -* -* @package phpBB3 -*/ -class template_compile -{ - var $template; - - // Various storage arrays - var $block_names = array(); - var $block_else_level = array(); - - /** - * constuctor - */ - function template_compile(&$template) - { - $this->template = &$template; - } - - /** - * Load template source from file - * @access private - */ - function _tpl_load_file($handle, $store_in_db = false) - { - // Try and open template for read - if (!file_exists($this->template->files[$handle])) - { - trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR); - } - - $this->template->compiled_code[$handle] = $this->compile(trim(@file_get_contents($this->template->files[$handle]))); - - // Actually compile the code now. - $this->compile_write($handle, $this->template->compiled_code[$handle]); - - // Store in database if required... - if ($store_in_db) - { - global $db, $user; - - $sql_ary = array( - 'template_id' => $this->template->files_template[$handle], - 'template_filename' => $this->template->filename[$handle], - 'template_included' => '', - 'template_mtime' => time(), - 'template_data' => trim(@file_get_contents($this->template->files[$handle])), - ); - - $sql = 'INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - } - } - - /** - * Remove any PHP tags that do not belong, these regular expressions are derived from - * the ones that exist in zend_language_scanner.l - * @access private - */ - function remove_php_tags(&$code) - { - // This matches the information gathered from the internal PHP lexer - $match = array( - '#<([\?%])=?.*?\1>#s', - '#<script\s+language\s*=\s*(["\']?)php\1\s*>.*?</script\s*>#s', - '#<\?php(?:\r\n?|[ \n\t]).*?\?>#s' - ); - - $code = preg_replace($match, '', $code); - } - - /** - * The all seeing all doing compile method. Parts are inspired by or directly from Smarty - * @access private - */ - function compile($code, $no_echo = false, $echo_var = '') - { - global $config; - - if ($echo_var) - { - global $$echo_var; - } - - // Remove any "loose" php ... we want to give admins the ability - // to switch on/off PHP for a given template. Allowing unchecked - // php is a no-no. There is a potential issue here in that non-php - // content may be removed ... however designers should use entities - // if they wish to display < and > - $this->remove_php_tags($code); - - // Pull out all block/statement level elements and separate plain text - preg_match_all('#<!-- PHP -->(.*?)<!-- ENDPHP -->#s', $code, $matches); - $php_blocks = $matches[1]; - $code = preg_replace('#<!-- PHP -->.*?<!-- ENDPHP -->#s', '<!-- PHP -->', $code); - - preg_match_all('#<!-- INCLUDE (\{\$?[A-Z0-9\-_]+\}|[a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches); - $include_blocks = $matches[1]; - $code = preg_replace('#<!-- INCLUDE (?:\{\$?[A-Z0-9\-_]+\}|[a-zA-Z0-9\_\-\+\./]+) -->#', '<!-- INCLUDE -->', $code); - - preg_match_all('#<!-- INCLUDEPHP ([a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches); - $includephp_blocks = $matches[1]; - $code = preg_replace('#<!-- INCLUDEPHP [a-zA-Z0-9\_\-\+\./]+ -->#', '<!-- INCLUDEPHP -->', $code); - - preg_match_all('#<!-- ([^<].*?) (.*?)? ?-->#', $code, $blocks, PREG_SET_ORDER); - - $text_blocks = preg_split('#<!-- [^<].*? (?:.*?)? ?-->#', $code); - - for ($i = 0, $j = sizeof($text_blocks); $i < $j; $i++) - { - $this->compile_var_tags($text_blocks[$i]); - } - $compile_blocks = array(); - - for ($curr_tb = 0, $tb_size = sizeof($blocks); $curr_tb < $tb_size; $curr_tb++) - { - $block_val = &$blocks[$curr_tb]; - - switch ($block_val[1]) - { - case 'BEGIN': - $this->block_else_level[] = false; - $compile_blocks[] = '<?php ' . $this->compile_tag_block($block_val[2]) . ' ?>'; - break; - - case 'BEGINELSE': - $this->block_else_level[sizeof($this->block_else_level) - 1] = true; - $compile_blocks[] = '<?php }} else { ?>'; - break; - - case 'END': - array_pop($this->block_names); - $compile_blocks[] = '<?php ' . ((array_pop($this->block_else_level)) ? '}' : '}}') . ' ?>'; - break; - - case 'IF': - $compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], false) . ' ?>'; - break; - - case 'ELSE': - $compile_blocks[] = '<?php } else { ?>'; - break; - - case 'ELSEIF': - $compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], true) . ' ?>'; - break; - - case 'ENDIF': - $compile_blocks[] = '<?php } ?>'; - break; - - case 'DEFINE': - $compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], true) . ' ?>'; - break; - - case 'UNDEFINE': - $compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], false) . ' ?>'; - break; - - case 'INCLUDE': - $temp = array_shift($include_blocks); - - // Dynamic includes - // Cheap match rather than a full blown regexp, we already know - // the format of the input so just use string manipulation. - if ($temp[0] == '{') - { - $file = false; - - if ($temp[1] == '$') - { - $var = substr($temp, 2, -1); - //$file = $this->template->_tpldata['DEFINE']['.'][$var]; - $temp = "\$this->_tpldata['DEFINE']['.']['$var']"; - } - else - { - $var = substr($temp, 1, -1); - //$file = $this->template->_rootref[$var]; - $temp = "\$this->_rootref['$var']"; - } - } - else - { - $file = $temp; - } - - $compile_blocks[] = '<?php ' . $this->compile_tag_include($temp) . ' ?>'; - - // No point in checking variable includes - if ($file) - { - $this->template->_tpl_include($file, false); - } - break; - - case 'INCLUDEPHP': - $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . $this->compile_tag_include_php(array_shift($includephp_blocks)) . ' ?>' : ''; - break; - - case 'PHP': - $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . array_shift($php_blocks) . ' ?>' : ''; - break; - - default: - $this->compile_var_tags($block_val[0]); - $trim_check = trim($block_val[0]); - $compile_blocks[] = (!$no_echo) ? ((!empty($trim_check)) ? $block_val[0] : '') : ((!empty($trim_check)) ? $block_val[0] : ''); - break; - } - } - - $template_php = ''; - for ($i = 0, $size = sizeof($text_blocks); $i < $size; $i++) - { - $trim_check_text = trim($text_blocks[$i]); - $template_php .= (!$no_echo) ? (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : '') : (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : ''); - } - - // Remove unused opening/closing tags - $template_php = str_replace(' ?><?php ', ' ', $template_php); - - // Now add a newline after each php closing tag which already has a newline - // PHP itself strips a newline if a closing tag is used (this is documented behaviour) and it is mostly not intended by style authors to remove newlines - $template_php = preg_replace('#\?\>([\r\n])#', '?>\1\1', $template_php); - - // There will be a number of occasions where we switch into and out of - // PHP mode instantaneously. Rather than "burden" the parser with this - // we'll strip out such occurences, minimising such switching - if ($no_echo) - { - return "\$$echo_var .= '" . $template_php . "'"; - } - - return $template_php; - } - - /** - * Compile variables - * @access private - */ - function compile_var_tags(&$text_blocks) - { - // change template varrefs into PHP varrefs - $varrefs = array(); - - // This one will handle varrefs WITH namespaces - preg_match_all('#\{((?:[a-z0-9\-_]+\.)+)(\$)?([A-Z0-9\-_]+)\}#', $text_blocks, $varrefs, PREG_SET_ORDER); - - foreach ($varrefs as $var_val) - { - $namespace = $var_val[1]; - $varname = $var_val[3]; - $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]); - - $text_blocks = str_replace($var_val[0], $new, $text_blocks); - } - - // This will handle the remaining root-level varrefs - // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array - if (strpos($text_blocks, '{L_') !== false) - { - $text_blocks = preg_replace('#\{L_([A-Z0-9\-_]+)\}#', "<?php echo ((isset(\$this->_rootref['L_\\1'])) ? \$this->_rootref['L_\\1'] : ((isset(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '{ \\1 }')); ?>", $text_blocks); - } - - // Handle addslashed language variables prefixed with LA_ - // If a template variable already exist, it will be used in favor of it... - if (strpos($text_blocks, '{LA_') !== false) - { - $text_blocks = preg_replace('#\{LA_([A-Z0-9\-_]+)\}#', "<?php echo ((isset(\$this->_rootref['LA_\\1'])) ? \$this->_rootref['LA_\\1'] : ((isset(\$this->_rootref['L_\\1'])) ? addslashes(\$this->_rootref['L_\\1']) : ((isset(\$user->lang['\\1'])) ? addslashes(\$user->lang['\\1']) : '{ \\1 }'))); ?>", $text_blocks); - } - - // Handle remaining varrefs - $text_blocks = preg_replace('#\{([A-Z0-9\-_]+)\}#', "<?php echo (isset(\$this->_rootref['\\1'])) ? \$this->_rootref['\\1'] : ''; ?>", $text_blocks); - $text_blocks = preg_replace('#\{\$([A-Z0-9\-_]+)\}#', "<?php echo (isset(\$this->_tpldata['DEFINE']['.']['\\1'])) ? \$this->_tpldata['DEFINE']['.']['\\1'] : ''; ?>", $text_blocks); - - return; - } - - /** - * Compile blocks - * @access private - */ - function compile_tag_block($tag_args) - { - $no_nesting = false; - - // Is the designer wanting to call another loop in a loop? - if (strpos($tag_args, '!') === 0) - { - // Count the number of ! occurrences (not allowed in vars) - $no_nesting = substr_count($tag_args, '!'); - $tag_args = substr($tag_args, $no_nesting); - } - - // Allow for control of looping (indexes start from zero): - // foo(2) : Will start the loop on the 3rd entry - // foo(-2) : Will start the loop two entries from the end - // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth - // foo(3,-4) : Will start the loop on the fourth entry and end it four from last - if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match)) - { - $tag_args = $match[1]; - - if ($match[2] < 0) - { - $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')'; - } - else - { - $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')'; - } - - if (strlen($match[3]) < 1 || $match[3] == -1) - { - $loop_end = '$_' . $tag_args . '_count'; - } - else if ($match[3] >= 0) - { - $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')'; - } - else //if ($match[3] < -1) - { - $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1); - } - } - else - { - $loop_start = 0; - $loop_end = '$_' . $tag_args . '_count'; - } - - $tag_template_php = ''; - array_push($this->block_names, $tag_args); - - if ($no_nesting !== false) - { - // We need to implode $no_nesting times from the end... - $block = array_slice($this->block_names, -$no_nesting); - } - else - { - $block = $this->block_names; - } - - if (sizeof($block) < 2) - { - // Block is not nested. - $tag_template_php = '$_' . $tag_args . "_count = (isset(\$this->_tpldata['$tag_args'])) ? sizeof(\$this->_tpldata['$tag_args']) : 0;"; - $varref = "\$this->_tpldata['$tag_args']"; - } - else - { - // This block is nested. - // Generate a namespace string for this block. - $namespace = implode('.', $block); - - // Get a reference to the data array for this block that depends on the - // current indices of all parent blocks. - $varref = $this->generate_block_data_ref($namespace, false); - - // Create the for loop code to iterate over this block. - $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;'; - } - - $tag_template_php .= 'if ($_' . $tag_args . '_count) {'; - - /** - * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory - * <code> - * if (!$offset) - * { - * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){'; - * } - * </code> - */ - - $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){'; - $tag_template_php .= '$_'. $tag_args . '_val = &' . $varref . '[$_'. $tag_args. '_i];'; - - return $tag_template_php; - } - - /** - * Compile IF tags - much of this is from Smarty with - * some adaptions for our block level methods - * @access private - */ - function compile_tag_if($tag_args, $elseif) - { - // Tokenize args for 'if' tag. - preg_match_all('/(?: - "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | - \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | - [(),] | - [^\s(),]+)/x', $tag_args, $match); - - $tokens = $match[0]; - $is_arg_stack = array(); - - for ($i = 0, $size = sizeof($tokens); $i < $size; $i++) - { - $token = &$tokens[$i]; - - switch ($token) - { - case '!==': - case '===': - case '<<': - case '>>': - case '|': - case '^': - case '&': - case '~': - case ')': - case ',': - case '+': - case '-': - case '*': - case '/': - case '@': - break; - - case '==': - case 'eq': - $token = '=='; - break; - - case '!=': - case '<>': - case 'ne': - case 'neq': - $token = '!='; - break; - - case '<': - case 'lt': - $token = '<'; - break; - - case '<=': - case 'le': - case 'lte': - $token = '<='; - break; - - case '>': - case 'gt': - $token = '>'; - break; - - case '>=': - case 'ge': - case 'gte': - $token = '>='; - break; - - case '&&': - case 'and': - $token = '&&'; - break; - - case '||': - case 'or': - $token = '||'; - break; - - case '!': - case 'not': - $token = '!'; - break; - - case '%': - case 'mod': - $token = '%'; - break; - - case '(': - array_push($is_arg_stack, $i); - break; - - case 'is': - $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1; - $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); - - $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); - - array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens); - - $i = $is_arg_start; - - // no break - - default: - if (preg_match('#^((?:[a-z0-9\-_]+\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs)) - { - $token = (!empty($varrefs[1])) ? $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']' : (($varrefs[2]) ? '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$this->_rootref[\'' . $varrefs[3] . '\']'); - } - else if (preg_match('#^\.((?:[a-z0-9\-_]+\.?)+)$#s', $token, $varrefs)) - { - // Allow checking if loops are set with .loopname - // It is also possible to check the loop count by doing <!-- IF .loopname > 1 --> for example - $blocks = explode('.', $varrefs[1]); - - // If the block is nested, we have a reference that we can grab. - // If the block is not nested, we just go and grab the block from _tpldata - if (sizeof($blocks) > 1) - { - $block = array_pop($blocks); - $namespace = implode('.', $blocks); - $varref = $this->generate_block_data_ref($namespace, true); - - // Add the block reference for the last child. - $varref .= "['" . $block . "']"; - } - else - { - $varref = '$this->_tpldata'; - - // Add the block reference for the last child. - $varref .= "['" . $blocks[0] . "']"; - } - $token = "sizeof($varref)"; - } - else if (!empty($token)) - { - $token = '(' . $token . ')'; - } - - break; - } - } - - // If there are no valid tokens left or only control/compare characters left, we do skip this statement - if (!sizeof($tokens) || str_replace(array(' ', '=', '!', '<', '>', '&', '|', '%', '(', ')'), '', implode('', $tokens)) == '') - { - $tokens = array('false'); - } - return (($elseif) ? '} else if (' : 'if (') . (implode(' ', $tokens) . ') { '); - } - - /** - * Compile DEFINE tags - * @access private - */ - function compile_tag_define($tag_args, $op) - { - preg_match('#^((?:[a-z0-9\-_]+\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (\'?)([^\']*)(\'?))?$#', $tag_args, $match); - - if (empty($match[2]) || (!isset($match[4]) && $op)) - { - return ''; - } - - if (!$op) - { - return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');'; - } - - // Are we a string? - if ($match[3] && $match[5]) - { - $match[4] = str_replace(array('\\\'', '\\\\', '\''), array('\'', '\\', '\\\''), $match[4]); - - // Compile reference, we allow template variables in defines... - $match[4] = $this->compile($match[4]); - - // Now replace the php code - $match[4] = "'" . str_replace(array('<?php echo ', '; ?>'), array("' . ", " . '"), $match[4]) . "'"; - } - else - { - preg_match('#true|false|\.#i', $match[4], $type); - - switch (strtolower($type[0])) - { - case 'true': - case 'false': - $match[4] = strtoupper($match[4]); - break; - - case '.': - $match[4] = doubleval($match[4]); - break; - - default: - $match[4] = intval($match[4]); - break; - } - } - - return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $match[4] . ';'; - } - - /** - * Compile INCLUDE tag - * @access private - */ - function compile_tag_include($tag_args) - { - // Process dynamic includes - if ($tag_args[0] == '$') - { - return "if (isset($tag_args)) { \$this->_tpl_include($tag_args); }"; - } - - return "\$this->_tpl_include('$tag_args');"; - } - - /** - * Compile INCLUDE_PHP tag - * @access private - */ - function compile_tag_include_php($tag_args) - { - return "\$this->_php_include('$tag_args');"; - } - - /** - * parse expression - * This is from Smarty - * @access private - */ - function _parse_is_expr($is_arg, $tokens) - { - $expr_end = 0; - $negate_expr = false; - - if (($first_token = array_shift($tokens)) == 'not') - { - $negate_expr = true; - $expr_type = array_shift($tokens); - } - else - { - $expr_type = $first_token; - } - - switch ($expr_type) - { - case 'even': - if (@$tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!(($is_arg / $expr_arg) % $expr_arg)"; - } - else - { - $expr = "!($is_arg & 1)"; - } - break; - - case 'odd': - if (@$tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "(($is_arg / $expr_arg) % $expr_arg)"; - } - else - { - $expr = "($is_arg & 1)"; - } - break; - - case 'div': - if (@$tokens[$expr_end] == 'by') - { - $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!($is_arg % $expr_arg)"; - } - break; - } - - if ($negate_expr) - { - $expr = "!($expr)"; - } - - array_splice($tokens, 0, $expr_end, $expr); - - return $tokens; - } - - /** - * Generates a reference to the given variable inside the given (possibly nested) - * block namespace. This is a string of the form: - * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' - * It's ready to be inserted into an "echo" line in one of the templates. - * NOTE: expects a trailing "." on the namespace. - * @access private - */ - function generate_block_varref($namespace, $varname, $echo = true, $defop = false) - { - // Strip the trailing period. - $namespace = substr($namespace, 0, -1); - - // Get a reference to the data block for this namespace. - $varref = $this->generate_block_data_ref($namespace, true, $defop); - // Prepend the necessary code to stick this in an echo line. - - // Append the variable reference. - $varref .= "['$varname']"; - $varref = ($echo) ? "<?php echo $varref; ?>" : ((isset($varref)) ? $varref : ''); - - return $varref; - } - - /** - * Generates a reference to the array of data values for the given - * (possibly nested) block namespace. This is a string of the form: - * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] - * - * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. - * NOTE: does not expect a trailing "." on the blockname. - * @access private - */ - function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) - { - // Get an array of the blocks involved. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - // DEFINE is not an element of any referenced variable, we must use _tpldata to access it - if ($defop) - { - $varref = '$this->_tpldata[\'DEFINE\']'; - // Build up the string with everything but the last child. - for ($i = 0; $i < $blockcount; $i++) - { - $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]'; - } - // Add the block reference for the last child. - $varref .= "['" . $blocks[$blockcount] . "']"; - // Add the iterator for the last child if requried. - if ($include_last_iterator) - { - $varref .= '[$_' . $blocks[$blockcount] . '_i]'; - } - return $varref; - } - else if ($include_last_iterator) - { - return '$_'. $blocks[$blockcount] . '_val'; - } - else - { - return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']'; - } - } - - /** - * Write compiled file to cache directory - * @access private - */ - function compile_write($handle, $data) - { - global $phpEx; - - $filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . $phpEx; - - $data = "<?php if (!defined('IN_PHPBB')) exit;" . ((strpos($data, '<?php') === 0) ? substr($data, 5) : ' ?>' . $data); - - if ($fp = @fopen($filename, 'wb')) - { - @flock($fp, LOCK_EX); - @fwrite ($fp, $data); - @flock($fp, LOCK_UN); - @fclose($fp); - - phpbb_chmod($filename, CHMOD_READ | CHMOD_WRITE); - } - - return; - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_transfer.php b/phpBB/includes/functions_transfer.php index 5ab7a87efd..42fdee364c 100644 --- a/phpBB/includes/functions_transfer.php +++ b/phpBB/includes/functions_transfer.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,7 +21,6 @@ if (!defined('IN_PHPBB')) /** * Transfer class, wrapper for ftp/sftp/ssh -* @package phpBB3 */ class transfer { @@ -235,7 +237,7 @@ class transfer /** * Determine methods able to be used */ - function methods() + static public function methods() { $methods = array(); $disabled_functions = explode(',', @ini_get('disable_functions')); @@ -256,7 +258,6 @@ class transfer /** * FTP transfer class -* @package phpBB3 */ class ftp extends transfer { @@ -280,7 +281,7 @@ class ftp extends transfer } // Init some needed values - transfer::transfer(); + $this->transfer(); return; } @@ -288,7 +289,7 @@ class ftp extends transfer /** * Requests data */ - function data() + static public function data() { global $user; @@ -506,9 +507,6 @@ class ftp extends transfer /** * FTP fsock transfer class -* -* @author wGEric -* @package phpBB3 */ class ftp_fsock extends transfer { @@ -534,7 +532,7 @@ class ftp_fsock extends transfer } // Init some needed values - transfer::transfer(); + $this->transfer(); return; } @@ -542,7 +540,7 @@ class ftp_fsock extends transfer /** * Requests data */ - function data() + static public function data() { global $user; @@ -902,5 +900,3 @@ class ftp_fsock extends transfer return ($return) ? $response : true; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index 69f10911ec..f179b2fd70 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * Responsible for holding all file relevant information, as well as doing file-specific operations. * The {@link fileupload fileupload class} can be used to upload several files, each of them being this object to operate further on. -* @package phpBB3 */ class filespec { @@ -45,10 +47,22 @@ class filespec var $upload = ''; /** + * The plupload object + * @var \phpbb\plupload\plupload + */ + protected $plupload; + + /** + * phpBB Mimetype guesser + * @var \phpbb\mimetype\guesser + */ + protected $mimetype_guesser; + + /** * File Class * @access private */ - function filespec($upload_ary, $upload_namespace) + function filespec($upload_ary, $upload_namespace, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null) { if (!isset($upload_ary)) { @@ -59,7 +73,7 @@ class filespec $this->filename = $upload_ary['tmp_name']; $this->filesize = $upload_ary['size']; $name = (STRIP) ? stripslashes($upload_ary['name']) : $upload_ary['name']; - $name = trim(utf8_htmlspecialchars(utf8_basename($name))); + $name = trim(utf8_basename($name)); $this->realname = $this->uploadname = $name; $this->mimetype = $upload_ary['type']; @@ -68,10 +82,10 @@ class filespec if (!$this->mimetype) { - $this->mimetype = 'application/octetstream'; + $this->mimetype = 'application/octet-stream'; } - $this->extension = strtolower($this->get_extension($this->realname)); + $this->extension = strtolower(self::get_extension($this->realname)); // Try to get real filesize from temporary folder (not always working) ;) $this->filesize = (@filesize($this->filename)) ? @filesize($this->filename) : $this->filesize; @@ -81,6 +95,8 @@ class filespec $this->local = (isset($upload_ary['local_mode'])) ? true : false; $this->upload = $upload_namespace; + $this->plupload = $plupload; + $this->mimetype_guesser = $mimetype_guesser; } /** @@ -88,6 +104,7 @@ class filespec * * @param real|unique|unique_ext $mode real creates a realname, filtering some characters, lowering every character. Unique creates an unique filename * @param string $prefix Prefix applied to filename + * @param string $user_id The user_id is only needed for when cleaning a user's avatar * @access public */ function clean_filename($mode = 'unique', $prefix = '', $user_id = '') @@ -152,7 +169,7 @@ class filespec */ function is_image() { - return (strpos($this->mimetype, 'image/') !== false) ? true : false; + return (strpos($this->mimetype, 'image/') === 0); } /** @@ -162,12 +179,14 @@ class filespec */ function is_uploaded() { - if (!$this->local && !is_uploaded_file($this->filename)) + $is_plupload = $this->plupload && $this->plupload->is_active(); + + if (!$this->local && !$is_plupload && !is_uploaded_file($this->filename)) { return false; } - if ($this->local && !file_exists($this->filename)) + if (($this->local || $is_plupload) && !file_exists($this->filename)) { return false; } @@ -188,8 +207,11 @@ class filespec /** * Get file extension + * + * @param string Filename that needs to be checked + * @return string Extension of the supplied filename */ - function get_extension($filename) + static public function get_extension($filename) { if (strpos($filename, '.') === false) { @@ -201,25 +223,24 @@ class filespec } /** - * Get mimetype. Utilize mime_content_type if the function exist. - * Not used at the moment... + * Get mimetype + * + * @param string $filename Filename that needs to be checked + * @return string Mimetype of supplied filename */ function get_mimetype($filename) { - $mimetype = ''; - - if (function_exists('mime_content_type')) + if ($this->mimetype_guesser !== null) { - $mimetype = mime_content_type($filename); - } + $mimetype = $this->mimetype_guesser->guess($filename, $this->uploadname); - // Some browsers choke on a mimetype of application/octet-stream - if (!$mimetype || $mimetype == 'application/octet-stream') - { - $mimetype = 'application/octetstream'; + if ($mimetype !== 'application/octet-stream') + { + $this->mimetype = $mimetype; + } } - return $mimetype; + return $this->mimetype; } /** @@ -262,8 +283,9 @@ class filespec * Move file to destination folder * The phpbb_root_path variable will be applied to the destination path * - * @param string $destination_path Destination path, for example $config['avatar_path'] + * @param string $destination Destination path, for example $config['avatar_path'] * @param bool $overwrite If set to true, an already existing file will be overwritten + * @param bool $skip_image_check If set to true, the check for the file to be a valid image is skipped * @param string $chmod Permission mask for chmodding the file after a successful move. The mode entered here reflects the mode defined by {@link phpbb_chmod()} * * @access public @@ -297,6 +319,9 @@ class filespec if (file_exists($this->destination_file) && !$overwrite) { @unlink($this->filename); + $this->error[] = $user->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file); + $this->file_moved = false; + return false; } else { @@ -355,6 +380,9 @@ class filespec // Try to get real filesize from destination folder $this->filesize = (@filesize($this->destination_file)) ? @filesize($this->destination_file) : $this->filesize; + // Get mimetype of supplied file + $this->mimetype = $this->get_mimetype($this->destination_file); + if ($this->is_image() && !$skip_image_check) { $this->width = $this->height = 0; @@ -370,7 +398,7 @@ class filespec } // Check image type - $types = $this->upload->image_types(); + $types = fileupload::image_types(); if (!isset($types[$this->image_info[2]]) || !in_array($this->extension, $types[$this->image_info[2]])) { @@ -427,7 +455,13 @@ class filespec if (!$this->upload->valid_dimensions($this)) { - $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'WRONG_SIZE'], $this->upload->min_width, $this->upload->min_height, $this->upload->max_width, $this->upload->max_height, $this->width, $this->height); + $this->error[] = $user->lang($this->upload->error_prefix . 'WRONG_SIZE', + $user->lang('PIXELS', (int) $this->upload->min_width), + $user->lang('PIXELS', (int) $this->upload->min_height), + $user->lang('PIXELS', (int) $this->upload->max_width), + $user->lang('PIXELS', (int) $this->upload->max_height), + $user->lang('PIXELS', (int) $this->width), + $user->lang('PIXELS', (int) $this->height)); return false; } @@ -438,8 +472,6 @@ class filespec /** * Class for assigning error messages before a real filespec class can be assigned -* -* @package phpBB3 */ class fileerror extends filespec { @@ -452,13 +484,11 @@ class fileerror extends filespec /** * File upload class * Init class (all parameters optional and able to be set/overwritten separately) - scope is global and valid for all uploads -* -* @package phpBB3 */ class fileupload { var $allowed_extensions = array(); - var $disallowed_content = array('body', 'head', 'html', 'img', 'plaintext', 'a href', 'pre', 'script', 'table', 'title'); + var $disallowed_content = array('body', 'head', 'html', 'img', 'plaintext', 'a href', 'pre', 'script', 'table', 'title'); var $max_filesize = 0; var $min_width = 0; var $min_height = 0; @@ -479,6 +509,8 @@ class fileupload * @param int $min_height Minimum image height (only checked for images) * @param int $max_width Maximum image width (only checked for images) * @param int $max_height Maximum image height (only checked for images) + * @param bool|array $disallowed_content If enabled, the first 256 bytes of the file must not + * contain any of its values. Defaults to false. * */ function fileupload($error_prefix = '', $allowed_extensions = false, $max_filesize = false, $min_width = false, $min_height = false, $max_width = false, $max_height = false, $disallowed_content = false) @@ -559,15 +591,29 @@ class fileupload * Upload file from users harddisk * * @param string $form_name Form name assigned to the file input field (if it is an array, the key has to be specified) + * @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser + * @param \phpbb\plupload\plupload $plupload The plupload object + * * @return object $file Object "filespec" is returned, all further operations can be done with this object * @access public */ - function form_upload($form_name) + function form_upload($form_name, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null) { - global $user; + global $user, $request; + + $upload = $request->file($form_name); + unset($upload['local_mode']); - unset($_FILES[$form_name]['local_mode']); - $file = new filespec($_FILES[$form_name], $this); + if ($plupload) + { + $result = $plupload->handle_upload($form_name); + if (is_array($result)) + { + $upload = array_merge($upload, $result); + } + } + + $file = new filespec($upload, $this, $mimetype_guesser, $plupload); if ($file->init_error) { @@ -576,9 +622,9 @@ class fileupload } // Error array filled? - if (isset($_FILES[$form_name]['error'])) + if (isset($upload['error'])) { - $error = $this->assign_internal_error($_FILES[$form_name]['error']); + $error = $this->assign_internal_error($upload['error']); if ($error !== false) { @@ -588,7 +634,7 @@ class fileupload } // Check if empty file got uploaded (not catched by is_uploaded_file) - if (isset($_FILES[$form_name]['size']) && $_FILES[$form_name]['size'] == 0) + if (isset($upload['size']) && $upload['size'] == 0) { $file->error[] = $user->lang[$this->error_prefix . 'EMPTY_FILEUPLOAD']; return $file; @@ -627,42 +673,28 @@ class fileupload /** * Move file from another location to phpBB */ - function local_upload($source_file, $filedata = false) + function local_upload($source_file, $filedata = false, \phpbb\mimetype\guesser $mimetype_guesser = null) { - global $user; + global $user, $request; - $form_name = 'local'; + $upload = array(); - $_FILES[$form_name]['local_mode'] = true; - $_FILES[$form_name]['tmp_name'] = $source_file; + $upload['local_mode'] = true; + $upload['tmp_name'] = $source_file; if ($filedata === false) { - $_FILES[$form_name]['name'] = utf8_basename($source_file); - $_FILES[$form_name]['size'] = 0; - $mimetype = ''; - - if (function_exists('mime_content_type')) - { - $mimetype = mime_content_type($source_file); - } - - // Some browsers choke on a mimetype of application/octet-stream - if (!$mimetype || $mimetype == 'application/octet-stream') - { - $mimetype = 'application/octetstream'; - } - - $_FILES[$form_name]['type'] = $mimetype; + $upload['name'] = utf8_basename($source_file); + $upload['size'] = 0; } else { - $_FILES[$form_name]['name'] = $filedata['realname']; - $_FILES[$form_name]['size'] = $filedata['size']; - $_FILES[$form_name]['type'] = $filedata['type']; + $upload['name'] = $filedata['realname']; + $upload['size'] = $filedata['size']; + $upload['type'] = $filedata['type']; } - $file = new filespec($_FILES[$form_name], $this); + $file = new filespec($upload, $this, $mimetype_guesser); if ($file->init_error) { @@ -670,9 +702,9 @@ class fileupload return $file; } - if (isset($_FILES[$form_name]['error'])) + if (isset($upload['error'])) { - $error = $this->assign_internal_error($_FILES[$form_name]['error']); + $error = $this->assign_internal_error($upload['error']); if ($error !== false) { @@ -707,6 +739,7 @@ class fileupload } $this->common_checks($file); + $request->overwrite('local', $upload, \phpbb\request\request_interface::FILES); return $file; } @@ -716,10 +749,11 @@ class fileupload * Uploads file from given url * * @param string $upload_url URL pointing to file to upload, for example http://www.foobar.com/example.gif + * @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser * @return object $file Object "filespec" is returned, all further operations can be done with this object * @access public */ - function remote_upload($upload_url) + function remote_upload($upload_url, \phpbb\mimetype\guesser $mimetype_guesser = null) { global $user, $phpbb_root_path; @@ -898,7 +932,7 @@ class fileupload $upload_ary['tmp_name'] = $filename; - $file = new filespec($upload_ary, $this); + $file = new filespec($upload_ary, $this, $mimetype_guesser); $this->common_checks($file); return $file; @@ -1023,12 +1057,15 @@ class fileupload */ function is_valid($form_name) { - return (isset($_FILES[$form_name]) && $_FILES[$form_name]['name'] != 'none') ? true : false; + global $request; + $upload = $request->file($form_name); + + return (!empty($upload) && $upload['name'] !== 'none'); } /** - * Check for allowed extension + * Check for bad content (IE mime-sniffing) */ function valid_content(&$file) { @@ -1036,29 +1073,35 @@ class fileupload } /** - * Return image type/extension mapping + * Get image type/extension mapping + * + * @return array Array containing the image types and their extensions */ - function image_types() + static public function image_types() { - return array( - 1 => array('gif'), - 2 => array('jpg', 'jpeg'), - 3 => array('png'), - 4 => array('swf'), - 5 => array('psd'), - 6 => array('bmp'), - 7 => array('tif', 'tiff'), - 8 => array('tif', 'tiff'), - 9 => array('jpg', 'jpeg'), - 10 => array('jpg', 'jpeg'), - 11 => array('jpg', 'jpeg'), - 12 => array('jpg', 'jpeg'), - 13 => array('swc'), - 14 => array('iff'), - 15 => array('wbmp'), - 16 => array('xbm'), + $result = array( + IMAGETYPE_GIF => array('gif'), + IMAGETYPE_JPEG => array('jpg', 'jpeg'), + IMAGETYPE_PNG => array('png'), + IMAGETYPE_SWF => array('swf'), + IMAGETYPE_PSD => array('psd'), + IMAGETYPE_BMP => array('bmp'), + IMAGETYPE_TIFF_II => array('tif', 'tiff'), + IMAGETYPE_TIFF_MM => array('tif', 'tiff'), + IMAGETYPE_JPC => array('jpg', 'jpeg'), + IMAGETYPE_JP2 => array('jpg', 'jpeg'), + IMAGETYPE_JPX => array('jpg', 'jpeg'), + IMAGETYPE_JB2 => array('jpg', 'jpeg'), + IMAGETYPE_IFF => array('iff'), + IMAGETYPE_WBMP => array('wbmp'), + IMAGETYPE_XBM => array('xbm'), ); + + if (defined('IMAGETYPE_SWC')) + { + $result[IMAGETYPE_SWC] = array('swc'); + } + + return $result; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/functions_url_matcher.php b/phpBB/includes/functions_url_matcher.php new file mode 100644 index 0000000000..b965046aad --- /dev/null +++ b/phpBB/includes/functions_url_matcher.php @@ -0,0 +1,112 @@ +<?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 Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper; +use Symfony\Component\Routing\Matcher\UrlMatcher; +use Symfony\Component\Routing\RequestContext; + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Create a new UrlMatcher class and dump it into the cache file +* +* @param \phpbb\extension\manager $manager Extension manager +* @param RequestContext $context Symfony RequestContext object +* @param string $root_path Root path +* @param string $php_ext PHP file extension +* @return null +*/ +function phpbb_get_url_matcher(\phpbb\extension\manager $manager, RequestContext $context, $root_path, $php_ext) +{ + if (defined('DEBUG')) + { + return phpbb_create_url_matcher($manager, $context, $root_path); + } + + if (!phpbb_url_matcher_dumped($root_path, $php_ext)) + { + phpbb_create_dumped_url_matcher($manager, $root_path, $php_ext); + } + + return phpbb_load_url_matcher($context, $root_path, $php_ext); +} + +/** +* Create a new UrlMatcher class and dump it into the cache file +* +* @param \phpbb\extension\manager $manager Extension manager +* @param string $root_path Root path +* @param string $php_ext PHP file extension +* @return null +*/ +function phpbb_create_dumped_url_matcher(\phpbb\extension\manager $manager, $root_path, $php_ext) +{ + $provider = new \phpbb\controller\provider(); + $provider->find_routing_files($manager->get_finder()); + $routes = $provider->find($root_path)->get_routes(); + $dumper = new PhpMatcherDumper($routes); + $cached_url_matcher_dump = $dumper->dump(array( + 'class' => 'phpbb_url_matcher', + )); + + file_put_contents($root_path . 'cache/url_matcher.' . $php_ext, $cached_url_matcher_dump); +} + +/** +* Create a non-cached UrlMatcher +* +* @param \phpbb\extension\manager $manager Extension manager +* @param RequestContext $context Symfony RequestContext object +* @return UrlMatcher +*/ +function phpbb_create_url_matcher(\phpbb\extension\manager $manager, RequestContext $context, $root_path) +{ + $provider = new \phpbb\controller\provider(); + $provider->find_routing_files($manager->get_finder()); + $routes = $provider->find($root_path)->get_routes(); + return new UrlMatcher($routes, $context); +} + +/** +* Load the cached phpbb_url_matcher class +* +* @param RequestContext $context Symfony RequestContext object +* @param string $root_path Root path +* @param string $php_ext PHP file extension +* @return phpbb_url_matcher +*/ +function phpbb_load_url_matcher(RequestContext $context, $root_path, $php_ext) +{ + require($root_path . 'cache/url_matcher.' . $php_ext); + return new phpbb_url_matcher($context); +} + +/** +* Determine whether we have our dumped URL matcher +* +* The class is automatically dumped to the cache directory +* +* @param string $root_path Root path +* @param string $php_ext PHP file extension +* @return bool True if it exists, false if not +*/ +function phpbb_url_matcher_dumped($root_path, $php_ext) +{ + return file_exists($root_path . 'cache/url_matcher.' . $php_ext); +} diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php index abb057df5b..9cd662027e 100644 --- a/phpBB/includes/functions_user.php +++ b/phpBB/includes/functions_user.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -41,13 +44,13 @@ function user_get_id_name(&$user_id_ary, &$username_ary, $user_type = false) $which_ary = ($user_id_ary) ? 'user_id_ary' : 'username_ary'; - if ($$which_ary && !is_array($$which_ary)) + if (${$which_ary} && !is_array(${$which_ary})) { - $$which_ary = array($$which_ary); + ${$which_ary} = array(${$which_ary}); } - $sql_in = ($which_ary == 'user_id_ary') ? array_map('intval', $$which_ary) : array_map('utf8_clean_string', $$which_ary); - unset($$which_ary); + $sql_in = ($which_ary == 'user_id_ary') ? array_map('intval', ${$which_ary}) : array_map('utf8_clean_string', ${$which_ary}); + unset(${$which_ary}); $user_id_ary = $username_ary = array(); @@ -113,7 +116,7 @@ function update_last_username() */ function user_update_name($old_name, $new_name) { - global $config, $db, $cache; + global $config, $db, $cache, $phpbb_dispatcher; $update_ary = array( FORUMS_TABLE => array('forum_last_poster_name'), @@ -138,6 +141,17 @@ function user_update_name($old_name, $new_name) set_config('newest_username', $new_name, true); } + /** + * Update a username when it is changed + * + * @event core.update_username + * @var string old_name The old username that is replaced + * @var string new_name The new username + * @since 3.1.0-a1 + */ + $vars = array('old_name', 'new_name'); + extract($phpbb_dispatcher->trigger_event('core.update_username', compact($vars))); + // Because some tables/caches use username-specific data we need to purge this here. $cache->destroy('sql', MODERATOR_CACHE_TABLE); } @@ -147,11 +161,13 @@ function user_update_name($old_name, $new_name) * * @param mixed $user_row An array containing the following keys (and the appropriate values): username, group_id (the group to place the user in), user_email and the user_type(usually 0). Additional entries not overridden by defaults will be forwarded. * @param string $cp_data custom profile fields, see custom_profile::build_insert_sql_array +* @param array $notifications_data The notifications settings for the new user * @return the new user's ID. */ -function user_add($user_row, $cp_data = false) +function user_add($user_row, $cp_data = false, $notifications_data = null) { global $db, $user, $auth, $config, $phpbb_root_path, $phpEx; + global $phpbb_dispatcher, $phpbb_container; if (empty($user_row['username']) || !isset($user_row['group_id']) || !isset($user_row['user_email']) || !isset($user_row['user_type'])) { @@ -169,7 +185,6 @@ function user_add($user_row, $cp_data = false) 'username' => $user_row['username'], 'username_clean' => $username_clean, 'user_password' => (isset($user_row['user_password'])) ? $user_row['user_password'] : '', - 'user_pass_convert' => 0, 'user_email' => strtolower($user_row['user_email']), 'user_email_hash' => phpbb_email_hash($user_row['user_email']), 'group_id' => $user_row['group_id'], @@ -198,12 +213,9 @@ function user_add($user_row, $cp_data = false) 'user_lastpost_time' => 0, 'user_lastpage' => '', 'user_posts' => 0, - 'user_dst' => (int) $config['board_dst'], 'user_colour' => '', - 'user_occ' => '', - 'user_interests' => '', 'user_avatar' => '', - 'user_avatar_type' => 0, + 'user_avatar_type' => '', 'user_avatar_width' => 0, 'user_avatar_height' => 0, 'user_new_privmsg' => 0, @@ -246,6 +258,19 @@ function user_add($user_row, $cp_data = false) } } + /** + * Use this event to modify the values to be inserted when a user is added + * + * @event core.user_add_modify_data + * @var array user_row Array of user details submited to user_add + * @var array cp_data Array of Custom profile fields submited to user_add + * @var array sql_ary Array of data to be inserted when a user is added + * @since 3.1.0-a1 + * @change 3.1.0-b5 + */ + $vars = array('user_row', 'cp_data', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.user_add_modify_data', compact($vars))); + $sql = 'INSERT INTO ' . USERS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); $db->sql_query($sql); @@ -256,13 +281,9 @@ function user_add($user_row, $cp_data = false) { $cp_data['user_id'] = (int) $user_id; - if (!class_exists('custom_profile')) - { - include_once($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); - } - + $cp = $phpbb_container->get('profilefields.manager'); $sql = 'INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' ' . - $db->sql_build_array('INSERT', custom_profile::build_insert_sql_array($cp_data)); + $db->sql_build_array('INSERT', $cp->build_insert_sql_array($cp_data)); $db->sql_query($sql); } @@ -290,8 +311,10 @@ function user_add($user_row, $cp_data = false) if ($add_group_id) { - // Because these actions only fill the log unneccessarily we skip the add_log() entry with a little hack. :/ - $GLOBALS['skip_add_log'] = true; + global $phpbb_log; + + // Because these actions only fill the log unneccessarily we skip the add_log() entry. + $phpbb_log->disable('admin'); // Add user to "newly registered users" group and set to default group if admin specified so. if ($config['new_member_group_default']) @@ -304,7 +327,7 @@ function user_add($user_row, $cp_data = false) group_user_add($add_group_id, $user_id); } - unset($GLOBALS['skip_add_log']); + $phpbb_log->enable('admin'); } } @@ -325,38 +348,101 @@ function user_add($user_row, $cp_data = false) set_config('newest_user_colour', $row['group_colour'], true); } + // Use default notifications settings if notifications_data is not set + if ($notifications_data === null) + { + $notifications_data = array( + array( + 'item_type' => 'notification.type.post', + 'method' => 'notification.method.email', + ), + array( + 'item_type' => 'notification.type.topic', + 'method' => 'notification.method.email', + ), + ); + } + + // Subscribe user to notifications if necessary + if (!empty($notifications_data)) + { + $phpbb_notifications = $phpbb_container->get('notification_manager'); + foreach ($notifications_data as $subscription) + { + $phpbb_notifications->add_subscription($subscription['item_type'], 0, $subscription['method'], $user_id); + } + } + + /** + * Event that returns user id, user detals and user CPF of newly registared user + * + * @event core.user_add_after + * @var int user_id User id of newly registared user + * @var array user_row Array of user details submited to user_add + * @var array cp_data Array of Custom profile fields submited to user_add + * @since 3.1.0-b5 + */ + $vars = array('user_id', 'user_row', 'cp_data'); + extract($phpbb_dispatcher->trigger_event('core.user_add_after', compact($vars))); + return $user_id; } /** * Remove User * - * @param string $mode 'retain' or 'remove' - * @param int $user_id - * @param mixed $post_username + * @param string $mode Either 'retain' or 'remove' + * @param mixed $user_ids Either an array of integers or an integer + * @param bool $retain_username * @return bool */ -function user_delete($mode, $user_id, $post_username = false) +function user_delete($mode, $user_ids, $retain_username = true) { - global $cache, $config, $db, $user; + global $cache, $config, $db, $user, $phpbb_dispatcher, $phpbb_container; global $phpbb_root_path, $phpEx; + $db->sql_transaction('begin'); + + $user_rows = array(); + if (!is_array($user_ids)) + { + $user_ids = array($user_ids); + } + + $user_id_sql = $db->sql_in_set('user_id', $user_ids); + $sql = 'SELECT * FROM ' . USERS_TABLE . ' - WHERE user_id = ' . $user_id; + WHERE ' . $user_id_sql; $result = $db->sql_query($sql); - $user_row = $db->sql_fetchrow($result); + while ($row = $db->sql_fetchrow($result)) + { + $user_rows[(int) $row['user_id']] = $row; + } $db->sql_freeresult($result); - if (!$user_row) + if (empty($user_rows)) { return false; } + /** + * Event before a user is deleted + * + * @event core.delete_user_before + * @var string mode Mode of deletion (retain/delete posts) + * @var array user_ids IDs of the deleted user + * @var mixed retain_username True if username should be retained + * or false if not + * @since 3.1.0-a1 + */ + $vars = array('mode', 'user_ids', 'retain_username'); + extract($phpbb_dispatcher->trigger_event('core.delete_user_before', compact($vars))); + // Before we begin, we will remove the reports the user issued. $sql = 'SELECT r.post_id, p.topic_id FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . ' p - WHERE r.user_id = ' . $user_id . ' + WHERE ' . $db->sql_in_set('r.user_id', $user_ids) . ' AND p.post_id = r.post_id'; $result = $db->sql_query($sql); @@ -410,92 +496,119 @@ function user_delete($mode, $user_id, $post_username = false) } // Remove reports - $db->sql_query('DELETE FROM ' . REPORTS_TABLE . ' WHERE user_id = ' . $user_id); + $db->sql_query('DELETE FROM ' . REPORTS_TABLE . ' WHERE ' . $user_id_sql); - if ($user_row['user_avatar'] && $user_row['user_avatar_type'] == AVATAR_UPLOAD) - { - avatar_delete('user', $user_row); - } + $num_users_delta = 0; - switch ($mode) + // Some things need to be done in the loop (if the query changes based + // on which user is currently being deleted) + $added_guest_posts = 0; + foreach ($user_rows as $user_id => $user_row) { - case 'retain': - - $db->sql_transaction('begin'); - - if ($post_username === false) - { - $post_username = $user->lang['GUEST']; - } - - // If the user is inactive and newly registered we assume no posts from this user being there... - if ($user_row['user_type'] == USER_INACTIVE && $user_row['user_inactive_reason'] == INACTIVE_REGISTER && !$user_row['user_posts']) - { - } - else - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_last_poster_id = ' . ANONYMOUS . ", forum_last_poster_name = '" . $db->sql_escape($post_username) . "', forum_last_poster_colour = '' - WHERE forum_last_poster_id = $user_id"; - $db->sql_query($sql); + if ($user_row['user_avatar'] && $user_row['user_avatar_type'] == 'avatar.driver.upload') + { + avatar_delete('user', $user_row); + } - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET poster_id = ' . ANONYMOUS . ", post_username = '" . $db->sql_escape($post_username) . "' - WHERE poster_id = $user_id"; - $db->sql_query($sql); + // Decrement number of users if this user is active + if ($user_row['user_type'] != USER_INACTIVE && $user_row['user_type'] != USER_IGNORE) + { + --$num_users_delta; + } - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_poster = ' . ANONYMOUS . ", topic_first_poster_name = '" . $db->sql_escape($post_username) . "', topic_first_poster_colour = '' - WHERE topic_poster = $user_id"; - $db->sql_query($sql); + switch ($mode) + { + case 'retain': + if ($retain_username === false) + { + $post_username = $user->lang['GUEST']; + } + else + { + $post_username = $user_row['username']; + } - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_last_poster_id = ' . ANONYMOUS . ", topic_last_poster_name = '" . $db->sql_escape($post_username) . "', topic_last_poster_colour = '' - WHERE topic_last_poster_id = $user_id"; - $db->sql_query($sql); + // If the user is inactive and newly registered + // we assume no posts from the user, and save + // the queries + if ($user_row['user_type'] != USER_INACTIVE || $user_row['user_inactive_reason'] != INACTIVE_REGISTER || $user_row['user_posts']) + { + // When we delete these users and retain the posts, we must assign all the data to the guest user + $sql = 'UPDATE ' . FORUMS_TABLE . ' + SET forum_last_poster_id = ' . ANONYMOUS . ", forum_last_poster_name = '" . $db->sql_escape($post_username) . "', forum_last_poster_colour = '' + WHERE forum_last_poster_id = $user_id"; + $db->sql_query($sql); - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' - SET poster_id = ' . ANONYMOUS . " - WHERE poster_id = $user_id"; - $db->sql_query($sql); + $sql = 'UPDATE ' . POSTS_TABLE . ' + SET poster_id = ' . ANONYMOUS . ", post_username = '" . $db->sql_escape($post_username) . "' + WHERE poster_id = $user_id"; + $db->sql_query($sql); - // Since we change every post by this author, we need to count this amount towards the anonymous user + $sql = 'UPDATE ' . TOPICS_TABLE . ' + SET topic_poster = ' . ANONYMOUS . ", topic_first_poster_name = '" . $db->sql_escape($post_username) . "', topic_first_poster_colour = '' + WHERE topic_poster = $user_id"; + $db->sql_query($sql); - // Update the post count for the anonymous user - if ($user_row['user_posts']) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts + ' . $user_row['user_posts'] . ' - WHERE user_id = ' . ANONYMOUS; + $sql = 'UPDATE ' . TOPICS_TABLE . ' + SET topic_last_poster_id = ' . ANONYMOUS . ", topic_last_poster_name = '" . $db->sql_escape($post_username) . "', topic_last_poster_colour = '' + WHERE topic_last_poster_id = $user_id"; $db->sql_query($sql); - } - } - $db->sql_transaction('commit'); + // Since we change every post by this author, we need to count this amount towards the anonymous user - break; + if ($user_row['user_posts']) + { + $added_guest_posts += $user_row['user_posts']; + } + } + break; - case 'remove': + case 'remove': + // there is nothing variant specific to deleting posts + break; + } + } - if (!function_exists('delete_posts')) - { - include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } + if ($num_users_delta != 0) + { + set_config_count('num_users', $num_users_delta, true); + } - // Delete posts, attachments, etc. - delete_posts('poster_id', $user_id); + // Now do the invariant tasks + // all queries performed in one call of this function are in a single transaction + // so this is kosher + if ($mode == 'retain') + { + // Assign more data to the Anonymous user + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' + SET poster_id = ' . ANONYMOUS . ' + WHERE ' . $db->sql_in_set('poster_id', $user_ids); + $db->sql_query($sql); - break; + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_posts = user_posts + ' . $added_guest_posts . ' + WHERE user_id = ' . ANONYMOUS; + $db->sql_query($sql); } + else if ($mode == 'remove') + { + if (!function_exists('delete_posts')) + { + include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); + } - $db->sql_transaction('begin'); + // Delete posts, attachments, etc. + // delete_posts can handle any number of IDs in its second argument + delete_posts('poster_id', $user_ids); + } $table_ary = array(USERS_TABLE, USER_GROUP_TABLE, TOPICS_WATCH_TABLE, FORUMS_WATCH_TABLE, ACL_USERS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, FORUMS_TRACK_TABLE, PROFILE_FIELDS_DATA_TABLE, MODERATOR_CACHE_TABLE, DRAFTS_TABLE, BOOKMARKS_TABLE, SESSIONS_KEYS_TABLE, PRIVMSGS_FOLDER_TABLE, PRIVMSGS_RULES_TABLE); + // Delete the miscellaneous (non-post) data for the user foreach ($table_ary as $table) { $sql = "DELETE FROM $table - WHERE user_id = $user_id"; + WHERE " . $user_id_sql; $db->sql_query($sql); } @@ -504,40 +617,52 @@ function user_delete($mode, $user_id, $post_username = false) // Change user_id to anonymous for posts edited by this user $sql = 'UPDATE ' . POSTS_TABLE . ' SET post_edit_user = ' . ANONYMOUS . ' - WHERE post_edit_user = ' . $user_id; + WHERE ' . $db->sql_in_set('post_edit_user', $user_ids); $db->sql_query($sql); // Change user_id to anonymous for pms edited by this user $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' SET message_edit_user = ' . ANONYMOUS . ' - WHERE message_edit_user = ' . $user_id; + WHERE ' . $db->sql_in_set('message_edit_user', $user_ids); + $db->sql_query($sql); + + // Change user_id to anonymous for posts deleted by this user + $sql = 'UPDATE ' . POSTS_TABLE . ' + SET post_delete_user = ' . ANONYMOUS . ' + WHERE ' . $db->sql_in_set('post_delete_user', $user_ids); + $db->sql_query($sql); + + // Change user_id to anonymous for topics deleted by this user + $sql = 'UPDATE ' . TOPICS_TABLE . ' + SET topic_delete_user = ' . ANONYMOUS . ' + WHERE ' . $db->sql_in_set('topic_delete_user', $user_ids); $db->sql_query($sql); // Delete user log entries about this user $sql = 'DELETE FROM ' . LOG_TABLE . ' - WHERE reportee_id = ' . $user_id; + WHERE ' . $db->sql_in_set('reportee_id', $user_ids); $db->sql_query($sql); // Change user_id to anonymous for this users triggered events $sql = 'UPDATE ' . LOG_TABLE . ' SET user_id = ' . ANONYMOUS . ' - WHERE user_id = ' . $user_id; + WHERE ' . $user_id_sql; $db->sql_query($sql); // Delete the user_id from the zebra table $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE user_id = ' . $user_id . ' - OR zebra_id = ' . $user_id; + WHERE ' . $user_id_sql . ' + OR ' . $db->sql_in_set('zebra_id', $user_ids); $db->sql_query($sql); // Delete the user_id from the banlist $sql = 'DELETE FROM ' . BANLIST_TABLE . ' - WHERE ban_userid = ' . $user_id; + WHERE ' . $db->sql_in_set('ban_userid', $user_ids); $db->sql_query($sql); // Delete the user_id from the session table $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . $user_id; + WHERE ' . $db->sql_in_set('session_user_id', $user_ids); $db->sql_query($sql); // Clean the private messages tables from the user @@ -545,22 +670,32 @@ function user_delete($mode, $user_id, $post_username = false) { include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); } - phpbb_delete_user_pms($user_id); + phpbb_delete_users_pms($user_ids); + + $phpbb_notifications = $phpbb_container->get('notification_manager'); + $phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_ids); $db->sql_transaction('commit'); + /** + * Event after a user is deleted + * + * @event core.delete_user_after + * @var string mode Mode of deletion (retain/delete posts) + * @var array user_ids IDs of the deleted user + * @var mixed retain_username True if username should be retained + * or false if not + * @since 3.1.0-a1 + */ + $vars = array('mode', 'user_ids', 'retain_username'); + extract($phpbb_dispatcher->trigger_event('core.delete_user_after', compact($vars))); + // Reset newest user info if appropriate - if ($config['newest_user_id'] == $user_id) + if (in_array($config['newest_user_id'], $user_ids)) { update_last_username(); } - // Decrement number of users if this user is active - if ($user_row['user_type'] != USER_INACTIVE && $user_row['user_type'] != USER_IGNORE) - { - set_config_count('num_users', -1, true); - } - return false; } @@ -571,7 +706,7 @@ function user_delete($mode, $user_id, $post_username = false) */ function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL) { - global $config, $db, $user, $auth; + global $config, $db, $user, $auth, $phpbb_dispatcher; $deactivated = $activated = 0; $sql_statements = array(); @@ -624,6 +759,21 @@ function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL) } $db->sql_freeresult($result); + /** + * Check or modify activated/deactivated users data before submitting it to the database + * + * @event core.user_active_flip_before + * @var string mode User type changing mode, can be: flip|activate|deactivate + * @var int reason Reason for changing user type, can be: INACTIVE_REGISTER|INACTIVE_PROFILE|INACTIVE_MANUAL|INACTIVE_REMIND + * @var int activated The number of users to be activated + * @var int deactivated The number of users to be deactivated + * @var array user_id_ary Array with user ids to change user type + * @var array sql_statements Array with users data to submit to the database, keys: user ids, values: arrays with user data + * @since 3.1.4-RC1 + */ + $vars = array('mode', 'reason', 'activated', 'deactivated', 'user_id_ary', 'sql_statements'); + extract($phpbb_dispatcher->trigger_event('core.user_active_flip_before', compact($vars))); + if (sizeof($sql_statements)) { foreach ($sql_statements as $user_id => $sql_ary) @@ -637,6 +787,21 @@ function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL) $auth->acl_clear_prefetch(array_keys($sql_statements)); } + /** + * Perform additional actions after the users have been activated/deactivated + * + * @event core.user_active_flip_after + * @var string mode User type changing mode, can be: flip|activate|deactivate + * @var int reason Reason for changing user type, can be: INACTIVE_REGISTER|INACTIVE_PROFILE|INACTIVE_MANUAL|INACTIVE_REMIND + * @var int activated The number of users to be activated + * @var int deactivated The number of users to be deactivated + * @var array user_id_ary Array with user ids to change user type + * @var array sql_statements Array with users data to submit to the database, keys: user ids, values: arrays with user data + * @since 3.1.4-RC1 + */ + $vars = array('mode', 'reason', 'activated', 'deactivated', 'user_id_ary', 'sql_statements'); + extract($phpbb_dispatcher->trigger_event('core.user_active_flip_after', compact($vars))); + if ($deactivated) { set_config_count('num_users', $deactivated * (-1), true); @@ -687,11 +852,13 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas else { $ban_other = explode('-', $ban_len_other); - if (sizeof($ban_other) == 3 && ((int)$ban_other[0] < 9999) && + if (sizeof($ban_other) == 3 && ((int) $ban_other[0] < 9999) && (strlen($ban_other[0]) == 4) && (strlen($ban_other[1]) == 2) && (strlen($ban_other[2]) == 2)) { - $time_offset = (isset($user->timezone) && isset($user->dst)) ? (int) $user->timezone + (int) $user->dst : 0; - $ban_end = max($current_time, gmmktime(0, 0, 0, (int)$ban_other[1], (int)$ban_other[2], (int)$ban_other[0]) - $time_offset); + $ban_end = max($current_time, $user->create_datetime() + ->setDate((int) $ban_other[0], (int) $ban_other[1], (int) $ban_other[2]) + ->setTime(0, 0, 0) + ->getTimestamp() + $user->timezone->getOffset(new DateTime('UTC'))); } else { @@ -1052,7 +1219,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas // Update log $log_entry = ($ban_exclude) ? 'LOG_BAN_EXCLUDE_' : 'LOG_BAN_'; - // Add to moderator log, admin log and user notes + // Add to admin log, moderator log and user notes add_log('admin', $log_entry . strtoupper($mode), $ban_reason, $ban_list_log); add_log('mod', 0, 0, $log_entry . strtoupper($mode), $ban_reason, $ban_list_log); if ($mode == 'user') @@ -1259,9 +1426,18 @@ function validate_data($data, $val_ary) { $function = array_shift($validate); array_unshift($validate, $data[$var]); - $function_prefix = (function_exists('phpbb_validate_' . $function)) ? 'phpbb_validate_' : 'validate_'; - if ($result = call_user_func_array($function_prefix . $function, $validate)) + if (is_array($function)) + { + $result = call_user_func_array(array($function[0], 'validate_' . $function[1]), $validate); + } + else + { + $function_prefix = (function_exists('phpbb_validate_' . $function)) ? 'phpbb_validate_' : 'validate_'; + $result = call_user_func_array($function_prefix . $function, $validate); + } + + if ($result) { // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted. $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var); @@ -1410,6 +1586,22 @@ function validate_language_iso_name($lang_iso) } /** +* Validate Timezone Name +* +* Tests whether a timezone name is valid +* +* @param string $timezone The timezone string to test +* +* @return bool|string Either false if validation succeeded or +* a string which will be used as the error message +* (with the variable name appended) +*/ +function phpbb_validate_timezone($timezone) +{ + return (in_array($timezone, phpbb_get_timezone_identifiers($timezone))) ? false : 'TIMEZONE_INVALID'; +} + +/** * Check to see if the username has been taken, or if it is disallowed. * Also checks if it includes the " character, which we don't allow in usernames. * Used for registering, changing names, and posting anonymously with a username @@ -1440,7 +1632,7 @@ function validate_username($username, $allowed_username = false) $mbstring = $pcre = false; // generic UTF-8 character types supported? - if ((version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) && @preg_match('/\p{L}/u', 'a') !== false) + if (phpbb_pcre_utf8_support()) { $pcre = true; } @@ -1577,7 +1769,7 @@ function validate_password($password) $pcre = $mbstring = false; // generic UTF-8 character types supported? - if ((version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) && @preg_match('/\p{L}/u', 'a') !== false) + if (phpbb_pcre_utf8_support()) { $upp = '\p{Lu}'; $low = '\p{Ll}'; @@ -1650,25 +1842,21 @@ function validate_password($password) } /** -* Check to see if email address is banned or already present in the DB +* Check to see if email address is a valid address and contains a MX record * * @param string $email The email to check -* @param string $allowed_email An allowed email, default being $user->data['user_email'] * * @return mixed Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) */ -function validate_email($email, $allowed_email = false) +function phpbb_validate_email($email, $config = null) { - global $config, $db, $user; - - $email = strtolower($email); - $allowed_email = ($allowed_email === false) ? strtolower($user->data['user_email']) : strtolower($allowed_email); - - if ($allowed_email == $email) + if ($config === null) { - return false; + global $config; } + $email = strtolower($email); + if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email)) { return 'EMAIL_INVALID'; @@ -1686,6 +1874,35 @@ function validate_email($email, $allowed_email = false) } } + return false; +} + +/** +* Check to see if email address is banned or already present in the DB +* +* @param string $email The email to check +* @param string $allowed_email An allowed email, default being $user->data['user_email'] +* +* @return mixed Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) +*/ +function validate_user_email($email, $allowed_email = false) +{ + global $config, $db, $user; + + $email = strtolower($email); + $allowed_email = ($allowed_email === false) ? strtolower($user->data['user_email']) : strtolower($allowed_email); + + if ($allowed_email == $email) + { + return false; + } + + $validate_email = phpbb_validate_email($email, $config); + if ($validate_email) + { + return $validate_email; + } + if (($ban_reason = $user->check_ban(false, false, $email, true)) !== false) { return ($ban_reason === true) ? 'EMAIL_BANNED' : $ban_reason; @@ -1722,15 +1939,15 @@ function validate_jabber($jid) return false; } - $seperator_pos = strpos($jid, '@'); + $separator_pos = strpos($jid, '@'); - if ($seperator_pos === false) + if ($separator_pos === false) { return 'WRONG_DATA'; } - $username = substr($jid, 0, $seperator_pos); - $realm = substr($jid, $seperator_pos + 1); + $username = substr($jid, 0, $separator_pos); + $realm = substr($jid, $separator_pos + 1); if (strlen($username) == 0 || strlen($realm) < 3) { @@ -1966,7 +2183,7 @@ function avatar_delete($mode, $row, $clean_db = false) // Check if the users avatar is actually *not* a group avatar if ($mode == 'user') { - if (strpos($row['user_avatar'], 'g') === 0 || (((int)$row['user_avatar'] !== 0) && ((int)$row['user_avatar'] !== (int)$row['user_id']))) + if (strpos($row['user_avatar'], 'g') === 0 || (((int) $row['user_avatar'] !== 0) && ((int) $row['user_avatar'] !== (int) $row['user_id']))) { return false; } @@ -1977,6 +2194,7 @@ function avatar_delete($mode, $row, $clean_db = false) avatar_remove_db($row[$mode . '_avatar']); } $filename = get_avatar_filename($row[$mode . '_avatar']); + if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . $filename)) { @unlink($phpbb_root_path . $config['avatar_path'] . '/' . $filename); @@ -1987,140 +2205,12 @@ function avatar_delete($mode, $row, $clean_db = false) } /** -* Remote avatar linkage -*/ -function avatar_remote($data, &$error) -{ - global $config, $db, $user, $phpbb_root_path, $phpEx; - - if (!preg_match('#^(http|https|ftp)://#i', $data['remotelink'])) - { - $data['remotelink'] = 'http://' . $data['remotelink']; - } - if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.(gif|jpg|jpeg|png)$#i', $data['remotelink'])) - { - $error[] = $user->lang['AVATAR_URL_INVALID']; - return false; - } - - // Make sure getimagesize works... - if (($image_data = @getimagesize($data['remotelink'])) === false && (empty($data['width']) || empty($data['height']))) - { - $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE']; - return false; - } - - if (!empty($image_data) && ($image_data[0] < 2 || $image_data[1] < 2)) - { - $error[] = $user->lang['AVATAR_NO_SIZE']; - return false; - } - - $width = ($data['width'] && $data['height']) ? $data['width'] : $image_data[0]; - $height = ($data['width'] && $data['height']) ? $data['height'] : $image_data[1]; - - if ($width < 2 || $height < 2) - { - $error[] = $user->lang['AVATAR_NO_SIZE']; - return false; - } - - // Check image type - include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx); - $types = fileupload::image_types(); - $extension = strtolower(filespec::get_extension($data['remotelink'])); - - if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]]))) - { - if (!isset($types[$image_data[2]])) - { - $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE']; - } - else - { - $error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$image_data[2]][0], $extension); - } - return false; - } - - if ($config['avatar_max_width'] || $config['avatar_max_height']) - { - if ($width > $config['avatar_max_width'] || $height > $config['avatar_max_height']) - { - $error[] = sprintf($user->lang['AVATAR_WRONG_SIZE'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], $width, $height); - return false; - } - } - - if ($config['avatar_min_width'] || $config['avatar_min_height']) - { - if ($width < $config['avatar_min_width'] || $height < $config['avatar_min_height']) - { - $error[] = sprintf($user->lang['AVATAR_WRONG_SIZE'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], $width, $height); - return false; - } - } - - return array(AVATAR_REMOTE, $data['remotelink'], $width, $height); -} - -/** -* Avatar upload using the upload class -*/ -function avatar_upload($data, &$error) -{ - global $phpbb_root_path, $config, $db, $user, $phpEx; - - // Init upload class - include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx); - $upload = new fileupload('AVATAR_', array('jpg', 'jpeg', 'gif', 'png'), $config['avatar_filesize'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], (isset($config['mime_triggers']) ? explode('|', $config['mime_triggers']) : false)); - - if (!empty($_FILES['uploadfile']['name'])) - { - $file = $upload->form_upload('uploadfile'); - } - else - { - $file = $upload->remote_upload($data['uploadurl']); - } - - $prefix = $config['avatar_salt'] . '_'; - $file->clean_filename('avatar', $prefix, $data['user_id']); - - $destination = $config['avatar_path']; - - // Adjust destination path (no trailing slash) - if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\') - { - $destination = substr($destination, 0, -1); - } - - $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination); - if ($destination && ($destination[0] == '/' || $destination[0] == "\\")) - { - $destination = ''; - } - - // Move file and overwrite any existing image - $file->move_file($destination, true); - - if (sizeof($file->error)) - { - $file->remove(); - $error = array_merge($error, $file->error); - } - - return array(AVATAR_UPLOAD, $data['user_id'] . '_' . time() . '.' . $file->get('extension'), $file->get('width'), $file->get('height')); -} - -/** * Generates avatar filename from the database entry */ function get_avatar_filename($avatar_entry) { global $config; - if ($avatar_entry[0] === 'g') { $avatar_group = true; @@ -2136,358 +2226,111 @@ function get_avatar_filename($avatar_entry) } /** -* Avatar Gallery +* Returns an explanation string with maximum avatar settings +* +* @return string */ -function avatar_gallery($category, $avatar_select, $items_per_column, $block_var = 'avatar_row') +function phpbb_avatar_explanation_string() { - global $user, $cache, $template; - global $config, $phpbb_root_path; - - $avatar_list = array(); - - $path = $phpbb_root_path . $config['avatar_gallery_path']; - - if (!file_exists($path) || !is_dir($path)) - { - $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array()); - } - else - { - // Collect images - $dp = @opendir($path); - - if (!$dp) - { - return array($user->lang['NO_AVATAR_CATEGORY'] => array()); - } - - while (($file = readdir($dp)) !== false) - { - if ($file[0] != '.' && preg_match('#^[^&"\'<>]+$#i', $file) && is_dir("$path/$file")) - { - $avatar_row_count = $avatar_col_count = 0; - - if ($dp2 = @opendir("$path/$file")) - { - while (($sub_file = readdir($dp2)) !== false) - { - if (preg_match('#^[^&\'"<>]+\.(?:gif|png|jpe?g)$#i', $sub_file)) - { - $avatar_list[$file][$avatar_row_count][$avatar_col_count] = array( - 'file' => rawurlencode($file) . '/' . rawurlencode($sub_file), - 'filename' => rawurlencode($sub_file), - 'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $sub_file))), - ); - $avatar_col_count++; - if ($avatar_col_count == $items_per_column) - { - $avatar_row_count++; - $avatar_col_count = 0; - } - } - } - closedir($dp2); - } - } - } - closedir($dp); - } - - if (!sizeof($avatar_list)) - { - $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array()); - } - - @ksort($avatar_list); - - $category = (!$category) ? key($avatar_list) : $category; - $avatar_categories = array_keys($avatar_list); - - $s_category_options = ''; - foreach ($avatar_categories as $cat) - { - $s_category_options .= '<option value="' . $cat . '"' . (($cat == $category) ? ' selected="selected"' : '') . '>' . $cat . '</option>'; - } - - $template->assign_vars(array( - 'S_AVATARS_ENABLED' => true, - 'S_IN_AVATAR_GALLERY' => true, - 'S_CAT_OPTIONS' => $s_category_options) - ); - - $avatar_list = (isset($avatar_list[$category])) ? $avatar_list[$category] : array(); + global $config, $user; - foreach ($avatar_list as $avatar_row_ary) - { - $template->assign_block_vars($block_var, array()); - - foreach ($avatar_row_ary as $avatar_col_ary) - { - $template->assign_block_vars($block_var . '.avatar_column', array( - 'AVATAR_IMAGE' => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'], - 'AVATAR_NAME' => $avatar_col_ary['name'], - 'AVATAR_FILE' => $avatar_col_ary['filename']) - ); - - $template->assign_block_vars($block_var . '.avatar_option_column', array( - 'AVATAR_IMAGE' => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'], - 'S_OPTIONS_AVATAR' => $avatar_col_ary['filename']) - ); - } - } - - return $avatar_list; + return $user->lang('AVATAR_EXPLAIN', + $user->lang('PIXELS', (int) $config['avatar_max_width']), + $user->lang('PIXELS', (int) $config['avatar_max_height']), + round($config['avatar_filesize'] / 1024)); } +// +// Usergroup functions +// /** -* Tries to (re-)establish avatar dimensions -*/ -function avatar_get_dimensions($avatar, $avatar_type, &$error, $current_x = 0, $current_y = 0) -{ - global $config, $phpbb_root_path, $user; - - switch ($avatar_type) - { - case AVATAR_REMOTE : - break; - - case AVATAR_UPLOAD : - $avatar = $phpbb_root_path . $config['avatar_path'] . '/' . get_avatar_filename($avatar); - break; - - case AVATAR_GALLERY : - $avatar = $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar ; - break; - } - - // Make sure getimagesize works... - if (($image_data = @getimagesize($avatar)) === false) - { - $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE']; - return false; - } - - if ($image_data[0] < 2 || $image_data[1] < 2) - { - $error[] = $user->lang['AVATAR_NO_SIZE']; - return false; - } - - // try to maintain ratio - if (!(empty($current_x) && empty($current_y))) - { - if ($current_x != 0) - { - $image_data[1] = (int) floor(($current_x / $image_data[0]) * $image_data[1]); - $image_data[1] = min($config['avatar_max_height'], $image_data[1]); - $image_data[1] = max($config['avatar_min_height'], $image_data[1]); - } - if ($current_y != 0) - { - $image_data[0] = (int) floor(($current_y / $image_data[1]) * $image_data[0]); - $image_data[0] = min($config['avatar_max_width'], $image_data[1]); - $image_data[0] = max($config['avatar_min_width'], $image_data[1]); - } - } - return array($image_data[0], $image_data[1]); -} - -/** -* Uploading/Changing user avatar +* Add or edit a group. If we're editing a group we only update user +* parameters such as rank, etc. if they are changed */ -function avatar_process_user(&$error, $custom_userdata = false, $can_upload = null) +function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false) { - global $config, $phpbb_root_path, $auth, $user, $db; - - $data = array( - 'uploadurl' => request_var('uploadurl', ''), - 'remotelink' => request_var('remotelink', ''), - 'width' => request_var('width', 0), - 'height' => request_var('height', 0), - ); - - $error = validate_data($data, array( - 'uploadurl' => array('string', true, 5, 255), - 'remotelink' => array('string', true, 5, 255), - 'width' => array('string', true, 1, 3), - 'height' => array('string', true, 1, 3), - )); + global $phpbb_root_path, $config, $db, $user, $file_upload, $phpbb_container; - if (sizeof($error)) - { - return false; - } + $error = array(); - $sql_ary = array(); + // Attributes which also affect the users table + $user_attribute_ary = array('group_colour', 'group_rank', 'group_avatar', 'group_avatar_type', 'group_avatar_width', 'group_avatar_height'); - if ($custom_userdata === false) - { - $userdata = &$user->data; - } - else + // Check data. Limit group name length. + if (!utf8_strlen($name) || utf8_strlen($name) > 60) { - $userdata = &$custom_userdata; + $error[] = (!utf8_strlen($name)) ? $user->lang['GROUP_ERR_USERNAME'] : $user->lang['GROUP_ERR_USER_LONG']; } - $data['user_id'] = $userdata['user_id']; - $change_avatar = ($custom_userdata === false) ? $auth->acl_get('u_chgavatar') : true; - $avatar_select = basename(request_var('avatar_select', '')); - - // Can we upload? - if (is_null($can_upload)) + $err = group_validate_groupname($group_id, $name); + if (!empty($err)) { - $can_upload = ($config['allow_avatar_upload'] && file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $change_avatar && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false; + $error[] = $user->lang[$err]; } - if ((!empty($_FILES['uploadfile']['name']) || $data['uploadurl']) && $can_upload) - { - list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_upload($data, $error); - } - else if ($data['remotelink'] && $change_avatar && $config['allow_avatar_remote']) + if (!in_array($type, array(GROUP_OPEN, GROUP_CLOSED, GROUP_HIDDEN, GROUP_SPECIAL, GROUP_FREE))) { - list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_remote($data, $error); + $error[] = $user->lang['GROUP_ERR_TYPE']; } - else if ($avatar_select && $change_avatar && $config['allow_avatar_local']) - { - $category = basename(request_var('category', '')); - $sql_ary['user_avatar_type'] = AVATAR_GALLERY; - $sql_ary['user_avatar'] = $avatar_select; + $group_teampage = !empty($group_attributes['group_teampage']); + unset($group_attributes['group_teampage']); - // check avatar gallery - if (!is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category)) - { - $sql_ary['user_avatar'] = ''; - $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0; - } - else - { - list($sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . urldecode($sql_ary['user_avatar'])); - $sql_ary['user_avatar'] = $category . '/' . $sql_ary['user_avatar']; - } - } - else if (isset($_POST['delete']) && $change_avatar) - { - $sql_ary['user_avatar'] = ''; - $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0; - } - else if (!empty($userdata['user_avatar'])) + if (!sizeof($error)) { - // Only update the dimensions + $current_legend = \phpbb\groupposition\legend::GROUP_DISABLED; + $current_teampage = \phpbb\groupposition\teampage::GROUP_DISABLED; - if (empty($data['width']) || empty($data['height'])) + $legend = $phpbb_container->get('groupposition.legend'); + $teampage = $phpbb_container->get('groupposition.teampage'); + if ($group_id) { - if ($dims = avatar_get_dimensions($userdata['user_avatar'], $userdata['user_avatar_type'], $error, $data['width'], $data['height'])) + try { - list($guessed_x, $guessed_y) = $dims; - if (empty($data['width'])) - { - $data['width'] = $guessed_x; - } - if (empty($data['height'])) - { - $data['height'] = $guessed_y; - } + $current_legend = $legend->get_group_value($group_id); + $current_teampage = $teampage->get_group_value($group_id); } - } - if (($config['avatar_max_width'] || $config['avatar_max_height']) && - (($data['width'] != $userdata['user_avatar_width']) || $data['height'] != $userdata['user_avatar_height'])) - { - if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height']) + catch (\phpbb\groupposition\exception $exception) { - $error[] = sprintf($user->lang['AVATAR_WRONG_SIZE'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], $data['width'], $data['height']); + trigger_error($user->lang($exception->getMessage())); } } - if (!sizeof($error)) + if (!empty($group_attributes['group_legend'])) { - if ($config['avatar_min_width'] || $config['avatar_min_height']) + if (($group_id && ($current_legend == \phpbb\groupposition\legend::GROUP_DISABLED)) || !$group_id) { - if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height']) - { - $error[] = sprintf($user->lang['AVATAR_WRONG_SIZE'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], $data['width'], $data['height']); - } + // Old group currently not in the legend or new group, add at the end. + $group_attributes['group_legend'] = 1 + $legend->get_group_count(); + } + else + { + // Group stayes in the legend + $group_attributes['group_legend'] = $current_legend; } } - - if (!sizeof($error)) - { - $sql_ary['user_avatar_width'] = $data['width']; - $sql_ary['user_avatar_height'] = $data['height']; - } - } - - if (!sizeof($error)) - { - // Do we actually have any data to update? - if (sizeof($sql_ary)) + else if ($group_id && ($current_legend != \phpbb\groupposition\legend::GROUP_DISABLED)) { - $ext_new = $ext_old = ''; - if (isset($sql_ary['user_avatar'])) + // Group is removed from the legend + try { - $userdata = ($custom_userdata === false) ? $user->data : $custom_userdata; - $ext_new = (empty($sql_ary['user_avatar'])) ? '' : substr(strrchr($sql_ary['user_avatar'], '.'), 1); - $ext_old = (empty($userdata['user_avatar'])) ? '' : substr(strrchr($userdata['user_avatar'], '.'), 1); - - if ($userdata['user_avatar_type'] == AVATAR_UPLOAD) - { - // Delete old avatar if present - if ((!empty($userdata['user_avatar']) && empty($sql_ary['user_avatar'])) - || ( !empty($userdata['user_avatar']) && !empty($sql_ary['user_avatar']) && $ext_new !== $ext_old)) - { - avatar_delete('user', $userdata); - } - } + $legend->delete_group($group_id, true); } - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . (($custom_userdata === false) ? $user->data['user_id'] : $custom_userdata['user_id']); - $db->sql_query($sql); - + catch (\phpbb\groupposition\exception $exception) + { + trigger_error($user->lang($exception->getMessage())); + } + $group_attributes['group_legend'] = \phpbb\groupposition\legend::GROUP_DISABLED; + } + else + { + $group_attributes['group_legend'] = \phpbb\groupposition\legend::GROUP_DISABLED; } - } - - return (sizeof($error)) ? false : true; -} - -// -// Usergroup functions -// - -/** -* Add or edit a group. If we're editing a group we only update user -* parameters such as rank, etc. if they are changed -*/ -function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false) -{ - global $phpbb_root_path, $config, $db, $user, $file_upload; - - $error = array(); - - // Attributes which also affect the users table - $user_attribute_ary = array('group_colour', 'group_rank', 'group_avatar', 'group_avatar_type', 'group_avatar_width', 'group_avatar_height'); - - // Check data. Limit group name length. - if (!utf8_strlen($name) || utf8_strlen($name) > 60) - { - $error[] = (!utf8_strlen($name)) ? $user->lang['GROUP_ERR_USERNAME'] : $user->lang['GROUP_ERR_USER_LONG']; - } - - $err = group_validate_groupname($group_id, $name); - if (!empty($err)) - { - $error[] = $user->lang[$err]; - } - if (!in_array($type, array(GROUP_OPEN, GROUP_CLOSED, GROUP_HIDDEN, GROUP_SPECIAL, GROUP_FREE))) - { - $error[] = $user->lang['GROUP_ERR_TYPE']; - } + // Unset the objects, we don't need them anymore. + unset($legend); - if (!sizeof($error)) - { $user_ary = array(); $sql_ary = array( 'group_name' => (string) $name, @@ -2527,12 +2370,12 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow } $db->sql_freeresult($result); - if (isset($sql_ary['group_avatar']) && !$sql_ary['group_avatar']) + if (isset($sql_ary['group_avatar'])) { remove_default_avatar($group_id, $user_ary); } - if (isset($sql_ary['group_rank']) && !$sql_ary['group_rank']) + if (isset($sql_ary['group_rank'])) { remove_default_rank($group_id, $user_ary); } @@ -2580,16 +2423,55 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow $db->sql_query($sql); } + // Remove the group from the teampage, only if unselected and we are editing a group, + // which is currently displayed. + if (!$group_teampage && $group_id && $current_teampage != \phpbb\groupposition\teampage::GROUP_DISABLED) + { + try + { + $teampage->delete_group($group_id); + } + catch (\phpbb\groupposition\exception $exception) + { + trigger_error($user->lang($exception->getMessage())); + } + } + if (!$group_id) { $group_id = $db->sql_nextid(); - if (isset($sql_ary['group_avatar_type']) && $sql_ary['group_avatar_type'] == AVATAR_UPLOAD) + if (isset($sql_ary['group_avatar_type']) && $sql_ary['group_avatar_type'] == 'avatar.driver.upload') { group_correct_avatar($group_id, $sql_ary['group_avatar']); } } + try + { + if ($group_teampage && $current_teampage == \phpbb\groupposition\teampage::GROUP_DISABLED) + { + $teampage->add_group($group_id); + } + + if ($group_teampage) + { + if ($current_teampage == \phpbb\groupposition\teampage::GROUP_DISABLED) + { + $teampage->add_group($group_id); + } + } + else if ($group_id && ($current_teampage != \phpbb\groupposition\teampage::GROUP_DISABLED)) + { + $teampage->delete_group($group_id); + } + } + catch (\phpbb\groupposition\exception $exception) + { + trigger_error($user->lang($exception->getMessage())); + } + unset($teampage); + // Set user attributes $sql_ary = array(); if (sizeof($group_attributes)) @@ -2634,7 +2516,7 @@ function group_correct_avatar($group_id, $old_entry) { global $config, $db, $phpbb_root_path; - $group_id = (int)$group_id; + $group_id = (int) $group_id; $ext = substr(strrchr($old_entry, '.'), 1); $old_filename = get_avatar_filename($old_entry); $new_filename = $config['avatar_salt'] . "_g$group_id.$ext"; @@ -2660,7 +2542,7 @@ function avatar_remove_db($avatar_name) $sql = 'UPDATE ' . USERS_TABLE . " SET user_avatar = '', - user_avatar_type = 0 + user_avatar_type = '' WHERE user_avatar = '" . $db->sql_escape($avatar_name) . '\''; $db->sql_query($sql); } @@ -2671,7 +2553,7 @@ function avatar_remove_db($avatar_name) */ function group_delete($group_id, $group_name = false) { - global $db, $phpbb_root_path, $phpEx; + global $db, $cache, $auth, $user, $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container; if (!$group_name) { @@ -2712,6 +2594,33 @@ function group_delete($group_id, $group_name = false) } while ($start); + // Delete group from legend and teampage + try + { + $legend = $phpbb_container->get('groupposition.legend'); + $legend->delete_group($group_id); + unset($legend); + } + catch (\phpbb\groupposition\exception $exception) + { + // The group we want to delete does not exist. + // No reason to worry, we just continue the deleting process. + //trigger_error($user->lang($exception->getMessage())); + } + + try + { + $teampage = $phpbb_container->get('groupposition.teampage'); + $teampage->delete_group($group_id); + unset($teampage); + } + catch (\phpbb\groupposition\exception $exception) + { + // The group we want to delete does not exist. + // No reason to worry, we just continue the deleting process. + //trigger_error($user->lang($exception->getMessage())); + } + // Delete group $sql = 'DELETE FROM ' . GROUPS_TABLE . " WHERE group_id = $group_id"; @@ -2722,13 +2631,24 @@ function group_delete($group_id, $group_name = false) WHERE group_id = $group_id"; $db->sql_query($sql); + /** + * Event after a group is deleted + * + * @event core.delete_group_after + * @var int group_id ID of the deleted group + * @var string group_name Name of the deleted group + * @since 3.1.0-a1 + */ + $vars = array('group_id', 'group_name'); + extract($phpbb_dispatcher->trigger_event('core.delete_group_after', compact($vars))); + // Re-cache moderators - if (!function_exists('cache_moderators')) + if (!function_exists('phpbb_cache_moderators')) { include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); } - cache_moderators(); + phpbb_cache_moderators($db, $cache, $auth); add_log('admin', 'LOG_GROUP_DELETE', $group_name); @@ -2743,7 +2663,7 @@ function group_delete($group_id, $group_name = false) */ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $default = false, $leader = 0, $pending = 0, $group_attributes = false) { - global $db, $auth; + global $db, $auth, $phpbb_container; // We need both username and user_id info $result = user_get_id_name($user_id_ary, $username_ary); @@ -2831,6 +2751,20 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, group_update_listings($group_id); + if ($pending) + { + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + foreach ($add_id_ary as $user_id) + { + $phpbb_notifications->add_notifications('notification.type.group_request', array( + 'group_id' => $group_id, + 'user_id' => $user_id, + 'group_name' => $group_name, + )); + } + } + // Return false - no error return false; } @@ -2844,7 +2778,7 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, */ function group_user_del($group_id, $user_id_ary = false, $username_ary = false, $group_name = false) { - global $db, $auth, $config; + global $db, $auth, $config, $phpbb_dispatcher, $phpbb_container; if ($config['coppa_enable']) { @@ -2943,6 +2877,19 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false, } unset($special_group_data); + /** + * Event before users are removed from a group + * + * @event core.group_delete_user_before + * @var int group_id ID of the group from which users are deleted + * @var string group_name Name of the group + * @var array user_id_ary IDs of the users which are removed + * @var array username_ary names of the users which are removed + * @since 3.1.0-a1 + */ + $vars = array('group_id', 'group_name', 'user_id_ary', 'username_ary'); + extract($phpbb_dispatcher->trigger_event('core.group_delete_user_before', compact($vars))); + $sql = 'DELETE FROM ' . USER_GROUP_TABLE . " WHERE group_id = $group_id AND " . $db->sql_in_set('user_id', $user_id_ary); @@ -2965,6 +2912,10 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false, group_update_listings($group_id); + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + $phpbb_notifications->delete_notifications('notification.type.group_request', $user_id_ary, $group_id); + // Return false - no error return false; } @@ -2990,7 +2941,7 @@ function remove_default_avatar($group_id, $user_ids) $sql = 'SELECT * FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int)$group_id; + WHERE group_id = ' . (int) $group_id; $result = $db->sql_query($sql); if (!$row = $db->sql_fetchrow($result)) { @@ -3001,12 +2952,12 @@ function remove_default_avatar($group_id, $user_ids) $sql = 'UPDATE ' . USERS_TABLE . " SET user_avatar = '', - user_avatar_type = 0, + user_avatar_type = '', user_avatar_width = 0, user_avatar_height = 0 WHERE group_id = " . (int) $group_id . " - AND user_avatar = '" . $db->sql_escape($row['group_avatar']) . "' - AND " . $db->sql_in_set('user_id', $user_ids); + AND user_avatar = '" . $db->sql_escape($row['group_avatar']) . "' + AND " . $db->sql_in_set('user_id', $user_ids); $db->sql_query($sql); } @@ -3031,7 +2982,7 @@ function remove_default_rank($group_id, $user_ids) $sql = 'SELECT * FROM ' . GROUPS_TABLE . ' - WHERE group_id = ' . (int)$group_id; + WHERE group_id = ' . (int) $group_id; $result = $db->sql_query($sql); if (!$row = $db->sql_fetchrow($result)) { @@ -3042,10 +2993,10 @@ function remove_default_rank($group_id, $user_ids) $sql = 'UPDATE ' . USERS_TABLE . ' SET user_rank = 0 - WHERE group_id = ' . (int)$group_id . ' - AND user_rank <> 0 - AND user_rank = ' . (int)$row['group_rank'] . ' - AND ' . $db->sql_in_set('user_id', $user_ids); + WHERE group_id = ' . (int) $group_id . ' + AND user_rank <> 0 + AND user_rank = ' . (int) $row['group_rank'] . ' + AND ' . $db->sql_in_set('user_id', $user_ids); $db->sql_query($sql); } @@ -3054,7 +3005,7 @@ function remove_default_rank($group_id, $user_ids) */ function group_user_attributes($action, $group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $group_attributes = false) { - global $db, $auth, $phpbb_root_path, $phpEx, $config; + global $db, $auth, $phpbb_root_path, $phpEx, $config, $phpbb_container; // We need both username and user_id info $result = user_get_id_name($user_id_ary, $username_ary); @@ -3074,7 +3025,8 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna case 'demote': case 'promote': - $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . " + $sql = 'SELECT user_id + FROM ' . USER_GROUP_TABLE . " WHERE group_id = $group_id AND user_pending = 1 AND " . $db->sql_in_set('user_id', $user_id_ary); @@ -3106,11 +3058,10 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna AND ' . $db->sql_in_set('ug.user_id', $user_id_ary); $result = $db->sql_query($sql); - $user_id_ary = $email_users = array(); + $user_id_ary = array(); while ($row = $db->sql_fetchrow($result)) { $user_id_ary[] = $row['user_id']; - $email_users[] = $row; } $db->sql_freeresult($result); @@ -3125,27 +3076,14 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna AND " . $db->sql_in_set('user_id', $user_id_ary); $db->sql_query($sql); - // Send approved email to users... - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $messenger = new messenger(); - - foreach ($email_users as $row) - { - $messenger->template('group_approved', $row['user_lang']); - - $messenger->to($row['user_email'], $row['username']); - $messenger->im($row['user_jabber'], $row['username']); + $phpbb_notifications = $phpbb_container->get('notification_manager'); - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($row['username']), - 'GROUP_NAME' => htmlspecialchars_decode($group_name), - 'U_GROUP' => generate_board_url() . "/ucp.$phpEx?i=groups&mode=membership") - ); - - $messenger->send($row['user_notify_type']); - } - - $messenger->save_queue(); + $phpbb_notifications->add_notifications('notification.type.group_request_approved', array( + 'user_ids' => $user_id_ary, + 'group_id' => $group_id, + 'group_name' => $group_name, + )); + $phpbb_notifications->delete_notifications('notification.type.group_request', $user_id_ary, $group_id); $log = 'LOG_USERS_APPROVED'; break; @@ -3172,7 +3110,8 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna return 'NO_USERS'; } - $sql = 'SELECT user_id, group_id FROM ' . USERS_TABLE . ' + $sql = 'SELECT user_id, group_id + FROM ' . USERS_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $user_id_ary, false, true); $result = $db->sql_query($sql); @@ -3260,7 +3199,7 @@ function group_validate_groupname($group_id, $group_name) */ function group_set_user_default($group_id, $user_id_ary, $group_attributes = false, $update_listing = false) { - global $cache, $db; + global $phpbb_container, $db, $phpbb_dispatcher; if (empty($user_id_ary)) { @@ -3271,7 +3210,7 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal 'group_colour' => 'string', 'group_rank' => 'int', 'group_avatar' => 'string', - 'group_avatar_type' => 'int', + 'group_avatar_type' => 'string', 'group_avatar_width' => 'int', 'group_avatar_height' => 'int', ); @@ -3306,45 +3245,69 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal } } - // Before we update the user attributes, we will make a list of those having now the group avatar assigned - if (isset($sql_ary['user_avatar'])) + $updated_sql_ary = $sql_ary; + + // Before we update the user attributes, we will update the rank for users that don't have a custom rank + if (isset($sql_ary['user_rank'])) { - // Ok, get the original avatar data from users having an uploaded one (we need to remove these from the filesystem) - $sql = 'SELECT user_id, group_id, user_avatar - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary) . ' - AND user_avatar_type = ' . AVATAR_UPLOAD; - $result = $db->sql_query($sql); + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', array('user_rank' => $sql_ary['user_rank'])) . ' + WHERE user_rank = 0 + AND ' . $db->sql_in_set('user_id', $user_id_ary); + $db->sql_query($sql); + unset($sql_ary['user_rank']); + } - while ($row = $db->sql_fetchrow($result)) + // Before we update the user attributes, we will update the avatar for users that don't have a custom avatar + $avatar_options = array('user_avatar', 'user_avatar_type', 'user_avatar_height', 'user_avatar_width'); + + if (isset($sql_ary['user_avatar'])) + { + $avatar_sql_ary = array(); + foreach ($avatar_options as $avatar_option) { - avatar_delete('user', $row); - } - $db->sql_freeresult($result); + if (isset($sql_ary[$avatar_option])) + { + $avatar_sql_ary[$avatar_option] = $sql_ary[$avatar_option]; + } + } + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $avatar_sql_ary) . " + WHERE user_avatar = '' + AND " . $db->sql_in_set('user_id', $user_id_ary); + $db->sql_query($sql); } - else + + // Remove the avatar options, as we already updated them + foreach ($avatar_options as $avatar_option) { - unset($sql_ary['user_avatar_type']); - unset($sql_ary['user_avatar_height']); - unset($sql_ary['user_avatar_width']); + unset($sql_ary[$avatar_option]); } - $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); + if (!empty($sql_ary)) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE ' . $db->sql_in_set('user_id', $user_id_ary); + $db->sql_query($sql); + } if (isset($sql_ary['user_colour'])) { // Update any cached colour information for these users - $sql = 'UPDATE ' . FORUMS_TABLE . " SET forum_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' + $sql = 'UPDATE ' . FORUMS_TABLE . " + SET forum_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' WHERE " . $db->sql_in_set('forum_last_poster_id', $user_id_ary); $db->sql_query($sql); - $sql = 'UPDATE ' . TOPICS_TABLE . " SET topic_first_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' + $sql = 'UPDATE ' . TOPICS_TABLE . " + SET topic_first_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' WHERE " . $db->sql_in_set('topic_poster', $user_id_ary); $db->sql_query($sql); - $sql = 'UPDATE ' . TOPICS_TABLE . " SET topic_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' + $sql = 'UPDATE ' . TOPICS_TABLE . " + SET topic_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' WHERE " . $db->sql_in_set('topic_last_poster_id', $user_id_ary); $db->sql_query($sql); @@ -3356,13 +3319,30 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal } } + // Make all values available for the event + $sql_ary = $updated_sql_ary; + + /** + * Event when the default group is set for an array of users + * + * @event core.user_set_default_group + * @var int group_id ID of the group + * @var array user_id_ary IDs of the users + * @var array group_attributes Group attributes which were changed + * @var array update_listing Update the list of moderators and foes + * @var array sql_ary User attributes which were changed + * @since 3.1.0-a1 + */ + $vars = array('group_id', 'user_id_ary', 'group_attributes', 'update_listing', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.user_set_default_group', compact($vars))); + if ($update_listing) { group_update_listings($group_id); } // Because some tables/caches use usercolour-specific data we need to purge this here. - $cache->destroy('sql', MODERATOR_CACHE_TABLE); + $phpbb_container->get('cache.driver')->destroy('sql', MODERATOR_CACHE_TABLE); } /** @@ -3461,7 +3441,7 @@ function group_memberships($group_id_ary = false, $user_id_ary = false, $return_ */ function group_update_listings($group_id) { - global $auth; + global $db, $cache, $auth; $hold_ary = $auth->acl_group_raw_data($group_id, array('a_', 'm_')); @@ -3503,22 +3483,22 @@ function group_update_listings($group_id) if ($mod_permissions) { - if (!function_exists('cache_moderators')) + if (!function_exists('phpbb_cache_moderators')) { global $phpbb_root_path, $phpEx; include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); } - cache_moderators(); + phpbb_cache_moderators($db, $cache, $auth); } if ($mod_permissions || $admin_permissions) { - if (!function_exists('update_foes')) + if (!function_exists('phpbb_update_foes')) { global $phpbb_root_path, $phpEx; include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); } - update_foes(array($group_id)); + phpbb_update_foes($db, $auth, array($group_id)); } } @@ -3600,9 +3580,12 @@ function remove_newly_registered($user_id, $user_data = false) * * @param array $user_ids Array of users' ids to check for banning, * leave empty to get complete list of banned ids +* @param bool|int $ban_end Bool True to get users currently banned +* Bool False to only get permanently banned users +* Int Unix timestamp to get users banned until that time * @return array Array of banned users' ids if any, empty array otherwise */ -function phpbb_get_banned_user_ids($user_ids = array()) +function phpbb_get_banned_user_ids($user_ids = array(), $ban_end = true) { global $db; @@ -3614,9 +3597,26 @@ function phpbb_get_banned_user_ids($user_ids = array()) $sql = 'SELECT ban_userid FROM ' . BANLIST_TABLE . " WHERE $sql_user_ids - AND ban_exclude <> 1 - AND (ban_end > " . time() . ' + AND ban_exclude <> 1"; + + if ($ban_end === true) + { + // Banned currently + $sql .= " AND (ban_end > " . time() . ' + OR ban_end = 0)'; + } + else if ($ban_end === false) + { + // Permanently banned + $sql .= " AND ban_end = 0"; + } + else + { + // Banned until a specified time + $sql .= " AND (ban_end > " . (int) $ban_end . ' OR ban_end = 0)'; + } + $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { @@ -3628,4 +3628,22 @@ function phpbb_get_banned_user_ids($user_ids = array()) return $banned_ids_list; } -?>
\ No newline at end of file +/** +* Function for assigning a template var if the zebra module got included +*/ +function phpbb_module_zebra($mode, &$module_row) +{ + global $template; + + $template->assign_var('S_ZEBRA_ENABLED', true); + + if ($mode == 'friends') + { + $template->assign_var('S_ZEBRA_FRIENDS_ENABLED', true); + } + + if ($mode == 'foes') + { + $template->assign_var('S_ZEBRA_FOES_ENABLED', true); + } +} diff --git a/phpBB/includes/hooks/index.php b/phpBB/includes/hooks/index.php index aa85e63f32..805e0eea1a 100644 --- a/phpBB/includes/hooks/index.php +++ b/phpBB/includes/hooks/index.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2007 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,7 +21,6 @@ if (!defined('IN_PHPBB')) /** * phpBB Hook Class -* @package phpBB3 */ class phpbb_hook { @@ -246,5 +248,3 @@ class phpbb_hook } } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/info/mcp_ban.php b/phpBB/includes/mcp/info/mcp_ban.php index 383df30498..4aedbc8558 100644 --- a/phpBB/includes/mcp/info/mcp_ban.php +++ b/phpBB/includes/mcp/info/mcp_ban.php @@ -1,16 +1,16 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class mcp_ban_info { function module() @@ -35,5 +35,3 @@ class mcp_ban_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/info/mcp_logs.php b/phpBB/includes/mcp/info/mcp_logs.php index fe2f9fa1d7..c6482c1255 100644 --- a/phpBB/includes/mcp/info/mcp_logs.php +++ b/phpBB/includes/mcp/info/mcp_logs.php @@ -1,16 +1,16 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class mcp_logs_info { function module() @@ -35,5 +35,3 @@ class mcp_logs_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/info/mcp_main.php b/phpBB/includes/mcp/info/mcp_main.php index 9755cdfc07..81ccdbd1cd 100644 --- a/phpBB/includes/mcp/info/mcp_main.php +++ b/phpBB/includes/mcp/info/mcp_main.php @@ -1,16 +1,16 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class mcp_main_info { function module() @@ -36,5 +36,3 @@ class mcp_main_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/info/mcp_notes.php b/phpBB/includes/mcp/info/mcp_notes.php index afe232e5b5..4b8c255fe2 100644 --- a/phpBB/includes/mcp/info/mcp_notes.php +++ b/phpBB/includes/mcp/info/mcp_notes.php @@ -1,16 +1,16 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class mcp_notes_info { function module() @@ -34,5 +34,3 @@ class mcp_notes_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/info/mcp_pm_reports.php b/phpBB/includes/mcp/info/mcp_pm_reports.php index 84f15b7107..8670b71084 100644 --- a/phpBB/includes/mcp/info/mcp_pm_reports.php +++ b/phpBB/includes/mcp/info/mcp_pm_reports.php @@ -1,16 +1,16 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class mcp_pm_reports_info { function module() @@ -35,5 +35,3 @@ class mcp_pm_reports_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/info/mcp_queue.php b/phpBB/includes/mcp/info/mcp_queue.php index 7a256642b9..556c3902b0 100644 --- a/phpBB/includes/mcp/info/mcp_queue.php +++ b/phpBB/includes/mcp/info/mcp_queue.php @@ -1,16 +1,16 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class mcp_queue_info { function module() @@ -22,6 +22,8 @@ class mcp_queue_info 'modes' => array( 'unapproved_topics' => array('title' => 'MCP_QUEUE_UNAPPROVED_TOPICS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')), 'unapproved_posts' => array('title' => 'MCP_QUEUE_UNAPPROVED_POSTS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')), + 'deleted_topics' => array('title' => 'MCP_QUEUE_DELETED_TOPICS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')), + 'deleted_posts' => array('title' => 'MCP_QUEUE_DELETED_POSTS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')), 'approve_details' => array('title' => 'MCP_QUEUE_APPROVE_DETAILS', 'auth' => 'acl_m_approve,$id || (!$id && aclf_m_approve)', 'cat' => array('MCP_QUEUE')), ), ); @@ -35,5 +37,3 @@ class mcp_queue_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/info/mcp_reports.php b/phpBB/includes/mcp/info/mcp_reports.php index 3893ba5abb..31fee19d79 100644 --- a/phpBB/includes/mcp/info/mcp_reports.php +++ b/phpBB/includes/mcp/info/mcp_reports.php @@ -1,16 +1,16 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class mcp_reports_info { function module() @@ -35,5 +35,3 @@ class mcp_reports_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/info/mcp_warn.php b/phpBB/includes/mcp/info/mcp_warn.php index 2b0b09f75a..d85499f280 100644 --- a/phpBB/includes/mcp/info/mcp_warn.php +++ b/phpBB/includes/mcp/info/mcp_warn.php @@ -1,16 +1,16 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class mcp_warn_info { function module() @@ -36,5 +36,3 @@ class mcp_warn_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_ban.php b/phpBB/includes/mcp/mcp_ban.php index d9f5eb8f22..4d2151fded 100644 --- a/phpBB/includes/mcp/mcp_ban.php +++ b/phpBB/includes/mcp/mcp_ban.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,16 +19,13 @@ if (!defined('IN_PHPBB')) exit; } -/** -* @package mcp -*/ class mcp_ban { var $u_action; function main($id, $mode) { - global $config, $db, $user, $auth, $template, $cache; + global $db, $user, $auth, $template, $request, $phpbb_dispatcher; global $phpbb_root_path, $phpEx; include($phpbb_root_path . 'includes/functions_user.' . $phpEx); @@ -33,55 +33,133 @@ class mcp_ban // Include the admin banning interface... include($phpbb_root_path . 'includes/acp/acp_ban.' . $phpEx); - $bansubmit = (isset($_POST['bansubmit'])) ? true : false; - $unbansubmit = (isset($_POST['unbansubmit'])) ? true : false; - $current_time = time(); + $bansubmit = $request->is_set_post('bansubmit'); + $unbansubmit = $request->is_set_post('unbansubmit'); $user->add_lang(array('acp/ban', 'acp/users')); $this->tpl_name = 'mcp_ban'; + /** + * Use this event to pass perform actions when a ban is issued or revoked + * + * @event core.mcp_ban_main + * @var bool bansubmit True if a ban is issued + * @var bool unbansubmit True if a ban is removed + * @var string mode Mode of the ban that is being worked on + * @since 3.1.0-RC5 + */ + $vars = array( + 'bansubmit', + 'unbansubmit', + 'mode', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_ban_main', compact($vars))); + // Ban submitted? if ($bansubmit) { // Grab the list of entries - $ban = request_var('ban', '', ($mode === 'user') ? true : false); - - if ($mode === 'user') - { - $ban = utf8_normalize_nfc($ban); - } - - $ban_len = request_var('banlength', 0); - $ban_len_other = request_var('banlengthother', ''); - $ban_exclude = request_var('banexclude', 0); - $ban_reason = utf8_normalize_nfc(request_var('banreason', '', true)); - $ban_give_reason = utf8_normalize_nfc(request_var('bangivereason', '', true)); + $ban = $request->variable('ban', '', $mode === 'user'); + $ban_length = $request->variable('banlength', 0); + $ban_length_other = $request->variable('banlengthother', ''); + $ban_exclude = $request->variable('banexclude', 0); + $ban_reason = $request->variable('banreason', '', true); + $ban_give_reason = $request->variable('bangivereason', '', true); if ($ban) { if (confirm_box(true)) { - user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reason, $ban_give_reason); + $abort_ban = false; + /** + * Use this event to modify the ban details before the ban is performed + * + * @event core.mcp_ban_before + * @var string mode One of the following: user, ip, email + * @var string ban Either string or array with usernames, ips or email addresses + * @var int ban_length Ban length in minutes + * @var string ban_length_other Ban length as a date (YYYY-MM-DD) + * @var bool ban_exclude Are we banning or excluding from another ban + * @var string ban_reason Ban reason displayed to moderators + * @var string ban_give_reason Ban reason displayed to the banned user + * @var mixed abort_ban Either false, or an error message that is displayed to the user. + * If a string is given the bans are not issued. + * @since 3.1.0-RC5 + */ + $vars = array( + 'mode', + 'ban', + 'ban_length', + 'ban_length_other', + 'ban_exclude', + 'ban_reason', + 'ban_give_reason', + 'abort_ban', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_ban_before', compact($vars))); + + if ($abort_ban) + { + trigger_error($abort_ban); + } + user_ban($mode, $ban, $ban_length, $ban_length_other, $ban_exclude, $ban_reason, $ban_give_reason); + + /** + * Use this event to perform actions after the ban has been performed + * + * @event core.mcp_ban_after + * @var string mode One of the following: user, ip, email + * @var string ban Either string or array with usernames, ips or email addresses + * @var int ban_length Ban length in minutes + * @var string ban_length_other Ban length as a date (YYYY-MM-DD) + * @var bool ban_exclude Are we banning or excluding from another ban + * @var string ban_reason Ban reason displayed to moderators + * @var string ban_give_reason Ban reason displayed to the banned user + * @since 3.1.0-RC5 + */ + $vars = array( + 'mode', + 'ban', + 'ban_length', + 'ban_length_other', + 'ban_exclude', + 'ban_reason', + 'ban_give_reason', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_ban_after', compact($vars))); trigger_error($user->lang['BAN_UPDATE_SUCCESSFUL'] . '<br /><br /><a href="' . $this->u_action . '">« ' . $user->lang['BACK_TO_PREV'] . '</a>'); } else { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( + $hidden_fields = array( 'mode' => $mode, 'ban' => $ban, 'bansubmit' => true, - 'banlength' => $ban_len, - 'banlengthother' => $ban_len_other, + 'banlength' => $ban_length, + 'banlengthother' => $ban_length_other, 'banexclude' => $ban_exclude, 'banreason' => $ban_reason, - 'bangivereason' => $ban_give_reason))); + 'bangivereason' => $ban_give_reason, + ); + + /** + * Use this event to pass data from the ban form to the confirmation screen + * + * @event core.mcp_ban_confirm + * @var array hidden_fields Hidden fields that are passed through the confirm screen + * @since 3.1.0-RC5 + */ + $vars = array('hidden_fields'); + extract($phpbb_dispatcher->trigger_event('core.mcp_ban_confirm', compact($vars))); + + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($hidden_fields)); } } } else if ($unbansubmit) { - $ban = request_var('unban', array('')); + $ban = $request->variable('unban', array('')); if ($ban) { @@ -157,9 +235,9 @@ class mcp_ban } // As a "service" we will check if any post id is specified and populate the username of the poster id if given - $post_id = request_var('p', 0); - $user_id = request_var('u', 0); - $username = $pre_fill = false; + $post_id = $request->variable('p', 0); + $user_id = $request->variable('u', 0); + $pre_fill = false; if ($user_id && $user_id <> ANONYMOUS) { @@ -172,7 +250,7 @@ class mcp_ban case 'user': $pre_fill = (string) $db->sql_fetchfield('username'); break; - + case 'ip': $pre_fill = (string) $db->sql_fetchfield('user_ip'); break; @@ -185,7 +263,7 @@ class mcp_ban } else if ($post_id) { - $post_info = get_post_data($post_id, 'm_ban'); + $post_info = phpbb_get_post_data($post_id, 'm_ban'); if (sizeof($post_info) && !empty($post_info[$post_id])) { @@ -215,5 +293,3 @@ class mcp_ban } } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index 04e0e70f1d..c18ca1aa1d 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -23,6 +26,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) { global $template, $db, $user, $auth, $cache, $module; global $phpEx, $phpbb_root_path, $config; + global $request, $phpbb_dispatcher, $phpbb_container; $user->add_lang(array('viewtopic', 'viewforum')); @@ -34,7 +38,10 @@ function mcp_forum_view($id, $mode, $action, $forum_info) if ($merge_select) { // Fixes a "bug" that makes forum_view use the same ordering as topic_view - unset($_POST['sk'], $_POST['sd'], $_REQUEST['sk'], $_REQUEST['sd']); + $request->overwrite('sk', null); + $request->overwrite('sd', null); + $request->overwrite('sk', null, \phpbb\request\request_interface::POST); + $request->overwrite('sd', null, \phpbb\request\request_interface::POST); } $forum_id = $forum_info['forum_id']; @@ -70,6 +77,8 @@ function mcp_forum_view($id, $mode, $action, $forum_info) break; } + $pagination = $phpbb_container->get('pagination'); + $selected_ids = ''; if (sizeof($post_id_list) && $action != 'merge_topics') { @@ -93,11 +102,14 @@ function mcp_forum_view($id, $mode, $action, $forum_info) $sort_days = $total = 0; $sort_key = $sort_dir = ''; $sort_by_sql = $sort_order_sql = array(); - mcp_sorting('viewforum', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id); + phpbb_mcp_sorting('viewforum', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id); - $forum_topics = ($total == -1) ? $forum_info['forum_topics'] : $total; + $forum_topics = ($total == -1) ? $forum_info['forum_topics_approved'] : $total; $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : ''; + $base_url = $url . "&i=$id&action=$action&mode=$mode&sd=$sort_dir&sk=$sort_key&st=$sort_days" . (($merge_select) ? $selected_ids : ''); + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $forum_topics, $topics_per_page, $start); + $template->assign_vars(array( 'ACTION' => $action, 'FORUM_NAME' => $forum_info['forum_name'], @@ -110,6 +122,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) 'S_CAN_REPORT' => $auth->acl_get('m_report', $forum_id), 'S_CAN_DELETE' => $auth->acl_get('m_delete', $forum_id), + 'S_CAN_RESTORE' => $auth->acl_get('m_approve', $forum_id), 'S_CAN_MERGE' => $auth->acl_get('m_merge', $forum_id), 'S_CAN_MOVE' => $auth->acl_get('m_move', $forum_id), 'S_CAN_FORK' => $auth->acl_get('m_', $forum_id), @@ -126,9 +139,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) 'S_MCP_ACTION' => $url . "&i=$id&forum_action=$action&mode=$mode&start=$start" . (($merge_select) ? $selected_ids : ''), - 'PAGINATION' => generate_pagination($url . "&i=$id&action=$action&mode=$mode&sd=$sort_dir&sk=$sort_key&st=$sort_days" . (($merge_select) ? $selected_ids : ''), $forum_topics, $topics_per_page, $start), - 'PAGE_NUMBER' => on_page($forum_topics, $topics_per_page, $start), - 'TOTAL_TOPICS' => ($forum_topics == 1) ? $user->lang['VIEW_FORUM_TOPIC'] : sprintf($user->lang['VIEW_FORUM_TOPICS'], $forum_topics), + 'TOTAL_TOPICS' => $user->lang('VIEW_FORUM_TOPICS', (int) $forum_topics), )); // Grab icons @@ -146,12 +157,30 @@ function mcp_forum_view($id, $mode, $action, $forum_info) $read_tracking_join = $read_tracking_select = ''; } - $sql = "SELECT t.topic_id - FROM " . TOPICS_TABLE . " t - WHERE t.forum_id IN($forum_id, 0) - " . (($auth->acl_get('m_approve', $forum_id)) ? '' : 'AND t.topic_approved = 1') . " + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + + $sql = 'SELECT t.topic_id + FROM ' . TOPICS_TABLE . ' t + WHERE t.forum_id = ' . $forum_id . ' + AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.') . " $limit_time_sql ORDER BY t.topic_type DESC, $sort_order_sql"; + + /** + * Modify SQL query before MCP forum view topic list is queried + * + * @event core.mcp_view_forum_modify_sql + * @var string sql SQL query for forum view topic list + * @var int forum_id ID of the forum + * @var string limit_time_sql SQL query part for limit time + * @var string sort_order_sql SQL query part for sort order + * @var int topics_per_page Number of topics per page + * @var int start Start value + * @since 3.1.2-RC1 + */ + $vars = array('sql', 'forum_id', 'limit_time_sql', 'sort_order_sql', 'topics_per_page', 'start'); + extract($phpbb_dispatcher->trigger_event('core.mcp_view_forum_modify_sql', compact($vars))); + $result = $db->sql_query_limit($sql, $topics_per_page, $start); $topic_list = $topic_tracking_info = array(); @@ -184,11 +213,11 @@ function mcp_forum_view($id, $mode, $action, $forum_info) { if ($config['load_db_lastread']) { - $topic_tracking_info = get_topic_tracking($forum_id, $topic_list, $topic_rows, array($forum_id => $forum_info['mark_time']), array()); + $topic_tracking_info = get_topic_tracking($forum_id, $topic_list, $topic_rows, array($forum_id => $forum_info['mark_time'])); } else { - $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_list, array()); + $topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_list); } } @@ -198,7 +227,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) $row = &$topic_rows[$topic_id]; - $replies = ($auth->acl_get('m_approve', $forum_id)) ? $row['topic_replies_real'] : $row['topic_replies']; + $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1; if ($row['topic_status'] == ITEM_MOVED) { @@ -215,18 +244,21 @@ function mcp_forum_view($id, $mode, $action, $forum_info) $topic_title = censor_text($row['topic_title']); - $topic_unapproved = (!$row['topic_approved'] && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false; - $posts_unapproved = ($row['topic_approved'] && $row['topic_replies'] < $row['topic_replies_real'] && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false; + $topic_unapproved = (($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false; + $posts_unapproved = ($row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false; + $topic_deleted = $row['topic_visibility'] == ITEM_DELETED; $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? $url . '&i=queue&mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . '&t=' . $row['topic_id'] : ''; + $u_mcp_queue = (!$u_mcp_queue && $topic_deleted) ? $url . '&i=queue&mode=deleted_topics&t=' . $topic_id : $u_mcp_queue; $topic_row = array( 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', + 'TOPIC_IMG_STYLE' => $folder_img, 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'TOPIC_FOLDER_IMG_SRC' => $user->img($folder_img, $folder_alt, false, '', 'src'), 'TOPIC_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['img'] : '', 'TOPIC_ICON_IMG_WIDTH' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '', 'TOPIC_ICON_IMG_HEIGHT' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['height'] : '', 'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '', + 'DELETED_IMG' => ($topic_deleted) ? $user->img('icon_topic_deleted', 'POSTS_DELETED') : '', 'TOPIC_AUTHOR' => get_username_string('username', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']), 'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']), @@ -240,7 +272,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) 'TOPIC_TYPE' => $topic_type, 'TOPIC_TITLE' => $topic_title, - 'REPLIES' => ($auth->acl_get('m_approve', $row['forum_id'])) ? $row['topic_replies_real'] : $row['topic_replies'], + 'REPLIES' => $phpbb_content_visibility->get_count('topic_posts', $row, $row['forum_id']) - 1, 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']), 'FIRST_POST_TIME' => $user->format_date($row['topic_time']), 'LAST_POST_SUBJECT' => $row['topic_last_post_subject'], @@ -249,6 +281,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && empty($row['topic_moved_id']) && $auth->acl_get('m_report', $row['forum_id'])) ? true : false, 'S_TOPIC_UNAPPROVED' => $topic_unapproved, 'S_POSTS_UNAPPROVED' => $posts_unapproved, + 'S_TOPIC_DELETED' => $topic_deleted, 'S_UNREAD_TOPIC' => $unread_topic, ); @@ -283,6 +316,17 @@ function mcp_forum_view($id, $mode, $action, $forum_info) )); } + /** + * Modify the topic data before it is assigned to the template in MCP + * + * @event core.mcp_view_forum_modify_topicrow + * @var array row Array with topic data + * @var array topic_row Template array with topic data + * @since 3.1.0-a1 + */ + $vars = array('row', 'topic_row'); + extract($phpbb_dispatcher->trigger_event('core.mcp_view_forum_modify_topicrow', compact($vars))); + $template->assign_block_vars('topicrow', $topic_row); } unset($topic_rows); @@ -300,7 +344,7 @@ function mcp_resync_topics($topic_ids) trigger_error('NO_TOPIC_SELECTED'); } - if (!check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_'))) + if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_'))) { return; } @@ -350,14 +394,22 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) return; } - $topic_data = get_topic_data(array($to_topic_id), 'm_merge'); + $sync_topics = array_merge($topic_ids, array($to_topic_id)); + + $topic_data = phpbb_get_topic_data($sync_topics, 'm_merge'); - if (!sizeof($topic_data)) + if (!sizeof($topic_data) || empty($topic_data[$to_topic_id])) { $template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']); return; } + $sync_forums = array(); + foreach ($topic_data as $data) + { + $sync_forums[$data['forum_id']] = $data['forum_id']; + } + $topic_data = $topic_data[$to_topic_id]; $post_id_list = request_var('post_id_list', array(0)); @@ -384,7 +436,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) return; } - if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_merge'))) + if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_merge'))) { return; } @@ -408,7 +460,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) { $to_forum_id = $topic_data['forum_id']; - move_posts($post_id_list, $to_topic_id); + move_posts($post_id_list, $to_topic_id, false); add_log('mod', $to_forum_id, $to_topic_id, 'LOG_MERGE', $topic_data['topic_title']); // Message and return links @@ -425,26 +477,22 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) // Update the bookmarks table. phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $topic_ids, $to_topic_id); + // Re-sync the topics and forums because the auto-sync was deactivated in the call of move_posts() + sync('topic_reported', 'topic_id', $sync_topics); + sync('topic_attachment', 'topic_id', $sync_topics); + sync('topic', 'topic_id', $sync_topics, true); + sync('forum', 'forum_id', $sync_forums, true, true); + // Link to the new topic $return_link .= (($return_link) ? '<br /><br />' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_forum_id . '&t=' . $to_topic_id) . '">', '</a>'); - } - else - { - confirm_box(false, 'MERGE_TOPICS', $s_hidden_fields); - } - - $redirect = request_var('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); + $redirect = request_var('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&t=$to_topic_id"); + $redirect = reapply_sid($redirect); - if (!$success_msg) - { - return; + meta_refresh(3, $redirect); + trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link); } else { - meta_refresh(3, append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$to_forum_id&t=$to_topic_id")); - trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link); + confirm_box(false, 'MERGE_TOPICS', $s_hidden_fields); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_front.php b/phpBB/includes/mcp/mcp_front.php index af262baa29..500db55456 100644 --- a/phpBB/includes/mcp/mcp_front.php +++ b/phpBB/includes/mcp/mcp_front.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -23,6 +26,7 @@ function mcp_front_view($id, $mode, $action) { global $phpEx, $phpbb_root_path, $config; global $template, $db, $user, $auth, $module; + global $phpbb_dispatcher; // Latest 5 unapproved if ($module->loaded('queue')) @@ -39,16 +43,14 @@ function mcp_front_view($id, $mode, $action) { $sql = 'SELECT COUNT(post_id) AS total FROM ' . POSTS_TABLE . ' - WHERE forum_id IN (0, ' . implode(', ', $forum_list) . ') - AND post_approved = 0'; + WHERE ' . $db->sql_in_set('forum_id', $forum_list) . ' + AND ' . $db->sql_in_set('post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)); $result = $db->sql_query($sql); $total = (int) $db->sql_fetchfield('total'); $db->sql_freeresult($result); if ($total) { - $global_id = $forum_list[0]; - $sql = 'SELECT forum_id, forum_name FROM ' . FORUMS_TABLE . ' WHERE ' . $db->sql_in_set('forum_id', $forum_list); @@ -62,9 +64,9 @@ function mcp_front_view($id, $mode, $action) $sql = 'SELECT post_id FROM ' . POSTS_TABLE . ' - WHERE forum_id IN (0, ' . implode(', ', $forum_list) . ') - AND post_approved = 0 - ORDER BY post_time DESC'; + WHERE ' . $db->sql_in_set('forum_id', $forum_list) . ' + AND ' . $db->sql_in_set('post_visibility', array(ITEM_UNAPPROVED, ITEM_REAPPROVE)) . ' + ORDER BY post_time DESC, post_id DESC'; $result = $db->sql_query_limit($sql, 5); while ($row = $db->sql_fetchrow($result)) @@ -79,29 +81,36 @@ function mcp_front_view($id, $mode, $action) } } + /** + * Alter list of posts and total as required + * + * @event core.mcp_front_view_queue_postid_list_after + * @var int total Number of unapproved posts + * @var array post_list List of unapproved posts + * @var array forum_list List of forums that contain the posts + * @var array forum_names Associative array with forum_id as key and it's corresponding forum_name as value + * @since 3.1.0-RC3 + */ + $vars = array('total', 'post_list', 'forum_list', 'forum_names'); + extract($phpbb_dispatcher->trigger_event('core.mcp_front_view_queue_postid_list_after', compact($vars))); + if ($total) { - $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.username, u.username_clean, u.user_colour, t.topic_id, t.topic_title, t.topic_first_post_id, p.forum_id + $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.post_attachment, p.poster_id, p.post_username, u.username, u.username_clean, u.user_colour, t.topic_id, t.topic_title, t.topic_first_post_id, p.forum_id FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . USERS_TABLE . ' u WHERE ' . $db->sql_in_set('p.post_id', $post_list) . ' AND t.topic_id = p.topic_id AND p.poster_id = u.user_id - ORDER BY p.post_time DESC'; + ORDER BY p.post_time DESC, p.post_id DESC'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - $global_topic = ($row['forum_id']) ? false : true; - if ($global_topic) - { - $row['forum_id'] = $global_id; - } - $template->assign_block_vars('unapproved', array( 'U_POST_DETAILS' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=approve_details&f=' . $row['forum_id'] . '&p=' . $row['post_id']), - 'U_MCP_FORUM' => (!$global_topic) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=forum_view&f=' . $row['forum_id']) : '', + 'U_MCP_FORUM' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=forum_view&f=' . $row['forum_id']), 'U_MCP_TOPIC' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=topic_view&f=' . $row['forum_id'] . '&t=' . $row['topic_id']), - 'U_FORUM' => (!$global_topic) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : '', + 'U_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']), 'U_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id'] . '&t=' . $row['topic_id']), 'AUTHOR_FULL' => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour']), @@ -109,12 +118,13 @@ function mcp_front_view($id, $mode, $action) 'AUTHOR_COLOUR' => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour']), 'U_AUTHOR' => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour']), - 'FORUM_NAME' => (!$global_topic) ? $forum_names[$row['forum_id']] : $user->lang['GLOBAL_ANNOUNCEMENT'], + 'FORUM_NAME' => $forum_names[$row['forum_id']], 'POST_ID' => $row['post_id'], 'TOPIC_TITLE' => $row['topic_title'], 'SUBJECT' => ($row['post_subject']) ? $row['post_subject'] : $user->lang['NO_SUBJECT'], - 'POST_TIME' => $user->format_date($row['post_time'])) - ); + 'POST_TIME' => $user->format_date($row['post_time']), + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['post_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', + )); } $db->sql_freeresult($result); } @@ -126,22 +136,9 @@ function mcp_front_view($id, $mode, $action) $template->assign_vars(array( 'S_HIDDEN_FIELDS' => $s_hidden_fields, 'S_MCP_QUEUE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue"), + 'L_UNAPPROVED_TOTAL' => $user->lang('UNAPPROVED_POSTS_TOTAL', (int) $total), + 'S_HAS_UNAPPROVED_POSTS'=> ($total != 0), )); - - if ($total == 0) - { - $template->assign_vars(array( - 'L_UNAPPROVED_TOTAL' => $user->lang['UNAPPROVED_POSTS_ZERO_TOTAL'], - 'S_HAS_UNAPPROVED_POSTS' => false) - ); - } - else - { - $template->assign_vars(array( - 'L_UNAPPROVED_TOTAL' => ($total == 1) ? $user->lang['UNAPPROVED_POST_TOTAL'] : sprintf($user->lang['UNAPPROVED_POSTS_TOTAL'], $total), - 'S_HAS_UNAPPROVED_POSTS' => true) - ); - } } } @@ -159,31 +156,29 @@ function mcp_front_view($id, $mode, $action) WHERE r.post_id = p.post_id AND r.pm_id = 0 AND r.report_closed = 0 - AND p.forum_id IN (0, ' . implode(', ', $forum_list) . ')'; + AND ' . $db->sql_in_set('p.forum_id', $forum_list); $result = $db->sql_query($sql); $total = (int) $db->sql_fetchfield('total'); $db->sql_freeresult($result); if ($total) { - $global_id = $forum_list[0]; - - $sql = $db->sql_build_query('SELECT', array( - 'SELECT' => 'r.report_time, p.post_id, p.post_subject, p.post_time, u.username, u.username_clean, u.user_colour, u.user_id, u2.username as author_name, u2.username_clean as author_name_clean, u2.user_colour as author_colour, u2.user_id as author_id, t.topic_id, t.topic_title, f.forum_id, f.forum_name', + $sql_ary = array( + 'SELECT' => 'r.report_time, p.post_id, p.post_subject, p.post_time, p.post_attachment, u.username, u.username_clean, u.user_colour, u.user_id, u2.username as author_name, u2.username_clean as author_name_clean, u2.user_colour as author_colour, u2.user_id as author_id, t.topic_id, t.topic_title, f.forum_id, f.forum_name', 'FROM' => array( REPORTS_TABLE => 'r', REPORTS_REASONS_TABLE => 'rr', TOPICS_TABLE => 't', USERS_TABLE => array('u', 'u2'), - POSTS_TABLE => 'p' + POSTS_TABLE => 'p', ), 'LEFT_JOIN' => array( array( 'FROM' => array(FORUMS_TABLE => 'f'), - 'ON' => 'f.forum_id = p.forum_id' - ) + 'ON' => 'f.forum_id = p.forum_id', + ), ), 'WHERE' => 'r.post_id = p.post_id @@ -193,25 +188,32 @@ function mcp_front_view($id, $mode, $action) AND p.topic_id = t.topic_id AND r.user_id = u.user_id AND p.poster_id = u2.user_id - AND p.forum_id IN (0, ' . implode(', ', $forum_list) . ')', + AND ' . $db->sql_in_set('p.forum_id', $forum_list), - 'ORDER_BY' => 'p.post_time DESC' - )); + 'ORDER_BY' => 'p.post_time DESC, p.post_id DESC', + ); + + /** + * Alter sql query to get latest reported posts + * + * @event core.mcp_front_reports_listing_query_before + * @var int sql_ary Associative array with the query to be executed + * @var array forum_list List of forums that contain the posts + * @since 3.1.0-RC3 + */ + $vars = array('sql_ary', 'forum_list'); + extract($phpbb_dispatcher->trigger_event('core.mcp_front_reports_listing_query_before', compact($vars))); + + $sql = $db->sql_build_query('SELECT', $sql_ary); $result = $db->sql_query_limit($sql, 5); while ($row = $db->sql_fetchrow($result)) { - $global_topic = ($row['forum_id']) ? false : true; - if ($global_topic) - { - $row['forum_id'] = $global_id; - } - $template->assign_block_vars('report', array( 'U_POST_DETAILS' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'f=' . $row['forum_id'] . '&p=' . $row['post_id'] . "&i=reports&mode=report_details"), - 'U_MCP_FORUM' => (!$global_topic) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'f=' . $row['forum_id'] . "&i=$id&mode=forum_view") : '', + 'U_MCP_FORUM' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'f=' . $row['forum_id'] . "&i=$id&mode=forum_view"), 'U_MCP_TOPIC' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'f=' . $row['forum_id'] . '&t=' . $row['topic_id'] . "&i=$id&mode=topic_view"), - 'U_FORUM' => (!$global_topic) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : '', + 'U_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']), 'U_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id'] . '&t=' . $row['topic_id']), 'REPORTER_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), @@ -224,29 +226,21 @@ function mcp_front_view($id, $mode, $action) 'AUTHOR_COLOUR' => get_username_string('colour', $row['author_id'], $row['author_name'], $row['author_colour']), 'U_AUTHOR' => get_username_string('profile', $row['author_id'], $row['author_name'], $row['author_colour']), - 'FORUM_NAME' => (!$global_topic) ? $row['forum_name'] : $user->lang['GLOBAL_ANNOUNCEMENT'], + 'FORUM_NAME' => $row['forum_name'], 'TOPIC_TITLE' => $row['topic_title'], 'SUBJECT' => ($row['post_subject']) ? $row['post_subject'] : $user->lang['NO_SUBJECT'], 'REPORT_TIME' => $user->format_date($row['report_time']), 'POST_TIME' => $user->format_date($row['post_time']), + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['post_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', )); } + $db->sql_freeresult($result); } - if ($total == 0) - { - $template->assign_vars(array( - 'L_REPORTS_TOTAL' => $user->lang['REPORTS_ZERO_TOTAL'], - 'S_HAS_REPORTS' => false) - ); - } - else - { - $template->assign_vars(array( - 'L_REPORTS_TOTAL' => ($total == 1) ? $user->lang['REPORT_TOTAL'] : sprintf($user->lang['REPORTS_TOTAL'], $total), - 'S_HAS_REPORTS' => true) - ); - } + $template->assign_vars(array( + 'L_REPORTS_TOTAL' => $user->lang('REPORTS_TOTAL', (int) $total), + 'S_HAS_REPORTS' => ($total != 0), + )); } } @@ -269,14 +263,14 @@ function mcp_front_view($id, $mode, $action) { include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); - $sql = $db->sql_build_query('SELECT', array( - 'SELECT' => 'r.report_id, r.report_time, p.msg_id, p.message_subject, p.message_time, p.to_address, p.bcc_address, u.username, u.username_clean, u.user_colour, u.user_id, u2.username as author_name, u2.username_clean as author_name_clean, u2.user_colour as author_colour, u2.user_id as author_id', + $sql_ary = array( + 'SELECT' => 'r.report_id, r.report_time, p.msg_id, p.message_subject, p.message_time, p.to_address, p.bcc_address, p.message_attachment, u.username, u.username_clean, u.user_colour, u.user_id, u2.username as author_name, u2.username_clean as author_name_clean, u2.user_colour as author_colour, u2.user_id as author_id', 'FROM' => array( REPORTS_TABLE => 'r', REPORTS_REASONS_TABLE => 'rr', USERS_TABLE => array('u', 'u2'), - PRIVMSGS_TABLE => 'p' + PRIVMSGS_TABLE => 'p', ), 'WHERE' => 'r.pm_id = p.msg_id @@ -286,8 +280,9 @@ function mcp_front_view($id, $mode, $action) AND r.user_id = u.user_id AND p.author_id = u2.user_id', - 'ORDER_BY' => 'p.message_time DESC' - )); + 'ORDER_BY' => 'p.message_time DESC', + ); + $sql = $db->sql_build_query('SELECT', $sql_ary); $result = $db->sql_query_limit($sql, 5); $pm_by_id = $pm_list = array(); @@ -296,6 +291,7 @@ function mcp_front_view($id, $mode, $action) $pm_by_id[(int) $row['msg_id']] = $row; $pm_list[] = (int) $row['msg_id']; } + $db->sql_freeresult($result); $address_list = get_recipient_strings($pm_by_id); @@ -320,24 +316,15 @@ function mcp_front_view($id, $mode, $action) 'REPORT_TIME' => $user->format_date($row['report_time']), 'PM_TIME' => $user->format_date($row['message_time']), 'RECIPIENTS' => implode(', ', $address_list[$row['msg_id']]), + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $row['message_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', )); } } - if ($total == 0) - { - $template->assign_vars(array( - 'L_PM_REPORTS_TOTAL' => $user->lang['PM_REPORTS_ZERO_TOTAL'], - 'S_HAS_PM_REPORTS' => false) - ); - } - else - { - $template->assign_vars(array( - 'L_PM_REPORTS_TOTAL' => ($total == 1) ? $user->lang['PM_REPORT_TOTAL'] : sprintf($user->lang['PM_REPORTS_TOTAL'], $total), - 'S_HAS_PM_REPORTS' => true) - ); - } + $template->assign_vars(array( + 'L_PM_REPORTS_TOTAL' => $user->lang('PM_REPORTS_TOTAL', (int) $total), + 'S_HAS_PM_REPORTS' => ($total != 0), + )); } // Latest 5 logs @@ -347,9 +334,6 @@ function mcp_front_view($id, $mode, $action) if (!empty($forum_list)) { - // Add forum_id 0 for global announcements - $forum_list[] = 0; - $log_count = false; $log = array(); view_log('mod', $log, $log_count, 5, 0, $forum_list); @@ -376,5 +360,3 @@ function mcp_front_view($id, $mode, $action) $template->assign_var('S_MCP_ACTION', append_sid("{$phpbb_root_path}mcp.$phpEx")); make_jumpbox(append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=forum_view'), 0, false, 'm_', true); } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_logs.php b/phpBB/includes/mcp/mcp_logs.php index 73ff72c177..9c76f0df90 100644 --- a/phpBB/includes/mcp/mcp_logs.php +++ b/phpBB/includes/mcp/mcp_logs.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * mcp_logs * Handling warning the users -* @package mcp */ class mcp_logs { @@ -34,7 +36,7 @@ class mcp_logs function main($id, $mode) { global $auth, $db, $user, $template; - global $config, $phpbb_root_path, $phpEx; + global $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_log; $user->add_lang('acp/common'); @@ -63,6 +65,8 @@ class mcp_logs $this->tpl_name = 'mcp_logs'; $this->page_title = 'MCP_LOGS'; + $pagination = $phpbb_container->get('pagination'); + $forum_list = array_values(array_intersect(get_forum_list('f_read'), get_forum_list('m_'))); $forum_list[] = 0; @@ -110,27 +114,33 @@ class mcp_logs { if ($deletemark && sizeof($marked)) { - $sql = 'DELETE FROM ' . LOG_TABLE . ' - WHERE log_type = ' . LOG_MOD . ' - AND ' . $db->sql_in_set('forum_id', $forum_list) . ' - AND ' . $db->sql_in_set('log_id', $marked); - $db->sql_query($sql); + $conditions = array( + 'forum_id' => array('IN' => $forum_list), + 'log_id' => array('IN' => $marked), + ); - add_log('admin', 'LOG_CLEAR_MOD'); + $phpbb_log->delete('mod', $conditions); } else if ($deleteall) { - $sql = 'DELETE FROM ' . LOG_TABLE . ' - WHERE log_type = ' . LOG_MOD . ' - AND ' . $db->sql_in_set('forum_id', $forum_list); + $keywords = utf8_normalize_nfc(request_var('keywords', '', true)); + + $conditions = array( + 'forum_id' => array('IN' => $forum_list), + 'keywords' => $keywords, + ); + + if ($sort_days) + { + $conditions['log_time'] = array('>=', time() - ($sort_days * 86400)); + } if ($mode == 'topic_logs') { - $sql .= ' AND topic_id = ' . $topic_id; + $conditions['topic_id'] = $topic_id; } - $db->sql_query($sql); - add_log('admin', 'LOG_CLEAR_MOD'); + $phpbb_log->delete('mod', $conditions); } } else @@ -172,10 +182,11 @@ class mcp_logs $log_count = 0; $start = view_log('mod', $log_data, $log_count, $config['topics_per_page'], $start, $forum_list, $topic_id, 0, $sql_where, $sql_sort, $keywords); + $base_url = $this->u_action . "&$u_sort_param$keywords_param"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); + $template->assign_vars(array( - 'PAGE_NUMBER' => on_page($log_count, $config['topics_per_page'], $start), - 'TOTAL' => ($log_count == 1) ? $user->lang['TOTAL_LOG'] : sprintf($user->lang['TOTAL_LOGS'], $log_count), - 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param$keywords_param", $log_count, $config['topics_per_page'], $start), + 'TOTAL' => $user->lang('TOTAL_LOGS', (int) $log_count), 'L_TITLE' => $user->lang['MCP_LOGS'], @@ -214,5 +225,3 @@ class mcp_logs } } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index 0cef8933fc..10f1a5b8c1 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * mcp_main * Handling mcp actions -* @package mcp */ class mcp_main { @@ -34,7 +36,8 @@ class mcp_main function main($id, $mode) { global $auth, $db, $user, $template, $action; - global $config, $phpbb_root_path, $phpEx; + global $config, $phpbb_root_path, $phpEx, $request; + global $phpbb_dispatcher; $quickmod = ($mode == 'quickmod') ? true : false; @@ -109,27 +112,62 @@ class mcp_main case 'delete_topic': $user->add_lang('viewtopic'); - $topic_ids = (!$quickmod) ? request_var('topic_id_list', array(0)) : array(request_var('t', 0)); + // f parameter is not reliable for permission usage, however we just use it to decide + // which permission we will check later on. So if it is manipulated, we will still catch it later on. + $forum_id = $request->variable('f', 0); + $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); + $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false; if (!sizeof($topic_ids)) { trigger_error('NO_TOPIC_SELECTED'); } - mcp_delete_topic($topic_ids); + mcp_delete_topic($topic_ids, $soft_delete, $request->variable('delete_reason', '', true)); break; case 'delete_post': $user->add_lang('posting'); - $post_ids = (!$quickmod) ? request_var('post_id_list', array(0)) : array(request_var('p', 0)); + // f parameter is not reliable for permission usage, however we just use it to decide + // which permission we will check later on. So if it is manipulated, we will still catch it later on. + $forum_id = $request->variable('f', 0); + $post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0)); + $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false; if (!sizeof($post_ids)) { trigger_error('NO_POST_SELECTED'); } - mcp_delete_post($post_ids); + mcp_delete_post($post_ids, $soft_delete, $request->variable('delete_reason', '', true)); + break; + + case 'restore_topic': + $user->add_lang('posting'); + + $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0)); + + if (!sizeof($topic_ids)) + { + trigger_error('NO_TOPIC_SELECTED'); + } + + mcp_restore_topic($topic_ids); + break; + + default: + /** + * This event allows you to handle custom quickmod options + * + * @event core.modify_quickmod_actions + * @var string action Topic quick moderation action name + * @var bool quickmod Flag indicating whether MCP is in quick moderation mode + * @since 3.1.0-a4 + * @change 3.1.0-RC4 Added variables: action, quickmod + */ + $vars = array('action', 'quickmod'); + extract($phpbb_dispatcher->trigger_event('core.modify_quickmod_actions', compact($vars))); break; } @@ -153,7 +191,7 @@ class mcp_main $forum_id = request_var('f', 0); - $forum_info = get_forum_data($forum_id, 'm_', true); + $forum_info = phpbb_get_forum_data($forum_id, 'm_', true); if (!sizeof($forum_info)) { @@ -188,6 +226,31 @@ class mcp_main break; default: + if ($quickmod) + { + switch ($action) + { + case 'lock': + case 'unlock': + case 'make_announce': + case 'make_sticky': + case 'make_global': + case 'make_normal': + case 'make_onindex': + case 'move': + case 'fork': + case 'delete_topic': + trigger_error('TOPIC_NOT_EXIST'); + break; + + case 'lock_post': + case 'unlock_post': + case 'delete_post': + trigger_error('POST_NOT_EXIST'); + break; + } + } + trigger_error('NO_MODE', E_USER_ERROR); break; } @@ -199,7 +262,7 @@ class mcp_main */ function lock_unlock($action, $ids) { - global $auth, $user, $db, $phpEx, $phpbb_root_path; + global $auth, $user, $db, $phpEx, $phpbb_root_path, $request; if ($action == 'lock' || $action == 'unlock') { @@ -218,7 +281,7 @@ function lock_unlock($action, $ids) $orig_ids = $ids; - if (!check_ids($ids, $table, $sql_id, array('m_lock'))) + if (!phpbb_check_ids($ids, $table, $sql_id, array('m_lock'))) { // Make sure that for f_user_lock only the lock action is triggered. if ($action != 'lock') @@ -228,7 +291,7 @@ function lock_unlock($action, $ids) $ids = $orig_ids; - if (!check_ids($ids, $table, $sql_id, array('f_user_lock'))) + if (!phpbb_check_ids($ids, $table, $sql_id, array('f_user_lock'))) { return; } @@ -236,6 +299,7 @@ function lock_unlock($action, $ids) unset($orig_ids); $redirect = request_var('redirect', build_url(array('action', 'quickmod'))); + $redirect = reapply_sid($redirect); $s_hidden_fields = build_hidden_fields(array( $sql_id . '_list' => $ids, @@ -251,7 +315,7 @@ function lock_unlock($action, $ids) WHERE ' . $db->sql_in_set($sql_id, $ids); $db->sql_query($sql); - $data = ($action == 'lock' || $action == 'unlock') ? get_topic_data($ids) : get_post_data($ids); + $data = ($action == 'lock' || $action == 'unlock') ? phpbb_get_topic_data($ids) : phpbb_get_post_data($ids); foreach ($data as $id => $row) { @@ -259,24 +323,22 @@ function lock_unlock($action, $ids) } $success_msg = $l_prefix . ((sizeof($ids) == 1) ? '' : 'S') . '_' . (($action == 'lock' || $action == 'lock_post') ? 'LOCKED' : 'UNLOCKED') . '_SUCCESS'; - } - else - { - confirm_box(false, strtoupper($action) . '_' . $l_prefix . ((sizeof($ids) == 1) ? '' : 'S'), $s_hidden_fields); - } - $redirect = request_var('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); + meta_refresh(2, $redirect); + $message = $user->lang[$success_msg]; - if (!$success_msg) - { - redirect($redirect); + if (!$request->is_ajax()) + { + $message .= '<br /><br />' . $user->lang('RETURN_PAGE', '<a href="' . $redirect . '">', '</a>'); + } + trigger_error($message); } else { - meta_refresh(2, $redirect); - trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>')); + confirm_box(false, strtoupper($action) . '_' . $l_prefix . ((sizeof($ids) == 1) ? '' : 'S'), $s_hidden_fields); } + + redirect($redirect); } /** @@ -284,7 +346,7 @@ function lock_unlock($action, $ids) */ function change_topic_type($action, $topic_ids) { - global $auth, $user, $db, $phpEx, $phpbb_root_path; + global $auth, $user, $db, $phpEx, $phpbb_root_path, $request; switch ($action) { @@ -313,7 +375,7 @@ function change_topic_type($action, $topic_ids) break; } - $forum_id = check_ids($topic_ids, TOPICS_TABLE, 'topic_id', $check_acl, true); + $forum_id = phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', $check_acl, true); if ($forum_id === false) { @@ -321,6 +383,7 @@ function change_topic_type($action, $topic_ids) } $redirect = request_var('redirect', build_url(array('action', 'quickmod'))); + $redirect = reapply_sid($redirect); $s_hidden_fields = array( 'topic_id_list' => $topic_ids, @@ -332,196 +395,51 @@ function change_topic_type($action, $topic_ids) if (confirm_box(true)) { - if ($new_topic_type != POST_GLOBAL) + $sql = 'UPDATE ' . TOPICS_TABLE . " + SET topic_type = $new_topic_type + WHERE " . $db->sql_in_set('topic_id', $topic_ids); + $db->sql_query($sql); + + if (($new_topic_type == POST_GLOBAL) && sizeof($topic_ids)) { + // Delete topic shadows for global announcements + $sql = 'DELETE FROM ' . TOPICS_TABLE . ' + WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids); + $db->sql_query($sql); + $sql = 'UPDATE ' . TOPICS_TABLE . " SET topic_type = $new_topic_type - WHERE " . $db->sql_in_set('topic_id', $topic_ids) . ' - AND forum_id <> 0'; + WHERE " . $db->sql_in_set('topic_id', $topic_ids); $db->sql_query($sql); - - // Reset forum id if a global topic is within the array - $to_forum_id = request_var('to_forum_id', 0); - - if ($to_forum_id) - { - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_type = $new_topic_type, forum_id = $to_forum_id - WHERE " . $db->sql_in_set('topic_id', $topic_ids) . ' - AND forum_id = 0'; - $db->sql_query($sql); - - // Update forum_ids for all posts - $sql = 'UPDATE ' . POSTS_TABLE . " - SET forum_id = $to_forum_id - WHERE " . $db->sql_in_set('topic_id', $topic_ids) . ' - AND forum_id = 0'; - $db->sql_query($sql); - - // Do a little forum sync stuff - $sql = 'SELECT SUM(t.topic_replies + t.topic_approved) as topic_posts, COUNT(t.topic_approved) as topics_authed - FROM ' . TOPICS_TABLE . ' t - WHERE ' . $db->sql_in_set('t.topic_id', $topic_ids); - $result = $db->sql_query($sql); - $row_data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $sync_sql = array(); - - if ($row_data['topic_posts']) - { - $sync_sql[$to_forum_id][] = 'forum_posts = forum_posts + ' . (int) $row_data['topic_posts']; - } - - if ($row_data['topics_authed']) - { - $sync_sql[$to_forum_id][] = 'forum_topics = forum_topics + ' . (int) $row_data['topics_authed']; - } - - $sync_sql[$to_forum_id][] = 'forum_topics_real = forum_topics_real + ' . (int) sizeof($topic_ids); - - foreach ($sync_sql as $forum_id_key => $array) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . implode(', ', $array) . ' - WHERE forum_id = ' . $forum_id_key; - $db->sql_query($sql); - } - - sync('forum', 'forum_id', $to_forum_id); - } - } - else - { - // Get away with those topics already being a global announcement by re-calculating $topic_ids - $sql = 'SELECT topic_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - AND forum_id <> 0'; - $result = $db->sql_query($sql); - - $topic_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_ids[] = $row['topic_id']; - } - $db->sql_freeresult($result); - - if (sizeof($topic_ids)) - { - // Delete topic shadows for global announcements - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids); - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_type = $new_topic_type, forum_id = 0 - WHERE " . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - - // Update forum_ids for all posts - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET forum_id = 0 - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - - // Do a little forum sync stuff - $sql = 'SELECT SUM(t.topic_replies + t.topic_approved) as topic_posts, COUNT(t.topic_approved) as topics_authed - FROM ' . TOPICS_TABLE . ' t - WHERE ' . $db->sql_in_set('t.topic_id', $topic_ids); - $result = $db->sql_query($sql); - $row_data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $sync_sql = array(); - - if ($row_data['topic_posts']) - { - $sync_sql[$forum_id][] = 'forum_posts = forum_posts - ' . (int) $row_data['topic_posts']; - } - - if ($row_data['topics_authed']) - { - $sync_sql[$forum_id][] = 'forum_topics = forum_topics - ' . (int) $row_data['topics_authed']; - } - - $sync_sql[$forum_id][] = 'forum_topics_real = forum_topics_real - ' . (int) sizeof($topic_ids); - - foreach ($sync_sql as $forum_id_key => $array) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . implode(', ', $array) . ' - WHERE forum_id = ' . $forum_id_key; - $db->sql_query($sql); - } - - sync('forum', 'forum_id', $forum_id); - } } $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_TYPE_CHANGED' : 'TOPICS_TYPE_CHANGED'; if (sizeof($topic_ids)) { - $data = get_topic_data($topic_ids); + $data = phpbb_get_topic_data($topic_ids); foreach ($data as $topic_id => $row) { add_log('mod', $forum_id, $topic_id, 'LOG_TOPIC_TYPE_CHANGED', $row['topic_title']); } } - } - else - { - // Global topic involved? - $global_involved = false; - - if ($new_topic_type != POST_GLOBAL) - { - $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' - AND forum_id = 0'; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $global_involved = true; - } - } - if ($global_involved) - { - global $template; - - $template->assign_vars(array( - 'S_FORUM_SELECT' => make_forum_select(request_var('f', $forum_id), false, false, true, true), - 'S_CAN_LEAVE_SHADOW' => false, - 'ADDITIONAL_MSG' => (sizeof($topic_ids) == 1) ? $user->lang['SELECT_FORUM_GLOBAL_ANNOUNCEMENT'] : $user->lang['SELECT_FORUM_GLOBAL_ANNOUNCEMENTS']) - ); + meta_refresh(2, $redirect); + $message = $user->lang[$success_msg]; - confirm_box(false, $l_new_type, build_hidden_fields($s_hidden_fields), 'mcp_move.html'); - } - else + if (!$request->is_ajax()) { - confirm_box(false, $l_new_type, build_hidden_fields($s_hidden_fields)); + $message .= '<br /><br />' . $user->lang('RETURN_PAGE', '<a href="' . $redirect . '">', '</a>'); } - } - - $redirect = request_var('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); - - if (!$success_msg) - { - redirect($redirect); + trigger_error($message); } else { - meta_refresh(2, $redirect); - trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>')); + confirm_box(false, $l_new_type, build_hidden_fields($s_hidden_fields)); } + + redirect($redirect); } /** @@ -529,11 +447,11 @@ function change_topic_type($action, $topic_ids) */ function mcp_move_topic($topic_ids) { - global $auth, $user, $db, $template; + global $auth, $user, $db, $template, $phpbb_log, $request; global $phpEx, $phpbb_root_path; // Here we limit the operation to one forum only - $forum_id = check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_move'), true); + $forum_id = phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_move'), true); if ($forum_id === false) { @@ -553,7 +471,7 @@ function mcp_move_topic($topic_ids) if ($to_forum_id) { - $forum_data = get_forum_data($to_forum_id, 'f_post'); + $forum_data = phpbb_get_forum_data($to_forum_id, 'f_post'); if (!sizeof($forum_data)) { @@ -584,13 +502,13 @@ function mcp_move_topic($topic_ids) if (!$to_forum_id || $additional_msg) { - unset($_POST['confirm']); - unset($_REQUEST['confirm_key']); + $request->overwrite('confirm', null, \phpbb\request\request_interface::POST); + $request->overwrite('confirm_key', null); } if (confirm_box(true)) { - $topic_data = get_topic_data($topic_ids); + $topic_data = phpbb_get_topic_data($topic_ids); $leave_shadow = (isset($_POST['move_leave_shadow'])) ? true : false; $forum_sync_data = array(); @@ -598,98 +516,77 @@ function mcp_move_topic($topic_ids) $forum_sync_data[$forum_id] = current($topic_data); $forum_sync_data[$to_forum_id] = $forum_data; - // Real topics added to target forum - $topics_moved = sizeof($topic_data); - - // Approved topics added to target forum - $topics_authed_moved = 0; - - // Posts (topic replies + topic post if approved) added to target forum - $topic_posts_added = 0; - - // Posts (topic replies + topic post if approved and not global announcement) removed from source forum - $topic_posts_removed = 0; - - // Real topics removed from source forum (all topics without global announcements) - $topics_removed = 0; - - // Approved topics removed from source forum (except global announcements) - $topics_authed_removed = 0; + $topics_moved = $topics_moved_unapproved = $topics_moved_softdeleted = 0; + $posts_moved = $posts_moved_unapproved = $posts_moved_softdeleted = 0; foreach ($topic_data as $topic_id => $topic_info) { - if ($topic_info['topic_approved']) + if ($topic_info['topic_visibility'] == ITEM_APPROVED) { - $topics_authed_moved++; - $topic_posts_added++; + $topics_moved++; } - - $topic_posts_added += $topic_info['topic_replies']; - - if ($topic_info['topic_type'] != POST_GLOBAL) + else if ($topic_info['topic_visibility'] == ITEM_UNAPPROVED || $topic_info['topic_visibility'] == ITEM_REAPPROVE) { - $topics_removed++; - $topic_posts_removed += $topic_info['topic_replies']; - - if ($topic_info['topic_approved']) - { - $topics_authed_removed++; - $topic_posts_removed++; - } + $topics_moved_unapproved++; + } + else if ($topic_info['topic_visibility'] == ITEM_DELETED) + { + $topics_moved_softdeleted++; } + + $posts_moved += $topic_info['topic_posts_approved']; + $posts_moved_unapproved += $topic_info['topic_posts_unapproved']; + $posts_moved_softdeleted += $topic_info['topic_posts_softdeleted']; } $db->sql_transaction('begin'); - $sync_sql = array(); - - if ($topic_posts_added) - { - $sync_sql[$to_forum_id][] = 'forum_posts = forum_posts + ' . $topic_posts_added; - } + // Move topics, but do not resync yet + move_topics($topic_ids, $to_forum_id, false); - if ($topics_authed_moved) + if ($request->is_set_post('move_lock_topics') && $auth->acl_get('m_lock', $to_forum_id)) { - $sync_sql[$to_forum_id][] = 'forum_topics = forum_topics + ' . (int) $topics_authed_moved; + $sql = 'UPDATE ' . TOPICS_TABLE . ' + SET topic_status = ' . ITEM_LOCKED . ' + WHERE ' . $db->sql_in_set('topic_id', $topic_ids); + $db->sql_query($sql); } - $sync_sql[$to_forum_id][] = 'forum_topics_real = forum_topics_real + ' . (int) $topics_moved; - - // Move topics, but do not resync yet - move_topics($topic_ids, $to_forum_id, false); - + $shadow_topics = 0; $forum_ids = array($to_forum_id); foreach ($topic_data as $topic_id => $row) { - // Get the list of forums to resync, add a log entry + // Get the list of forums to resync $forum_ids[] = $row['forum_id']; - add_log('mod', $to_forum_id, $topic_id, 'LOG_MOVE', $row['forum_name'], $forum_data['forum_name']); - // If we have moved a global announcement, we need to correct the topic type - if ($row['topic_type'] == POST_GLOBAL) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_type = ' . POST_ANNOUNCE . ' - WHERE topic_id = ' . (int) $row['topic_id']; - $db->sql_query($sql); - } + // We add the $to_forum_id twice, because 'forum_id' is updated + // when the topic is moved again later. + $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_MOVE', false, array( + 'forum_id' => (int) $to_forum_id, + 'topic_id' => (int) $topic_id, + $row['forum_name'], + $forum_data['forum_name'], + (int) $row['forum_id'], + (int) $forum_data['forum_id'], + )); // Leave a redirection if required and only if the topic is visible to users - if ($leave_shadow && $row['topic_approved'] && $row['topic_type'] != POST_GLOBAL) + if ($leave_shadow && $row['topic_visibility'] == ITEM_APPROVED && $row['topic_type'] != POST_GLOBAL) { $shadow = array( 'forum_id' => (int) $row['forum_id'], 'icon_id' => (int) $row['icon_id'], 'topic_attachment' => (int) $row['topic_attachment'], - 'topic_approved' => 1, // a shadow topic is always approved + 'topic_visibility' => ITEM_APPROVED, // a shadow topic is always approved 'topic_reported' => 0, // a shadow topic is never reported 'topic_title' => (string) $row['topic_title'], 'topic_poster' => (int) $row['topic_poster'], 'topic_time' => (int) $row['topic_time'], 'topic_time_limit' => (int) $row['topic_time_limit'], 'topic_views' => (int) $row['topic_views'], - 'topic_replies' => (int) $row['topic_replies'], - 'topic_replies_real' => (int) $row['topic_replies_real'], + 'topic_posts_approved' => (int) $row['topic_posts_approved'], + 'topic_posts_unapproved'=> (int) $row['topic_posts_unapproved'], + 'topic_posts_softdeleted'=> (int) $row['topic_posts_softdeleted'], 'topic_status' => ITEM_MOVED, 'topic_type' => POST_NORMAL, 'topic_first_post_id' => (int) $row['topic_first_post_id'], @@ -699,7 +596,7 @@ function mcp_move_topic($topic_ids) 'topic_last_poster_id' => (int) $row['topic_last_poster_id'], 'topic_last_poster_colour'=>(string) $row['topic_last_poster_colour'], 'topic_last_poster_name'=> (string) $row['topic_last_poster_name'], - 'topic_last_post_subject'=> (string) $row['topic_last_post_subject'], + 'topic_last_post_subject'=> (string) $row['topic_last_post_subject'], 'topic_last_post_time' => (int) $row['topic_last_post_time'], 'topic_last_view_time' => (int) $row['topic_last_view_time'], 'topic_moved_id' => (int) $row['topic_id'], @@ -715,25 +612,45 @@ function mcp_move_topic($topic_ids) $db->sql_query('INSERT INTO ' . TOPICS_TABLE . $db->sql_build_array('INSERT', $shadow)); // Shadow topics only count on new "topics" and not posts... a shadow topic alone has 0 posts - $topics_removed--; - $topics_authed_removed--; + $shadow_topics++; } } unset($topic_data); - if ($topic_posts_removed) + $sync_sql = array(); + if ($posts_moved) { - $sync_sql[$forum_id][] = 'forum_posts = forum_posts - ' . $topic_posts_removed; + $sync_sql[$to_forum_id][] = 'forum_posts_approved = forum_posts_approved + ' . (int) $posts_moved; + $sync_sql[$forum_id][] = 'forum_posts_approved = forum_posts_approved - ' . (int) $posts_moved; } - - if ($topics_removed) + if ($posts_moved_unapproved) + { + $sync_sql[$to_forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved + ' . (int) $posts_moved_unapproved; + $sync_sql[$forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved - ' . (int) $posts_moved_unapproved; + } + if ($posts_moved_softdeleted) { - $sync_sql[$forum_id][] = 'forum_topics_real = forum_topics_real - ' . (int) $topics_removed; + $sync_sql[$to_forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted + ' . (int) $posts_moved_softdeleted; + $sync_sql[$forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted - ' . (int) $posts_moved_softdeleted; } - if ($topics_authed_removed) + if ($topics_moved) { - $sync_sql[$forum_id][] = 'forum_topics = forum_topics - ' . (int) $topics_authed_removed; + $sync_sql[$to_forum_id][] = 'forum_topics_approved = forum_topics_approved + ' . (int) $topics_moved; + if ($topics_moved - $shadow_topics > 0) + { + $sync_sql[$forum_id][] = 'forum_topics_approved = forum_topics_approved - ' . (int) ($topics_moved - $shadow_topics); + } + } + if ($topics_moved_unapproved) + { + $sync_sql[$to_forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved + ' . (int) $topics_moved_unapproved; + $sync_sql[$forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved - ' . (int) $topics_moved_unapproved; + } + if ($topics_moved_softdeleted) + { + $sync_sql[$to_forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted + ' . (int) $topics_moved_softdeleted; + $sync_sql[$forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted - ' . (int) $topics_moved_softdeleted; } $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_MOVED_SUCCESS' : 'TOPICS_MOVED_SUCCESS'; @@ -755,6 +672,7 @@ function mcp_move_topic($topic_ids) $template->assign_vars(array( 'S_FORUM_SELECT' => make_forum_select($to_forum_id, $forum_id, false, true, true, true), 'S_CAN_LEAVE_SHADOW' => true, + 'S_CAN_LOCK_TOPIC' => ($auth->acl_get('m_lock', $to_forum_id)) ? true : false, 'ADDITIONAL_MSG' => $additional_msg) ); @@ -782,25 +700,99 @@ function mcp_move_topic($topic_ids) } /** -* Delete Topics +* Restore Topics */ -function mcp_delete_topic($topic_ids) +function mcp_restore_topic($topic_ids) { - global $auth, $user, $db, $phpEx, $phpbb_root_path; + global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container; - if (!check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_delete'))) + if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_approve'))) { return; } - $redirect = request_var('redirect', build_url(array('action', 'quickmod'))); - $forum_id = request_var('f', 0); + $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); + $forum_id = $request->variable('f', 0); $s_hidden_fields = build_hidden_fields(array( 'topic_id_list' => $topic_ids, 'f' => $forum_id, - 'action' => 'delete_topic', - 'redirect' => $redirect) + 'action' => 'restore_topic', + 'redirect' => $redirect, + )); + $success_msg = ''; + + if (confirm_box(true)) + { + $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_RESTORED_SUCCESS' : 'TOPICS_RESTORED_SUCCESS'; + + $data = phpbb_get_topic_data($topic_ids); + + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + foreach ($data as $topic_id => $row) + { + $return = $phpbb_content_visibility->set_topic_visibility(ITEM_APPROVED, $topic_id, $row['forum_id'], $user->data['user_id'], time(), ''); + if (!empty($return)) + { + add_log('mod', $row['forum_id'], $topic_id, 'LOG_RESTORE_TOPIC', $row['topic_title'], $row['topic_first_poster_name']); + } + } + } + else + { + confirm_box(false, (sizeof($topic_ids) == 1) ? 'RESTORE_TOPIC' : 'RESTORE_TOPICS', $s_hidden_fields); + } + + $topic_id = $request->variable('t', 0); + if (!$request->is_set('quickmod', \phpbb\request\request_interface::REQUEST)) + { + $redirect = $request->variable('redirect', "index.$phpEx"); + $redirect = reapply_sid($redirect); + $redirect_message = 'PAGE'; + } + else if ($topic_id) + { + $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id); + $redirect_message = 'TOPIC'; + } + else + { + $redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); + $redirect_message = 'FORUM'; + } + + if (!$success_msg) + { + redirect($redirect); + } + else + { + meta_refresh(3, $redirect); + trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_' . $redirect_message], '<a href="' . $redirect . '">', '</a>')); + } +} + +/** +* Delete Topics +*/ +function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = '', $action = 'delete_topic') +{ + global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container; + + $check_permission = ($is_soft) ? 'm_softdelete' : 'm_delete'; + if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array($check_permission))) + { + return; + } + + $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); + $forum_id = $request->variable('f', 0); + + $s_hidden_fields = array( + 'topic_id_list' => $topic_ids, + 'f' => $forum_id, + 'action' => $action, + 'redirect' => $redirect, ); $success_msg = ''; @@ -808,7 +800,7 @@ function mcp_delete_topic($topic_ids) { $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_DELETED_SUCCESS' : 'TOPICS_DELETED_SUCCESS'; - $data = get_topic_data($topic_ids); + $data = phpbb_get_topic_data($topic_ids); foreach ($data as $topic_id => $row) { @@ -818,23 +810,90 @@ function mcp_delete_topic($topic_ids) } else { - add_log('mod', $row['forum_id'], $topic_id, 'LOG_DELETE_TOPIC', $row['topic_title'], $row['topic_first_poster_name']); + // Only soft delete non-shadow topics + if ($is_soft) + { + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + $return = $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $row['forum_id'], $user->data['user_id'], time(), $soft_delete_reason); + if (!empty($return)) + { + add_log('mod', $row['forum_id'], $topic_id, 'LOG_SOFTDELETE_TOPIC', $row['topic_title'], $row['topic_first_poster_name'], $soft_delete_reason); + } + } + else + { + add_log('mod', $row['forum_id'], $topic_id, 'LOG_DELETE_TOPIC', $row['topic_title'], $row['topic_first_poster_name'], $soft_delete_reason); + } } } - $return = delete_topics('topic_id', $topic_ids); + if (!$is_soft) + { + $return = delete_topics('topic_id', $topic_ids); + } } else { - confirm_box(false, (sizeof($topic_ids) == 1) ? 'DELETE_TOPIC' : 'DELETE_TOPICS', $s_hidden_fields); + global $template; + + $user->add_lang('posting'); + + // If there are only shadow topics, we neither need a reason nor softdelete + $sql = 'SELECT topic_id + FROM ' . TOPICS_TABLE . ' + WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' + AND topic_moved_id = 0'; + $result = $db->sql_query_limit($sql, 1); + $only_shadow = !$db->sql_fetchfield('topic_id'); + $db->sql_freeresult($result); + + $only_softdeleted = false; + if (!$only_shadow && $auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id)) + { + // If there are only soft deleted topics, we display a message why the option is not available + $sql = 'SELECT topic_id + FROM ' . TOPICS_TABLE . ' + WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . ' + AND topic_visibility <> ' . ITEM_DELETED; + $result = $db->sql_query_limit($sql, 1); + $only_softdeleted = !$db->sql_fetchfield('topic_id'); + $db->sql_freeresult($result); + } + + $template->assign_vars(array( + 'S_SHADOW_TOPICS' => $only_shadow, + 'S_SOFTDELETED' => $only_softdeleted, + 'S_TOPIC_MODE' => true, + 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id), + 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id), + )); + + $l_confirm = (sizeof($topic_ids) == 1) ? 'DELETE_TOPIC' : 'DELETE_TOPICS'; + if ($only_softdeleted) + { + $l_confirm .= '_PERMANENTLY'; + $s_hidden_fields['delete_permanent'] = '1'; + } + else if ($only_shadow || !$auth->acl_get('m_softdelete', $forum_id)) + { + $s_hidden_fields['delete_permanent'] = '1'; + } + + confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html'); } - if (!isset($_REQUEST['quickmod'])) + $topic_id = $request->variable('t', 0); + if (!$request->is_set('quickmod', \phpbb\request\request_interface::REQUEST)) { - $redirect = request_var('redirect', "index.$phpEx"); + $redirect = $request->variable('redirect', "index.$phpEx"); $redirect = reapply_sid($redirect); $redirect_message = 'PAGE'; } + else if ($is_soft && $topic_id) + { + $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id); + $redirect_message = 'TOPIC'; + } else { $redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); @@ -855,27 +914,94 @@ function mcp_delete_topic($topic_ids) /** * Delete Posts */ -function mcp_delete_post($post_ids) +function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '', $action = 'delete_post') { - global $auth, $user, $db, $phpEx, $phpbb_root_path; + global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container; - if (!check_ids($post_ids, POSTS_TABLE, 'post_id', array('m_delete'))) + $check_permission = ($is_soft) ? 'm_softdelete' : 'm_delete'; + if (!phpbb_check_ids($post_ids, POSTS_TABLE, 'post_id', array($check_permission))) { return; } - $redirect = request_var('redirect', build_url(array('action', 'quickmod'))); - $forum_id = request_var('f', 0); + $redirect = $request->variable('redirect', build_url(array('action', 'quickmod'))); + $forum_id = $request->variable('f', 0); - $s_hidden_fields = build_hidden_fields(array( + $s_hidden_fields = array( 'post_id_list' => $post_ids, 'f' => $forum_id, - 'action' => 'delete_post', - 'redirect' => $redirect) + 'action' => $action, + 'redirect' => $redirect, ); $success_msg = ''; - if (confirm_box(true)) + if (confirm_box(true) && $is_soft) + { + $post_info = phpbb_get_post_data($post_ids); + + $topic_info = $approve_log = array(); + + // Group the posts by topic_id + foreach ($post_info as $post_id => $post_data) + { + if ($post_data['post_visibility'] != ITEM_APPROVED) + { + continue; + } + $topic_id = (int) $post_data['topic_id']; + + $topic_info[$topic_id]['posts'][] = (int) $post_id; + $topic_info[$topic_id]['forum_id'] = (int) $post_data['forum_id']; + + if ($post_id == $post_data['topic_first_post_id']) + { + $topic_info[$topic_id]['first_post'] = true; + } + + if ($post_id == $post_data['topic_last_post_id']) + { + $topic_info[$topic_id]['last_post'] = true; + } + + $approve_log[] = array( + 'forum_id' => $post_data['forum_id'], + 'topic_id' => $post_data['topic_id'], + 'post_subject' => $post_data['post_subject'], + 'poster_id' => $post_data['poster_id'], + 'post_username' => $post_data['post_username'], + 'username' => $post_data['username'], + ); + } + + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + foreach ($topic_info as $topic_id => $topic_data) + { + $phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $topic_data['posts'], $topic_id, $topic_data['forum_id'], $user->data['user_id'], time(), $soft_delete_reason, isset($topic_data['first_post']), isset($topic_data['last_post'])); + } + $affected_topics = sizeof($topic_info); + // None of the topics is really deleted, so a redirect won't hurt much. + $deleted_topics = 0; + + $success_msg = (sizeof($post_info) == 1) ? $user->lang['POST_DELETED_SUCCESS'] : $user->lang['POSTS_DELETED_SUCCESS']; + + foreach ($approve_log as $row) + { + $post_username = ($row['poster_id'] == ANONYMOUS && !empty($row['post_username'])) ? $row['post_username'] : $row['username']; + add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_SOFTDELETE_POST', $row['post_subject'], $post_username, $soft_delete_reason); + } + + $topic_id = $request->variable('t', 0); + + // Return links + $return_link = array(); + if ($affected_topics == 1 && $topic_id) + { + $return_link[] = sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id") . '">', '</a>'); + } + $return_link[] = sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) . '">', '</a>'); + + } + else if (confirm_box(true)) { if (!function_exists('delete_posts')) { @@ -899,12 +1025,12 @@ function mcp_delete_post($post_ids) $affected_topics = sizeof($topic_id_list); $db->sql_freeresult($result); - $post_data = get_post_data($post_ids); + $post_data = phpbb_get_post_data($post_ids); foreach ($post_data as $id => $row) { $post_username = ($row['poster_id'] == ANONYMOUS && !empty($row['post_username'])) ? $row['post_username'] : $row['username']; - add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_DELETE_POST', $row['post_subject'], $post_username); + add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_DELETE_POST', $row['post_subject'], $post_username, $soft_delete_reason); } // Now delete the posts, topics and forums are automatically resync'ed @@ -918,7 +1044,7 @@ function mcp_delete_post($post_ids) $deleted_topics = ($row = $db->sql_fetchrow($result)) ? ($affected_topics - $row['topics_left']) : $affected_topics; $db->sql_freeresult($result); - $topic_id = request_var('t', 0); + $topic_id = $request->variable('t', 0); // Return links $return_link = array(); @@ -956,10 +1082,44 @@ function mcp_delete_post($post_ids) } else { - confirm_box(false, (sizeof($post_ids) == 1) ? 'DELETE_POST' : 'DELETE_POSTS', $s_hidden_fields); + global $template; + + $user->add_lang('posting'); + + $only_softdeleted = false; + if ($auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id)) + { + // If there are only soft deleted posts, we display a message why the option is not available + $sql = 'SELECT post_id + FROM ' . POSTS_TABLE . ' + WHERE ' . $db->sql_in_set('post_id', $post_ids) . ' + AND post_visibility <> ' . ITEM_DELETED; + $result = $db->sql_query_limit($sql, 1); + $only_softdeleted = !$db->sql_fetchfield('post_id'); + $db->sql_freeresult($result); + } + + $template->assign_vars(array( + 'S_SOFTDELETED' => $only_softdeleted, + 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id), + 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id), + )); + + $l_confirm = (sizeof($post_ids) == 1) ? 'DELETE_POST' : 'DELETE_POSTS'; + if ($only_softdeleted) + { + $l_confirm .= '_PERMANENTLY'; + $s_hidden_fields['delete_permanent'] = '1'; + } + else if (!$auth->acl_get('m_softdelete', $forum_id)) + { + $s_hidden_fields['delete_permanent'] = '1'; + } + + confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html'); } - $redirect = request_var('redirect', "index.$phpEx"); + $redirect = $request->variable('redirect', "index.$phpEx"); $redirect = reapply_sid($redirect); if (!$success_msg) @@ -986,7 +1146,7 @@ function mcp_fork_topic($topic_ids) global $auth, $user, $db, $template, $config; global $phpEx, $phpbb_root_path; - if (!check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_'))) + if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_'))) { return; } @@ -995,6 +1155,7 @@ function mcp_fork_topic($topic_ids) $forum_id = request_var('f', 0); $redirect = request_var('redirect', build_url(array('action', 'quickmod'))); $additional_msg = $success_msg = ''; + $counter = array(); $s_hidden_fields = build_hidden_fields(array( 'topic_id_list' => $topic_ids, @@ -1005,7 +1166,7 @@ function mcp_fork_topic($topic_ids) if ($to_forum_id) { - $forum_data = get_forum_data($to_forum_id, 'f_post'); + $forum_data = phpbb_get_forum_data($to_forum_id, 'f_post'); if (!sizeof($topic_ids)) { @@ -1036,37 +1197,32 @@ function mcp_fork_topic($topic_ids) if ($additional_msg) { - unset($_POST['confirm']); - unset($_REQUEST['confirm_key']); + $request->overwrite('confirm', null, \phpbb\request\request_interface::POST); + $request->overwrite('confirm_key', null); } if (confirm_box(true)) { - $topic_data = get_topic_data($topic_ids, 'f_post'); + $topic_data = phpbb_get_topic_data($topic_ids, 'f_post'); - $total_posts = 0; + $total_topics = $total_topics_unapproved = $total_topics_softdeleted = 0; + $total_posts = $total_posts_unapproved = $total_posts_softdeleted = 0; $new_topic_id_list = array(); - foreach ($topic_data as $topic_id => $topic_row) { if (!isset($search_type) && $topic_row['enable_indexing']) { // Select the search method and do some additional checks to ensure it can actually be utilised - $search_type = basename($config['search_type']); - - if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx)) - { - trigger_error('NO_SUCH_SEARCH_MODULE'); - } + $search_type = $config['search_type']; if (!class_exists($search_type)) { - include("{$phpbb_root_path}includes/search/$search_type.$phpEx"); + trigger_error('NO_SUCH_SEARCH_MODULE'); } $error = false; - $search = new $search_type($error); + $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user); $search_mode = 'post'; if ($error) @@ -1083,13 +1239,14 @@ function mcp_fork_topic($topic_ids) 'forum_id' => (int) $to_forum_id, 'icon_id' => (int) $topic_row['icon_id'], 'topic_attachment' => (int) $topic_row['topic_attachment'], - 'topic_approved' => 1, + 'topic_visibility' => (int) $topic_row['topic_visibility'], 'topic_reported' => 0, 'topic_title' => (string) $topic_row['topic_title'], 'topic_poster' => (int) $topic_row['topic_poster'], 'topic_time' => (int) $topic_row['topic_time'], - 'topic_replies' => (int) $topic_row['topic_replies_real'], - 'topic_replies_real' => (int) $topic_row['topic_replies_real'], + 'topic_posts_approved' => (int) $topic_row['topic_posts_approved'], + 'topic_posts_unapproved' => (int) $topic_row['topic_posts_unapproved'], + 'topic_posts_softdeleted' => (int) $topic_row['topic_posts_softdeleted'], 'topic_status' => (int) $topic_row['topic_status'], 'topic_type' => (int) $topic_row['topic_type'], 'topic_first_poster_name' => (string) $topic_row['topic_first_poster_name'], @@ -1110,6 +1267,20 @@ function mcp_fork_topic($topic_ids) $new_topic_id = $db->sql_nextid(); $new_topic_id_list[$topic_id] = $new_topic_id; + switch ($topic_row['topic_visibility']) + { + case ITEM_APPROVED: + $total_topics++; + break; + case ITEM_UNAPPROVED: + case ITEM_REAPPROVE: + $total_topics_unapproved++; + break; + case ITEM_DELETED: + $total_topics_softdeleted++; + break; + } + if ($topic_row['poll_start']) { $poll_rows = array(); @@ -1130,12 +1301,13 @@ function mcp_fork_topic($topic_ids) $db->sql_query('INSERT INTO ' . POLL_OPTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); } + $db->sql_freeresult($result); } $sql = 'SELECT * FROM ' . POSTS_TABLE . " WHERE topic_id = $topic_id - ORDER BY post_time ASC"; + ORDER BY post_time ASC, post_id ASC"; $result = $db->sql_query($sql); $post_rows = array(); @@ -1150,7 +1322,6 @@ function mcp_fork_topic($topic_ids) continue; } - $total_posts += sizeof($post_rows); foreach ($post_rows as $row) { $sql_ary = array( @@ -1160,7 +1331,7 @@ function mcp_fork_topic($topic_ids) 'icon_id' => (int) $row['icon_id'], 'poster_ip' => (string) $row['poster_ip'], 'post_time' => (int) $row['post_time'], - 'post_approved' => 1, + 'post_visibility' => (int) $row['post_visibility'], 'post_reported' => 0, 'enable_bbcode' => (int) $row['enable_bbcode'], 'enable_smilies' => (int) $row['enable_smilies'], @@ -1178,12 +1349,37 @@ function mcp_fork_topic($topic_ids) 'post_edit_time' => (int) $row['post_edit_time'], 'post_edit_count' => (int) $row['post_edit_count'], 'post_edit_locked' => (int) $row['post_edit_locked'], - 'post_postcount' => 0, + 'post_postcount' => $row['post_postcount'], ); - + // Adjust post count only if the post can be incremented to the user counter + if ($row['post_postcount']) + { + if (isset($counter[$row['poster_id']])) + { + ++$counter[$row['poster_id']]; + } + else + { + $counter[$row['poster_id']] = 1; + } + } $db->sql_query('INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); $new_post_id = $db->sql_nextid(); + switch ($row['post_visibility']) + { + case ITEM_APPROVED: + $total_posts++; + break; + case ITEM_UNAPPROVED: + case ITEM_REAPPROVE: + $total_posts_unapproved++; + break; + case ITEM_DELETED: + $total_posts_softdeleted++; + break; + } + // Copy whether the topic is dotted markread('post', $to_forum_id, $new_topic_id, 0, $row['poster_id']); @@ -1276,23 +1472,31 @@ function mcp_fork_topic($topic_ids) } // Sync new topics, parent forums and board stats - sync('topic', 'topic_id', $new_topic_id_list); - - $sync_sql = array(); - - $sync_sql[$to_forum_id][] = 'forum_posts = forum_posts + ' . $total_posts; - $sync_sql[$to_forum_id][] = 'forum_topics = forum_topics + ' . sizeof($new_topic_id_list); - $sync_sql[$to_forum_id][] = 'forum_topics_real = forum_topics_real + ' . sizeof($new_topic_id_list); + $sql = 'UPDATE ' . FORUMS_TABLE . ' + SET forum_posts_approved = forum_posts_approved + ' . $total_posts . ', + forum_posts_unapproved = forum_posts_unapproved + ' . $total_posts_unapproved . ', + forum_posts_softdeleted = forum_posts_softdeleted + ' . $total_posts_softdeleted . ', + forum_topics_approved = forum_topics_approved + ' . $total_topics . ', + forum_topics_unapproved = forum_topics_unapproved + ' . $total_topics_unapproved . ', + forum_topics_softdeleted = forum_topics_softdeleted + ' . $total_topics_softdeleted . ' + WHERE forum_id = ' . $to_forum_id; + $db->sql_query($sql); - foreach ($sync_sql as $forum_id_key => $array) + if (!empty($counter)) { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET ' . implode(', ', $array) . ' - WHERE forum_id = ' . $forum_id_key; - $db->sql_query($sql); + // Do only one query per user and not a query per post. + foreach ($counter as $user_id => $count) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_posts = user_posts + ' . (int) $count . ' + WHERE user_id = ' . (int) $user_id; + $db->sql_query($sql); + } } + sync('topic', 'topic_id', $new_topic_id_list); sync('forum', 'forum_id', $to_forum_id); + set_config_count('num_topics', sizeof($new_topic_id_list), true); set_config_count('num_posts', $total_posts, true); @@ -1335,5 +1539,3 @@ function mcp_fork_topic($topic_ids) trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_notes.php b/phpBB/includes/mcp/mcp_notes.php index 02a89c0251..465ee63a98 100644 --- a/phpBB/includes/mcp/mcp_notes.php +++ b/phpBB/includes/mcp/mcp_notes.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * mcp_notes * Displays notes about a user -* @package mcp */ class mcp_notes { @@ -73,7 +75,7 @@ class mcp_notes function mcp_notes_user_view($action) { global $phpEx, $phpbb_root_path, $config; - global $template, $db, $user, $auth; + global $template, $db, $user, $auth, $phpbb_container; $user_id = request_var('u', 0); $username = request_var('username', '', true); @@ -81,6 +83,7 @@ class mcp_notes $st = request_var('st', 0); $sk = request_var('sk', 'b'); $sd = request_var('sd', 'd'); + $pagination = $phpbb_container->get('pagination'); add_form_key('mcp_notes'); @@ -174,13 +177,9 @@ class mcp_notes } // Generate the appropriate user information for the user we are looking at - if (!function_exists('get_user_avatar')) - { - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - } $rank_title = $rank_img = ''; - $avatar_img = get_user_avatar($userrow['user_avatar'], $userrow['user_avatar_type'], $userrow['user_avatar_width'], $userrow['user_avatar_height']); + $avatar_img = phpbb_get_user_avatar($userrow); $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); $sort_by_text = array('a' => $user->lang['SORT_USERNAME'], 'b' => $user->lang['SORT_DATE'], 'c' => $user->lang['SORT_IP'], 'd' => $user->lang['SORT_ACTION']); @@ -216,6 +215,9 @@ class mcp_notes } } + $base_url = $this->u_action . "&$u_sort_param$keywords_param"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $config['topics_per_page'], $start); + $template->assign_vars(array( 'U_POST_ACTION' => $this->u_action, 'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false, @@ -226,9 +228,7 @@ class mcp_notes 'L_TITLE' => $user->lang['MCP_NOTES_USER'], - 'PAGE_NUMBER' => on_page($log_count, $config['topics_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param$keywords_param", $log_count, $config['topics_per_page'], $start), - 'TOTAL_REPORTS' => ($log_count == 1) ? $user->lang['LIST_REPORT'] : sprintf($user->lang['LIST_REPORTS'], $log_count), + 'TOTAL_REPORTS' => $user->lang('LIST_REPORTS', (int) $log_count), 'RANK_TITLE' => $rank_title, 'JOINED' => $user->format_date($userrow['user_regdate']), @@ -247,5 +247,3 @@ class mcp_notes } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_pm_reports.php b/phpBB/includes/mcp/mcp_pm_reports.php index 0a33c80a90..d76bedba98 100644 --- a/phpBB/includes/mcp/mcp_pm_reports.php +++ b/phpBB/includes/mcp/mcp_pm_reports.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * mcp_reports * Handling the reports queue -* @package mcp */ class mcp_pm_reports { @@ -34,12 +36,13 @@ class mcp_pm_reports function main($id, $mode) { global $auth, $db, $user, $template, $cache; - global $config, $phpbb_root_path, $phpEx, $action; + global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container; include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); include_once($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); $start = request_var('start', 0); + $pagination = $phpbb_container->get('pagination'); $this->page_title = 'MCP_PM_REPORTS'; @@ -90,10 +93,14 @@ class mcp_pm_reports trigger_error('NO_REPORT'); } + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + $phpbb_notifications->mark_notifications_read_by_parent('notification.type.report_pm', $report_id, $user->data['user_id']); + $pm_id = $report['pm_id']; $report_id = $report['report_id']; - $pm_info = get_pm_data(array($pm_id)); + $pm_info = phpbb_get_pm_data(array($pm_id)); if (!sizeof($pm_info)) { @@ -112,17 +119,9 @@ class mcp_pm_reports } // Process message, leave it uncensored - $message = $pm_info['message_text']; + $parse_flags = ($pm_info['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; + $message = generate_text_for_display($pm_info['message_text'], $pm_info['bbcode_uid'], $pm_info['bbcode_bitfield'], $parse_flags, false); - if ($pm_info['bbcode_bitfield']) - { - include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode($pm_info['bbcode_bitfield']); - $bbcode->bbcode_second_pass($message, $pm_info['bbcode_uid'], $pm_info['bbcode_bitfield']); - } - - $message = bbcode_nl2br($message); - $message = smiley_text($message); $report['report_text'] = make_clickable(bbcode_nl2br($report['report_text'])); if ($pm_info['message_attachment'] && $auth->acl_get('u_pm_download')) @@ -174,7 +173,7 @@ class mcp_pm_reports 'U_MCP_USER_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $pm_info['author_id']), 'U_MCP_WARN_REPORTER' => ($auth->acl_get('m_warn')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user&u=' . $report['user_id']) : '', 'U_MCP_WARN_USER' => ($auth->acl_get('m_warn')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user&u=' . $pm_info['author_id']) : '', - + 'EDIT_IMG' => $user->img('icon_post_edit', $user->lang['EDIT_POST']), 'MINI_POST_IMG' => $user->img('icon_post_target', 'POST'), @@ -217,7 +216,7 @@ class mcp_pm_reports $sort_days = $total = 0; $sort_key = $sort_dir = ''; $sort_by_sql = $sort_order_sql = array(); - mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total); + phpbb_mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total); $limit_time_sql = ($sort_days) ? 'AND r.report_time >= ' . (time() - ($sort_days * 86400)) : ''; @@ -294,25 +293,27 @@ class mcp_pm_reports 'REPORT_ID' => $row['report_id'], 'REPORT_TIME' => $user->format_date($row['report_time']), - 'RECIPIENTS' => implode(', ', $address_list[$row['msg_id']]), + 'RECIPIENTS' => implode($user->lang['COMMA_SEPARATOR'], $address_list[$row['msg_id']]), + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $row['message_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', )); } } } + $base_url = $this->u_action . "&st=$sort_days&sk=$sort_key&sd=$sort_dir"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total, $config['topics_per_page'], $start); + // Now display the page $template->assign_vars(array( 'L_EXPLAIN' => ($mode == 'pm_reports') ? $user->lang['MCP_PM_REPORTS_OPEN_EXPLAIN'] : $user->lang['MCP_PM_REPORTS_CLOSED_EXPLAIN'], 'L_TITLE' => ($mode == 'pm_reports') ? $user->lang['MCP_PM_REPORTS_OPEN'] : $user->lang['MCP_PM_REPORTS_CLOSED'], - + 'S_PM' => true, 'S_MCP_ACTION' => $this->u_action, 'S_CLOSED' => ($mode == 'pm_reports_closed') ? true : false, - 'PAGINATION' => generate_pagination($this->u_action . "&st=$sort_days&sk=$sort_key&sd=$sort_dir", $total, $config['topics_per_page'], $start), - 'PAGE_NUMBER' => on_page($total, $config['topics_per_page'], $start), 'TOTAL' => $total, - 'TOTAL_REPORTS' => ($total == 1) ? $user->lang['LIST_REPORT'] : sprintf($user->lang['LIST_REPORTS'], $total), + 'TOTAL_REPORTS' => $user->lang('LIST_REPORTS', (int) $total), ) ); @@ -321,5 +322,3 @@ class mcp_pm_reports } } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_post.php b/phpBB/includes/mcp/mcp_post.php index df5dc27996..1687409198 100644 --- a/phpBB/includes/mcp/mcp_post.php +++ b/phpBB/includes/mcp/mcp_post.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -30,7 +33,7 @@ function mcp_post_details($id, $mode, $action) $start = request_var('start', 0); // Get post data - $post_info = get_post_data(array($post_id), false, true); + $post_info = phpbb_get_post_data(array($post_id), false, true); add_form_key('mcp_post_details'); @@ -40,7 +43,7 @@ function mcp_post_details($id, $mode, $action) } $post_info = $post_info[$post_id]; - $url = append_sid("{$phpbb_root_path}mcp.$phpEx?" . extra_url()); + $url = append_sid("{$phpbb_root_path}mcp.$phpEx?" . phpbb_extra_url()); switch ($action) { @@ -126,17 +129,8 @@ function mcp_post_details($id, $mode, $action) $post_unread = (isset($topic_tracking_info[$post_info['topic_id']]) && $post_info['post_time'] > $topic_tracking_info[$post_info['topic_id']]) ? true : false; // Process message, leave it uncensored - $message = $post_info['post_text']; - - if ($post_info['bbcode_bitfield']) - { - include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode($post_info['bbcode_bitfield']); - $bbcode->bbcode_second_pass($message, $post_info['bbcode_uid'], $post_info['bbcode_bitfield']); - } - - $message = bbcode_nl2br($message); - $message = smiley_text($message); + $parse_flags = ($post_info['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; + $message = generate_text_for_display($post_info['post_text'], $post_info['bbcode_uid'], $post_info['bbcode_bitfield'], $parse_flags, false); if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id'])) { @@ -176,6 +170,33 @@ function mcp_post_details($id, $mode, $action) } } + // Deleting information + if ($post_info['post_visibility'] == ITEM_DELETED && $post_info['post_delete_user']) + { + // User having deleted the post also being the post author? + if (!$post_info['post_delete_user'] || $post_info['post_delete_user'] == $post_info['poster_id']) + { + $display_username = get_username_string('full', $post_info['poster_id'], $post_info['username'], $post_info['user_colour'], $post_info['post_username']); + } + else + { + $sql = 'SELECT user_id, username, user_colour + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . (int) $post_info['post_delete_user']; + $result = $db->sql_query($sql); + $user_delete_row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + $display_username = get_username_string('full', $post_info['post_delete_user'], $user_delete_row['username'], $user_delete_row['user_colour']); + } + + $user->add_lang('viewtopic'); + $l_deleted_by = $user->lang('DELETED_INFORMATION', $display_username, $user->format_date($post_info['post_delete_time'], false, true)); + } + else + { + $l_deleted_by = ''; + } + $template->assign_vars(array( 'U_MCP_ACTION' => "$url&i=main&quickmod=1&mode=post_details", // Use this for mode paramaters 'U_POST_ACTION' => "$url&i=$id&mode=post_details", // Use this for action parameters @@ -187,10 +208,13 @@ function mcp_post_details($id, $mode, $action) 'S_CAN_DELETE_POST' => $auth->acl_get('m_delete', $post_info['forum_id']), 'S_POST_REPORTED' => ($post_info['post_reported']) ? true : false, - 'S_POST_UNAPPROVED' => (!$post_info['post_approved']) ? true : false, + 'S_POST_UNAPPROVED' => ($post_info['post_visibility'] == ITEM_UNAPPROVED || $post_info['post_visibility'] == ITEM_REAPPROVE) ? true : false, + 'S_POST_DELETED' => ($post_info['post_visibility'] == ITEM_DELETED) ? true : false, 'S_POST_LOCKED' => ($post_info['post_edit_locked']) ? true : false, 'S_USER_NOTES' => true, 'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false, + 'DELETED_MESSAGE' => $l_deleted_by, + 'DELETE_REASON' => $post_info['post_delete_reason'], 'U_EDIT' => ($auth->acl_get('m_edit', $post_info['forum_id'])) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&f={$post_info['forum_id']}&p={$post_info['post_id']}") : '', 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=mcp_chgposter&field=username&select_single=true'), @@ -207,6 +231,7 @@ function mcp_post_details($id, $mode, $action) 'RETURN_FORUM' => sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", "f={$post_info['forum_id']}&start={$start}") . '">', '</a>'), 'REPORTED_IMG' => $user->img('icon_topic_reported', $user->lang['POST_REPORTED']), 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', $user->lang['POST_UNAPPROVED']), + 'DELETED_IMG' => $user->img('icon_topic_deleted', $user->lang['POST_DELETED']), 'EDIT_IMG' => $user->img('icon_post_edit', $user->lang['EDIT_POST']), 'SEARCH_IMG' => $user->img('icon_user_search', $user->lang['SEARCH']), @@ -274,8 +299,8 @@ function mcp_post_details($id, $mode, $action) 'REPORT_ID' => $row['report_id'], 'REASON_TITLE' => $row['reason_title'], 'REASON_DESC' => $row['reason_description'], - 'REPORTER' => ($row['user_id'] != ANONYMOUS) ? $row['username'] : $user->lang['GUEST'], - 'U_REPORTER' => ($row['user_id'] != ANONYMOUS) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['user_id']) : '', + 'REPORTER' => get_username_string('username', $row['user_id'], $row['username']), + 'U_REPORTER' => get_username_string('profile', $row['user_id'], $row['username']), 'USER_NOTIFY' => ($row['user_notify']) ? true : false, 'REPORT_TIME' => $user->format_date($row['report_time']), 'REPORT_TEXT' => bbcode_nl2br(trim($row['report_text'])), @@ -334,11 +359,11 @@ function mcp_post_details($id, $mode, $action) foreach ($users_ary as $user_id => $user_row) { $template->assign_block_vars('userrow', array( - 'USERNAME' => ($user_id == ANONYMOUS) ? $user->lang['GUEST'] : $user_row['username'], + 'USERNAME' => get_username_string('username', $user_id, $user_row['username']), 'NUM_POSTS' => $user_row['postings'], 'L_POST_S' => ($user_row['postings'] == 1) ? $user->lang['POST'] : $user->lang['POSTS'], - 'U_PROFILE' => ($user_id == ANONYMOUS) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $user_id), + 'U_PROFILE' => get_username_string('profile', $user_id, $user_row['username']), 'U_SEARCHPOSTS' => append_sid("{$phpbb_root_path}search.$phpEx", 'author_id=' . $user_id . '&sr=topics')) ); } @@ -395,7 +420,7 @@ function mcp_post_details($id, $mode, $action) */ function change_poster(&$post_info, $userdata) { - global $auth, $db, $config, $phpbb_root_path, $phpEx; + global $auth, $db, $config, $phpbb_root_path, $phpEx, $user; if (empty($userdata) || $userdata['user_id'] == $post_info['user_id']) { @@ -417,7 +442,7 @@ function change_poster(&$post_info, $userdata) } // Adjust post counts... only if the post is approved (else, it was not added the users post count anyway) - if ($post_info['post_postcount'] && $post_info['post_approved']) + if ($post_info['post_postcount'] && $post_info['post_visibility'] == ITEM_APPROVED) { $sql = 'UPDATE ' . USERS_TABLE . ' SET user_posts = user_posts - 1 @@ -466,15 +491,13 @@ function change_poster(&$post_info, $userdata) } // refresh search cache of this post - $search_type = basename($config['search_type']); + $search_type = $config['search_type']; - if (file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx)) + if (class_exists($search_type)) { - require("{$phpbb_root_path}includes/search/$search_type.$phpEx"); - // We do some additional checks in the module to ensure it can actually be utilised $error = false; - $search = new $search_type($error); + $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user); if (!$error && method_exists($search, 'destroy_cache')) { @@ -486,7 +509,7 @@ function change_poster(&$post_info, $userdata) $to_username = $userdata['username']; // Renew post info - $post_info = get_post_data(array($post_id), false, true); + $post_info = phpbb_get_post_data(array($post_id), false, true); if (!sizeof($post_info)) { @@ -498,5 +521,3 @@ function change_poster(&$post_info, $userdata) // Now add log entry add_log('mod', $post_info['forum_id'], $post_info['topic_id'], 'LOG_MCP_CHANGE_POSTER', $post_info['topic_title'], $from_username, $to_username); } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php index acf344fd3c..82c3bc9ab0 100644 --- a/phpBB/includes/mcp/mcp_queue.php +++ b/phpBB/includes/mcp/mcp_queue.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,22 +22,22 @@ if (!defined('IN_PHPBB')) /** * mcp_queue * Handling the moderation queue -* @package mcp */ class mcp_queue { var $p_master; var $u_action; - function mcp_queue(&$p_master) + public function mcp_queue(&$p_master) { $this->p_master = &$p_master; } - function main($id, $mode) + public function main($id, $mode) { - global $auth, $db, $user, $template, $cache; - global $config, $phpbb_root_path, $phpEx, $action; + global $auth, $db, $user, $template, $cache, $request; + global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container; + global $phpbb_dispatcher; include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); @@ -46,25 +49,99 @@ class mcp_queue switch ($action) { case 'approve': - case 'disapprove': + case 'restore': include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $post_id_list = request_var('post_id_list', array(0)); + $post_id_list = $request->variable('post_id_list', array(0)); + $topic_id_list = $request->variable('topic_id_list', array(0)); - if (!sizeof($post_id_list)) + if (!empty($post_id_list)) + { + self::approve_posts($action, $post_id_list, 'queue', $mode); + } + else if (!empty($topic_id_list)) + { + self::approve_topics($action, $topic_id_list, 'queue', $mode); + } + else { trigger_error('NO_POST_SELECTED'); } + break; - if ($action == 'approve') + case 'delete': + $post_id_list = $request->variable('post_id_list', array(0)); + $topic_id_list = $request->variable('topic_id_list', array(0)); + + if (!empty($post_id_list)) + { + if (!function_exists('mcp_delete_post')) + { + global $phpbb_root_path, $phpEx; + include($phpbb_root_path . 'includes/mcp/mcp_main.' . $phpEx); + } + mcp_delete_post($post_id_list, false, '', $action); + } + else if (!empty($topic_id_list)) { - approve_post($post_id_list, 'queue', $mode); + if (!function_exists('mcp_delete_topic')) + { + global $phpbb_root_path, $phpEx; + include($phpbb_root_path . 'includes/mcp/mcp_main.' . $phpEx); + } + mcp_delete_topic($topic_id_list, false, '', $action); } else { - disapprove_post($post_id_list, 'queue', $mode); + trigger_error('NO_POST_SELECTED'); } + break; + case 'disapprove': + $post_id_list = $request->variable('post_id_list', array(0)); + $topic_id_list = $request->variable('topic_id_list', array(0)); + + if (!empty($topic_id_list) && $mode == 'deleted_topics') + { + if (!function_exists('mcp_delete_topics')) + { + global $phpbb_root_path, $phpEx; + include($phpbb_root_path . 'includes/mcp/mcp_main.' . $phpEx); + } + mcp_delete_topic($topic_id_list, false, '', 'disapprove'); + return; + } + + if (!class_exists('messenger')) + { + include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); + } + + if (!empty($topic_id_list)) + { + $post_visibility = ($mode == 'deleted_topics') ? ITEM_DELETED : array(ITEM_UNAPPROVED, ITEM_REAPPROVE); + $sql = 'SELECT post_id + FROM ' . POSTS_TABLE . ' + WHERE ' . $db->sql_in_set('post_visibility', $post_visibility) . ' + AND ' . $db->sql_in_set('topic_id', $topic_id_list); + $result = $db->sql_query($sql); + + $post_id_list = array(); + while ($row = $db->sql_fetchrow($result)) + { + $post_id_list[] = (int) $row['post_id']; + } + $db->sql_freeresult($result); + } + + if (!empty($post_id_list)) + { + self::disapprove_posts($post_id_list, 'queue', $mode); + } + else + { + trigger_error('NO_POST_SELECTED'); + } break; } @@ -79,12 +156,16 @@ class mcp_queue $post_id = request_var('p', 0); $topic_id = request_var('t', 0); + $phpbb_notifications = $phpbb_container->get('notification_manager'); + if ($topic_id) { - $topic_info = get_topic_data(array($topic_id), 'm_approve'); + $topic_info = phpbb_get_topic_data(array($topic_id), 'm_approve'); if (isset($topic_info[$topic_id]['topic_first_post_id'])) { $post_id = (int) $topic_info[$topic_id]['topic_first_post_id']; + + $phpbb_notifications->mark_notifications_read('notification.type.topic_in_queue', $topic_id, $user->data['user_id']); } else { @@ -92,7 +173,9 @@ class mcp_queue } } - $post_info = get_post_data(array($post_id), 'm_approve', true); + $phpbb_notifications->mark_notifications_read('notification.type.post_in_queue', $post_id, $user->data['user_id']); + + $post_info = phpbb_get_post_data(array($post_id), 'm_approve', true); if (!sizeof($post_info)) { @@ -106,8 +189,8 @@ class mcp_queue $template->assign_vars(array( 'S_TOPIC_REVIEW' => true, 'S_BBCODE_ALLOWED' => $post_info['enable_bbcode'], - 'TOPIC_TITLE' => $post_info['topic_title']) - ); + 'TOPIC_TITLE' => $post_info['topic_title'], + )); } $extensions = $attachments = $topic_tracking_info = array(); @@ -127,17 +210,8 @@ class mcp_queue $post_unread = (isset($topic_tracking_info[$post_info['topic_id']]) && $post_info['post_time'] > $topic_tracking_info[$post_info['topic_id']]) ? true : false; // Process message, leave it uncensored - $message = $post_info['post_text']; - - if ($post_info['bbcode_bitfield']) - { - include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode($post_info['bbcode_bitfield']); - $bbcode->bbcode_second_pass($message, $post_info['bbcode_uid'], $post_info['bbcode_bitfield']); - } - - $message = bbcode_nl2br($message); - $message = smiley_text($message); + $parse_flags = ($post_info['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; + $message = generate_text_for_display($post_info['post_text'], $post_info['bbcode_uid'], $post_info['bbcode_bitfield'], $parse_flags, false); if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id'])) { @@ -170,12 +244,39 @@ class mcp_queue foreach ($attachments as $attachment) { $template->assign_block_vars('attachment', array( - 'DISPLAY_ATTACHMENT' => $attachment) - ); + 'DISPLAY_ATTACHMENT' => $attachment, + )); } } } + // Deleting information + if ($post_info['post_visibility'] == ITEM_DELETED && $post_info['post_delete_user']) + { + // User having deleted the post also being the post author? + if (!$post_info['post_delete_user'] || $post_info['post_delete_user'] == $post_info['poster_id']) + { + $display_username = get_username_string('full', $post_info['poster_id'], $post_info['username'], $post_info['user_colour'], $post_info['post_username']); + } + else + { + $sql = 'SELECT u.user_id, u.username, u.user_colour + FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u + WHERE p.post_id = ' . $post_info['post_id'] . ' + AND p.post_delete_user = u.user_id'; + $result = $db->sql_query($sql); + $post_delete_userinfo = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + $display_username = get_username_string('full', $post_info['post_delete_user'], $post_delete_userinfo['username'], $post_delete_userinfo['user_colour']); + } + + $l_deleted_by = $user->lang('DELETED_INFORMATION', $display_username, $user->format_date($post_info['post_delete_time'], false, true)); + } + else + { + $l_deleted_by = ''; + } + $post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $post_info['forum_id'] . '&p=' . $post_info['post_id'] . '#p' . $post_info['post_id']); $topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $post_info['forum_id'] . '&t=' . $post_info['topic_id']); @@ -184,9 +285,12 @@ class mcp_queue 'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&p=$post_id&f=$forum_id"), 'S_CAN_VIEWIP' => $auth->acl_get('m_info', $post_info['forum_id']), 'S_POST_REPORTED' => $post_info['post_reported'], - 'S_POST_UNAPPROVED' => !$post_info['post_approved'], + 'S_POST_UNAPPROVED' => $post_info['post_visibility'] == ITEM_UNAPPROVED || $post_info['post_visibility'] == ITEM_REAPPROVE, 'S_POST_LOCKED' => $post_info['post_edit_locked'], 'S_USER_NOTES' => true, + 'S_POST_DELETED' => ($post_info['post_visibility'] == ITEM_DELETED), + 'DELETED_MESSAGE' => $l_deleted_by, + 'DELETE_REASON' => $post_info['post_delete_reason'], 'U_EDIT' => ($auth->acl_get('m_edit', $post_info['forum_id'])) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&f={$post_info['forum_id']}&p={$post_info['post_id']}") : '', 'U_MCP_APPROVE' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=approve_details&f=' . $post_info['forum_id'] . '&p=' . $post_id), @@ -198,7 +302,7 @@ class mcp_queue 'MINI_POST_IMG' => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'), - 'RETURN_QUEUE' => sprintf($user->lang['RETURN_QUEUE'], '<a href="' . append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue' . (($topic_id) ? '&mode=unapproved_topics' : '&mode=unapproved_posts')) . "&start=$start\">", '</a>'), + 'RETURN_QUEUE' => sprintf($user->lang['RETURN_QUEUE'], '<a href="' . append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue' . (($topic_id) ? '&mode=unapproved_topics' : '&mode=unapproved_posts')) . '&start=' . $start . '">', '</a>'), 'RETURN_POST' => sprintf($user->lang['RETURN_POST'], '<a href="' . $post_url . '">', '</a>'), 'RETURN_TOPIC_SIMPLE' => sprintf($user->lang['RETURN_TOPIC_SIMPLE'], '<a href="' . $topic_url . '">', '</a>'), 'REPORTED_IMG' => $user->img('icon_topic_reported', $user->lang['POST_REPORTED']), @@ -225,14 +329,22 @@ class mcp_queue case 'unapproved_topics': case 'unapproved_posts': + case 'deleted_topics': + case 'deleted_posts': + $m_perm = 'm_approve'; + $is_topics = ($mode == 'unapproved_topics' || $mode == 'deleted_topics') ? true : false; + $is_restore = ($mode == 'deleted_posts' || $mode == 'deleted_topics') ? true : false; + $visibility_const = (!$is_restore) ? array(ITEM_UNAPPROVED, ITEM_REAPPROVE) : ITEM_DELETED; + $user->add_lang(array('viewtopic', 'viewforum')); - $topic_id = request_var('t', 0); + $topic_id = $request->variable('t', 0); $forum_info = array(); + $pagination = $phpbb_container->get('pagination'); if ($topic_id) { - $topic_info = get_topic_data(array($topic_id)); + $topic_info = phpbb_get_topic_data(array($topic_id)); if (!sizeof($topic_info)) { @@ -243,7 +355,7 @@ class mcp_queue $forum_id = $topic_info['forum_id']; } - $forum_list_approve = get_forum_list('m_approve', false, true); + $forum_list_approve = get_forum_list($m_perm, false, true); $forum_list_read = array_flip(get_forum_list('f_read', true, true)); // Flipped so we can isset() the forum IDs // Remove forums we cannot read @@ -269,20 +381,16 @@ class mcp_queue trigger_error('NOT_MODERATOR'); } - $global_id = $forum_list[0]; - - $forum_list = implode(', ', $forum_list); - - $sql = 'SELECT SUM(forum_topics) as sum_forum_topics - FROM ' . FORUMS_TABLE . " - WHERE forum_id IN (0, $forum_list)"; + $sql = 'SELECT SUM(forum_topics_approved) as sum_forum_topics + FROM ' . FORUMS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $forum_list); $result = $db->sql_query($sql); - $forum_info['forum_topics'] = (int) $db->sql_fetchfield('sum_forum_topics'); + $forum_info['forum_topics_approved'] = (int) $db->sql_fetchfield('sum_forum_topics'); $db->sql_freeresult($result); } else { - $forum_info = get_forum_data(array($forum_id), 'm_approve'); + $forum_info = phpbb_get_forum_data(array($forum_id), $m_perm); if (!sizeof($forum_info)) { @@ -291,7 +399,6 @@ class mcp_queue $forum_info = $forum_info[$forum_id]; $forum_list = $forum_id; - $global_id = $forum_id; } $forum_options = '<option value="0"' . (($forum_id == 0) ? ' selected="selected"' : '') . '>' . $user->lang['ALL_FORUMS'] . '</option>'; @@ -303,25 +410,49 @@ class mcp_queue $sort_days = $total = 0; $sort_key = $sort_dir = ''; $sort_by_sql = $sort_order_sql = array(); - mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id); + phpbb_mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id); - $forum_topics = ($total == -1) ? $forum_info['forum_topics'] : $total; + $forum_topics = ($total == -1) ? $forum_info['forum_topics_approved'] : $total; $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : ''; $forum_names = array(); - if ($mode == 'unapproved_posts') + if (!$is_topics) { $sql = 'SELECT p.post_id - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t' . (($sort_order_sql[0] == 'u') ? ', ' . USERS_TABLE . ' u' : '') . " - WHERE p.forum_id IN (0, $forum_list) - AND p.post_approved = 0 - " . (($sort_order_sql[0] == 'u') ? 'AND u.user_id = p.poster_id' : '') . ' + FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t' . (($sort_order_sql[0] == 'u') ? ', ' . USERS_TABLE . ' u' : '') . ' + WHERE ' . $db->sql_in_set('p.forum_id', $forum_list) . ' + AND ' . $db->sql_in_set('p.post_visibility', $visibility_const) . ' + ' . (($sort_order_sql[0] == 'u') ? 'AND u.user_id = p.poster_id' : '') . ' ' . (($topic_id) ? 'AND p.topic_id = ' . $topic_id : '') . " AND t.topic_id = p.topic_id - AND t.topic_first_post_id <> p.post_id + AND (t.topic_visibility <> p.post_visibility + OR t.topic_delete_user = 0) $limit_time_sql ORDER BY $sort_order_sql"; + + /** + * Alter sql query to get posts in queue to be accepted + * + * @event core.mcp_queue_get_posts_query_before + * @var string sql Associative array with the query to be executed + * @var array forum_list List of forums that contain the posts + * @var int visibility_const Integer with one of the possible ITEM_* constant values + * @var int topic_id If topic_id not equal to 0, the topic id to filter the posts to display + * @var string limit_time_sql String with the SQL code to limit the time interval of the post (Note: May be empty string) + * @var string sort_order_sql String with the ORDER BY SQL code used in this query + * @since 3.1.0-RC3 + */ + $vars = array( + 'sql', + 'forum_list', + 'visibility_const', + 'topic_id', + 'limit_time_sql', + 'sort_order_sql', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_queue_get_posts_query_before', compact($vars))); + $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); $i = 0; @@ -335,7 +466,7 @@ class mcp_queue if (sizeof($post_ids)) { - $sql = 'SELECT t.topic_id, t.topic_title, t.forum_id, p.post_id, p.post_subject, p.post_username, p.poster_id, p.post_time, u.username, u.username_clean, u.user_colour + $sql = 'SELECT t.topic_id, t.topic_title, t.forum_id, p.post_id, p.post_subject, p.post_username, p.poster_id, p.post_time, p.post_attachment, u.username, u.username_clean, u.user_colour FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . USERS_TABLE . ' u WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' AND t.topic_id = p.topic_id @@ -346,10 +477,7 @@ class mcp_queue $post_data = $rowset = array(); while ($row = $db->sql_fetchrow($result)) { - if ($row['forum_id']) - { - $forum_names[] = $row['forum_id']; - } + $forum_names[] = $row['forum_id']; $post_data[$row['post_id']] = $row; } $db->sql_freeresult($result); @@ -367,21 +495,42 @@ class mcp_queue } else { - $sql = 'SELECT t.forum_id, t.topic_id, t.topic_title, t.topic_title AS post_subject, t.topic_time AS post_time, t.topic_poster AS poster_id, t.topic_first_post_id AS post_id, t.topic_first_poster_name AS username, t.topic_first_poster_colour AS user_colour - FROM ' . TOPICS_TABLE . " t - WHERE forum_id IN (0, $forum_list) - AND topic_approved = 0 + $sql = 'SELECT t.forum_id, t.topic_id, t.topic_title, t.topic_title AS post_subject, t.topic_time AS post_time, t.topic_poster AS poster_id, t.topic_first_post_id AS post_id, t.topic_attachment AS post_attachment, t.topic_first_poster_name AS username, t.topic_first_poster_colour AS user_colour + FROM ' . TOPICS_TABLE . ' t + WHERE ' . $db->sql_in_set('forum_id', $forum_list) . ' + AND ' . $db->sql_in_set('topic_visibility', $visibility_const) . " + AND topic_delete_user <> 0 $limit_time_sql ORDER BY $sort_order_sql"; + + /** + * Alter sql query to get information on all topics in the list of forums provided. + * + * @event core.mcp_queue_get_posts_for_topics_query_before + * @var string sql String with the query to be executed + * @var array forum_list List of forums that contain the posts + * @var int visibility_const Integer with one of the possible ITEM_* constant values + * @var int topic_id topic_id in the page request + * @var string limit_time_sql String with the SQL code to limit the time interval of the post (Note: May be empty string) + * @var string sort_order_sql String with the ORDER BY SQL code used in this query + * @since 3.1.0-RC3 + */ + $vars = array( + 'sql', + 'forum_list', + 'visibility_const', + 'topic_id', + 'limit_time_sql', + 'sort_order_sql', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_queue_get_posts_for_topics_query_before', compact($vars))); + $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); $rowset = array(); while ($row = $db->sql_fetchrow($result)) { - if ($row['forum_id']) - { - $forum_names[] = $row['forum_id']; - } + $forum_names[] = $row['forum_id']; $rowset[] = $row; } $db->sql_freeresult($result); @@ -405,20 +554,14 @@ class mcp_queue foreach ($rowset as $row) { - $global_topic = ($row['forum_id']) ? false : true; - if ($global_topic) - { - $row['forum_id'] = $global_id; - } - if (empty($row['post_username'])) { - $row['post_username'] = $user->lang['GUEST']; + $row['post_username'] = $row['username'] ?: $user->lang['GUEST']; } $template->assign_block_vars('postrow', array( 'U_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id'] . '&t=' . $row['topic_id']), - 'U_VIEWFORUM' => (!$global_topic) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : '', + 'U_VIEWFORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']), 'U_VIEWPOST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id'] . '&p=' . $row['post_id']) . (($mode == 'unapproved_posts') ? '#p' . $row['post_id'] : ''), 'U_VIEW_DETAILS' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&start=$start&mode=approve_details&f={$row['forum_id']}&p={$row['post_id']}" . (($mode == 'unapproved_topics') ? "&t={$row['topic_id']}" : '')), @@ -428,574 +571,855 @@ class mcp_queue 'U_POST_AUTHOR' => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), 'POST_ID' => $row['post_id'], - 'FORUM_NAME' => (!$global_topic) ? $forum_names[$row['forum_id']] : $user->lang['GLOBAL_ANNOUNCEMENT'], + 'TOPIC_ID' => $row['topic_id'], + 'FORUM_NAME' => $forum_names[$row['forum_id']], 'POST_SUBJECT' => ($row['post_subject'] != '') ? $row['post_subject'] : $user->lang['NO_SUBJECT'], 'TOPIC_TITLE' => $row['topic_title'], - 'POST_TIME' => $user->format_date($row['post_time'])) - ); + 'POST_TIME' => $user->format_date($row['post_time']), + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['post_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', + )); } unset($rowset, $forum_names); + $base_url = $this->u_action . "&f=$forum_id&st=$sort_days&sk=$sort_key&sd=$sort_dir"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total, $config['topics_per_page'], $start); + // Now display the page $template->assign_vars(array( - 'L_DISPLAY_ITEMS' => ($mode == 'unapproved_posts') ? $user->lang['DISPLAY_POSTS'] : $user->lang['DISPLAY_TOPICS'], - 'L_EXPLAIN' => ($mode == 'unapproved_posts') ? $user->lang['MCP_QUEUE_UNAPPROVED_POSTS_EXPLAIN'] : $user->lang['MCP_QUEUE_UNAPPROVED_TOPICS_EXPLAIN'], - 'L_TITLE' => ($mode == 'unapproved_posts') ? $user->lang['MCP_QUEUE_UNAPPROVED_POSTS'] : $user->lang['MCP_QUEUE_UNAPPROVED_TOPICS'], + 'L_DISPLAY_ITEMS' => (!$is_topics) ? $user->lang['DISPLAY_POSTS'] : $user->lang['DISPLAY_TOPICS'], + 'L_EXPLAIN' => $user->lang['MCP_QUEUE_' . strtoupper($mode) . '_EXPLAIN'], + 'L_TITLE' => $user->lang['MCP_QUEUE_' . strtoupper($mode)], 'L_ONLY_TOPIC' => ($topic_id) ? sprintf($user->lang['ONLY_TOPIC'], $topic_info['topic_title']) : '', 'S_FORUM_OPTIONS' => $forum_options, 'S_MCP_ACTION' => build_url(array('t', 'f', 'sd', 'st', 'sk')), - 'S_TOPICS' => ($mode == 'unapproved_posts') ? false : true, + 'S_TOPICS' => $is_topics, + 'S_RESTORE' => $is_restore, - 'PAGINATION' => generate_pagination($this->u_action . "&f=$forum_id&st=$sort_days&sk=$sort_key&sd=$sort_dir", $total, $config['topics_per_page'], $start), - 'PAGE_NUMBER' => on_page($total, $config['topics_per_page'], $start), 'TOPIC_ID' => $topic_id, - 'TOTAL' => ($total == 1) ? (($mode == 'unapproved_posts') ? $user->lang['VIEW_TOPIC_POST'] : $user->lang['VIEW_FORUM_TOPIC']) : sprintf((($mode == 'unapproved_posts') ? $user->lang['VIEW_TOPIC_POSTS'] : $user->lang['VIEW_FORUM_TOPICS']), $total), + 'TOTAL' => $user->lang(((!$is_topics) ? 'VIEW_TOPIC_POSTS' : 'VIEW_FORUM_TOPICS'), (int) $total), )); $this->tpl_name = 'mcp_queue'; break; } } -} -/** -* Approve Post/Topic -*/ -function approve_post($post_id_list, $id, $mode) -{ - global $db, $template, $user, $config; - global $phpEx, $phpbb_root_path; - - if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve'))) + /** + * Approve/Restore posts + * + * @param $action string Action we perform on the posts ('approve' or 'restore') + * @param $post_id_list array IDs of the posts to approve/restore + * @param $id mixed Category of the current active module + * @param $mode string Active module + * @return null + */ + static public function approve_posts($action, $post_id_list, $id, $mode) { - trigger_error('NOT_AUTHORISED'); - } - - $redirect = request_var('redirect', build_url(array('quickmod'))); - $success_msg = ''; + global $db, $template, $user, $config, $request, $phpbb_container, $phpbb_dispatcher; + global $phpEx, $phpbb_root_path; - $s_hidden_fields = build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'post_id_list' => $post_id_list, - 'action' => 'approve', - 'redirect' => $redirect) - ); - - $post_info = get_post_data($post_id_list, 'm_approve'); + if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve'))) + { + trigger_error('NOT_AUTHORISED'); + } - if (confirm_box(true)) - { - $notify_poster = (isset($_REQUEST['notify_poster'])) ? true : false; + $redirect = $request->variable('redirect', build_url(array('quickmod'))); + $redirect = reapply_sid($redirect); + $success_msg = $post_url = ''; + $approve_log = array(); + $num_topics = 0; - // If Topic -> total_topics = total_topics+1, total_posts = total_posts+1, forum_topics = forum_topics+1, forum_posts = forum_posts+1 - // If Post -> total_posts = total_posts+1, forum_posts = forum_posts+1, topic_replies = topic_replies+1 + $s_hidden_fields = build_hidden_fields(array( + 'i' => $id, + 'mode' => $mode, + 'post_id_list' => $post_id_list, + 'action' => $action, + 'redirect' => $redirect, + )); - $total_topics = $total_posts = 0; - $topic_approve_sql = $post_approve_sql = $topic_id_list = $forum_id_list = $approve_log = array(); - $user_posts_sql = $post_approved_list = array(); + $post_info = phpbb_get_post_data($post_id_list, 'm_approve'); - foreach ($post_info as $post_id => $post_data) + if (confirm_box(true)) { - if ($post_data['post_approved']) - { - $post_approved_list[] = $post_id; - continue; - } + $notify_poster = ($action == 'approve' && isset($_REQUEST['notify_poster'])); - $topic_id_list[$post_data['topic_id']] = 1; + $topic_info = array(); - if ($post_data['forum_id']) + // Group the posts by topic_id + foreach ($post_info as $post_id => $post_data) { - $forum_id_list[$post_data['forum_id']] = 1; - } + if ($post_data['post_visibility'] == ITEM_APPROVED) + { + continue; + } + $topic_id = (int) $post_data['topic_id']; - // User post update (we do not care about topic or post, since user posts are strictly connected to posts) - // But we care about forums where post counts get not increased. ;) - if ($post_data['post_postcount']) - { - $user_posts_sql[$post_data['poster_id']] = (empty($user_posts_sql[$post_data['poster_id']])) ? 1 : $user_posts_sql[$post_data['poster_id']] + 1; - } + $topic_info[$topic_id]['posts'][] = (int) $post_id; + $topic_info[$topic_id]['forum_id'] = (int) $post_data['forum_id']; - // Topic or Post. ;) - if ($post_data['topic_first_post_id'] == $post_id) - { - if ($post_data['forum_id']) + // Refresh the first post, if the time or id is older then the current one + if ($post_id <= $post_data['topic_first_post_id'] || $post_data['post_time'] <= $post_data['topic_time']) + { + $topic_info[$topic_id]['first_post'] = true; + } + + // Refresh the last post, if the time or id is newer then the current one + if ($post_id >= $post_data['topic_last_post_id'] || $post_data['post_time'] >= $post_data['topic_last_post_time']) { - $total_topics++; + $topic_info[$topic_id]['last_post'] = true; } - $topic_approve_sql[] = $post_data['topic_id']; + + $post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f={$post_data['forum_id']}&t={$post_data['topic_id']}&p={$post_data['post_id']}") . '#p' . $post_data['post_id']; $approve_log[] = array( - 'type' => 'topic', - 'post_subject' => $post_data['post_subject'], 'forum_id' => $post_data['forum_id'], 'topic_id' => $post_data['topic_id'], + 'post_subject' => $post_data['post_subject'], ); } - else + + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + foreach ($topic_info as $topic_id => $topic_data) { - $approve_log[] = array( - 'type' => 'post', - 'post_subject' => $post_data['post_subject'], - 'forum_id' => $post_data['forum_id'], - 'topic_id' => $post_data['topic_id'], - ); + $phpbb_content_visibility->set_post_visibility(ITEM_APPROVED, $topic_data['posts'], $topic_id, $topic_data['forum_id'], $user->data['user_id'], time(), '', isset($topic_data['first_post']), isset($topic_data['last_post'])); + } + + foreach ($approve_log as $log_data) + { + add_log('mod', $log_data['forum_id'], $log_data['topic_id'], 'LOG_POST_' . strtoupper($action) . 'D', $log_data['post_subject']); } - if ($post_data['forum_id']) + // Only send out the mails, when the posts are being approved + if ($action == 'approve') { - $total_posts++; + $phpbb_notifications = $phpbb_container->get('notification_manager'); - // Increment by topic_replies if we approve a topic... - // This works because we do not adjust the topic_replies when re-approving a topic after an edit. - if ($post_data['topic_first_post_id'] == $post_id && $post_data['topic_replies']) + // Handle notifications + foreach ($post_info as $post_id => $post_data) { - $total_posts += $post_data['topic_replies']; + // A single topic approval may also happen here, so handle deleting the respective notification. + if (!$post_data['topic_posts_approved']) + { + $phpbb_notifications->delete_notifications('notification.type.topic_in_queue', $post_data['topic_id']); + + if ($post_data['post_visibility'] == ITEM_UNAPPROVED) + { + $phpbb_notifications->add_notifications(array('notification.type.topic'), $post_data); + } + if ($post_data['post_visibility'] != ITEM_APPROVED) + { + $num_topics++; + } + } + else + { + // Only add notifications, if we are not reapproving post + // When the topic was already approved, but was edited and + // now needs re-approval, we don't want to notify the users + // again. + if ($post_data['post_visibility'] == ITEM_UNAPPROVED) + { + $phpbb_notifications->add_notifications(array( + 'notification.type.bookmark', + 'notification.type.post', + ), $post_data); + } + } + $phpbb_notifications->add_notifications(array('notification.type.quote'), $post_data); + $phpbb_notifications->delete_notifications('notification.type.post_in_queue', $post_id); + + $phpbb_notifications->mark_notifications_read(array( + 'notification.type.quote', + 'notification.type.bookmark', + 'notification.type.post', + ), $post_data['post_id'], $user->data['user_id']); + + // Notify Poster? + if ($notify_poster) + { + if ($post_data['poster_id'] == ANONYMOUS) + { + continue; + } + + if (!$post_data['topic_posts_approved']) + { + $phpbb_notifications->add_notifications('notification.type.approve_topic', $post_data); + } + else + { + $phpbb_notifications->add_notifications('notification.type.approve_post', $post_data); + } + } } } - $post_approve_sql[] = $post_id; - } + if ($num_topics >= 1) + { + $success_msg = ($num_topics == 1) ? 'TOPIC_' . strtoupper($action) . 'D_SUCCESS' : 'TOPICS_' . strtoupper($action) . 'D_SUCCESS'; + } + else + { + $success_msg = (sizeof($post_info) == 1) ? 'POST_' . strtoupper($action) . 'D_SUCCESS' : 'POSTS_' . strtoupper($action) . 'D_SUCCESS'; + } - $post_id_list = array_values(array_diff($post_id_list, $post_approved_list)); - for ($i = 0, $size = sizeof($post_approved_list); $i < $size; $i++) - { - unset($post_info[$post_approved_list[$i]]); - } + /** + * Perform additional actions during post(s) approval + * + * @event core.approve_posts_after + * @var string action Variable containing the action we perform on the posts ('approve' or 'restore') + * @var array post_info Array containing info for all posts being approved + * @var array topic_info Array containing info for all parent topics of the posts + * @var int num_topics Variable containing number of topics + * @var bool notify_poster Variable telling if the post should be notified or not + * @var string success_msg Variable containing the language key for the success message + * @var string redirect Variable containing the redirect url + * @since 3.1.4-RC1 + */ + $vars = array( + 'action', + 'post_info', + 'topic_info', + 'num_topics', + 'notify_poster', + 'success_msg', + 'redirect', + ); + extract($phpbb_dispatcher->trigger_event('core.approve_posts_after', compact($vars))); + + meta_refresh(3, $redirect); + $message = $user->lang[$success_msg]; + + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $message, + 'REFRESH_DATA' => null, + 'visible' => true, + )); + } + $message .= '<br /><br />' . $user->lang('RETURN_PAGE', '<a href="' . $redirect . '">', '</a>'); - if (sizeof($topic_approve_sql)) - { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_approved = 1 - WHERE ' . $db->sql_in_set('topic_id', $topic_approve_sql); - $db->sql_query($sql); + // If approving one post, also give links back to post... + if (sizeof($post_info) == 1 && $post_url) + { + $message .= '<br /><br />' . $user->lang('RETURN_POST', '<a href="' . $post_url . '">', '</a>'); + } + trigger_error($message); } - - if (sizeof($post_approve_sql)) + else { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_approved = 1 - WHERE ' . $db->sql_in_set('post_id', $post_approve_sql); - $db->sql_query($sql); - } + $show_notify = false; - unset($topic_approve_sql, $post_approve_sql); + if ($action == 'approve') + { + foreach ($post_info as $post_data) + { + if (!$post_data['topic_posts_approved']) + { + $num_topics++; + } - foreach ($approve_log as $log_data) - { - add_log('mod', $log_data['forum_id'], $log_data['topic_id'], ($log_data['type'] == 'topic') ? 'LOG_TOPIC_APPROVED' : 'LOG_POST_APPROVED', $log_data['post_subject']); - } + if (!$show_notify && $post_data['poster_id'] != ANONYMOUS) + { + $show_notify = true; + } + } + } - if (sizeof($user_posts_sql)) - { - // Try to minimize the query count by merging users with the same post count additions - $user_posts_update = array(); + $template->assign_vars(array( + 'S_NOTIFY_POSTER' => $show_notify, + 'S_' . strtoupper($action) => true, + )); - foreach ($user_posts_sql as $user_id => $user_posts) + // Create the confirm box message + $action_msg = strtoupper($action); + $num_posts = sizeof($post_id_list) - $num_topics; + if ($num_topics > 0 && $num_posts <= 0) { - $user_posts_update[$user_posts][] = $user_id; + $action_msg .= '_TOPIC' . (($num_topics == 1) ? '' : 'S'); } - - foreach ($user_posts_update as $user_posts => $user_id_ary) + else { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_posts = user_posts + ' . $user_posts . ' - WHERE ' . $db->sql_in_set('user_id', $user_id_ary); - $db->sql_query($sql); + $action_msg .= '_POST' . ((sizeof($post_id_list) == 1) ? '' : 'S'); } + confirm_box(false, $action_msg, $s_hidden_fields, 'mcp_approve.html'); } - if ($total_topics) - { - set_config_count('num_topics', $total_topics, true); - } + redirect($redirect); + } - if ($total_posts) + /** + * Approve/Restore topics + * + * @param $action string Action we perform on the posts ('approve' or 'restore') + * @param $topic_id_list array IDs of the topics to approve/restore + * @param $id mixed Category of the current active module + * @param $mode string Active module + * @return null + */ + static public function approve_topics($action, $topic_id_list, $id, $mode) + { + global $db, $template, $user, $config; + global $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_dispatcher; + + if (!phpbb_check_ids($topic_id_list, TOPICS_TABLE, 'topic_id', array('m_approve'))) { - set_config_count('num_posts', $total_posts, true); + trigger_error('NOT_AUTHORISED'); } - sync('topic', 'topic_id', array_keys($topic_id_list), true); - sync('forum', 'forum_id', array_keys($forum_id_list), true, true); - unset($topic_id_list, $forum_id_list); + $redirect = $request->variable('redirect', build_url(array('quickmod'))); + $redirect = reapply_sid($redirect); + $success_msg = $topic_url = ''; + $approve_log = array(); - $messenger = new messenger(); + $s_hidden_fields = build_hidden_fields(array( + 'i' => $id, + 'mode' => $mode, + 'topic_id_list' => $topic_id_list, + 'action' => $action, + 'redirect' => $redirect, + )); - // Notify Poster? - if ($notify_poster) - { - foreach ($post_info as $post_id => $post_data) - { - if ($post_data['poster_id'] == ANONYMOUS) - { - continue; - } + $topic_info = phpbb_get_topic_data($topic_id_list, 'm_approve'); - $email_template = ($post_data['post_id'] == $post_data['topic_first_post_id'] && $post_data['post_id'] == $post_data['topic_last_post_id']) ? 'topic_approved' : 'post_approved'; + if (confirm_box(true)) + { + $notify_poster = ($action == 'approve' && isset($_REQUEST['notify_poster'])) ? true : false; - $messenger->template($email_template, $post_data['user_lang']); + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + $first_post_ids = array(); - $messenger->to($post_data['user_email'], $post_data['username']); - $messenger->im($post_data['user_jabber'], $post_data['username']); + foreach ($topic_info as $topic_id => $topic_data) + { + $phpbb_content_visibility->set_topic_visibility(ITEM_APPROVED, $topic_id, $topic_data['forum_id'], $user->data['user_id'], time(), ''); + $first_post_ids[$topic_id] = (int) $topic_data['topic_first_post_id']; - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($post_data['username']), - 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_data['post_subject'])), - 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_data['topic_title'])), + $topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f={$topic_data['forum_id']}&t={$topic_id}"); - 'U_VIEW_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f={$post_data['forum_id']}&t={$post_data['topic_id']}&e=0", - 'U_VIEW_POST' => generate_board_url() . "/viewtopic.$phpEx?f={$post_data['forum_id']}&t={$post_data['topic_id']}&p=$post_id&e=$post_id") + $approve_log[] = array( + 'forum_id' => $topic_data['forum_id'], + 'topic_id' => $topic_data['topic_id'], + 'topic_title' => $topic_data['topic_title'], ); + } - $messenger->send($post_data['user_notify_type']); + if (sizeof($topic_info) >= 1) + { + $success_msg = (sizeof($topic_info) == 1) ? 'TOPIC_' . strtoupper($action) . 'D_SUCCESS' : 'TOPICS_' . strtoupper($action) . 'D_SUCCESS'; + } + + foreach ($approve_log as $log_data) + { + add_log('mod', $log_data['forum_id'], $log_data['topic_id'], 'LOG_TOPIC_' . strtoupper($action) . 'D', $log_data['topic_title']); } - } - $messenger->save_queue(); + // Only send out the mails, when the posts are being approved + if ($action == 'approve') + { + // Grab the first post text as it's needed for the quote notification. + $sql = 'SELECT topic_id, post_text + FROM ' . POSTS_TABLE . ' + WHERE ' . $db->sql_in_set('post_id', $first_post_ids); + $result = $db->sql_query($sql); - // Send out normal user notifications - $email_sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']); + while ($row = $db->sql_fetchrow($result)) + { + $topic_info[$row['topic_id']]['post_text'] = $row['post_text']; + } + $db->sql_freeresult($result); - foreach ($post_info as $post_id => $post_data) - { - $username = ($post_data['post_username']) ? $post_data['post_username'] : $post_data['username']; + // Handle notifications + $phpbb_notifications = $phpbb_container->get('notification_manager'); - if ($post_id == $post_data['topic_first_post_id'] && $post_id == $post_data['topic_last_post_id']) - { - // Forum Notifications - user_notification('post', $post_data['topic_title'], $post_data['topic_title'], $post_data['forum_name'], $post_data['forum_id'], $post_data['topic_id'], $post_id, $username); + foreach ($topic_info as $topic_id => $topic_data) + { + $topic_data = array_merge($topic_data, array( + 'post_id' => $topic_data['topic_first_post_id'], + 'post_subject' => $topic_data['topic_title'], + 'post_time' => $topic_data['topic_time'], + 'poster_id' => $topic_data['topic_poster'], + 'post_username' => $topic_data['topic_first_poster_name'], + )); + + $phpbb_notifications->delete_notifications('notification.type.topic_in_queue', $topic_id); + + // Only add notifications, if we are not reapproving post + // When the topic was already approved, but was edited and + // now needs re-approval, we don't want to notify the users + // again. + if ($topic_data['topic_visibility'] == ITEM_UNAPPROVED) + { + $phpbb_notifications->add_notifications(array( + 'notification.type.quote', + 'notification.type.topic', + ), $topic_data); + } + + $phpbb_notifications->mark_notifications_read('notification.type.quote', $topic_data['post_id'], $user->data['user_id']); + $phpbb_notifications->mark_notifications_read('notification.type.topic', $topic_id, $user->data['user_id']); + + if ($notify_poster) + { + $phpbb_notifications->add_notifications('notification.type.approve_topic', $topic_data); + } + } } - else + + /** + * Perform additional actions during topics(s) approval + * + * @event core.approve_topics_after + * @var string action Variable containing the action we perform on the posts ('approve' or 'restore') + * @var mixed topic_info Array containing info for all topics being approved + * @var array first_post_ids Array containing ids of all first posts + * @var bool notify_poster Variable telling if the poster should be notified or not + * @var string success_msg Variable containing the language key for the success message + * @var string redirect Variable containing the redirect url + * @since 3.1.4-RC1 + */ + $vars = array( + 'action', + 'topic_info', + 'first_post_ids', + 'notify_poster', + 'success_msg', + 'redirect', + ); + extract($phpbb_dispatcher->trigger_event('core.approve_topics_after', compact($vars))); + + meta_refresh(3, $redirect); + $message = $user->lang[$success_msg]; + + if ($request->is_ajax()) { - // Topic Notifications - user_notification('reply', $post_data['post_subject'], $post_data['topic_title'], $post_data['forum_name'], $post_data['forum_id'], $post_data['topic_id'], $post_id, $username); + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $message, + 'REFRESH_DATA' => null, + 'visible' => true, + )); } - } - - if (sizeof($post_id_list) == 1) - { - $post_data = $post_info[$post_id_list[0]]; - $post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f={$post_data['forum_id']}&t={$post_data['topic_id']}&p={$post_data['post_id']}") . '#p' . $post_data['post_id']; - } - unset($post_info); + $message .= '<br /><br />' . $user->lang('RETURN_PAGE', '<a href="' . $redirect . '">', '</a>'); - if ($total_topics) - { - $success_msg = ($total_topics == 1) ? 'TOPIC_APPROVED_SUCCESS' : 'TOPICS_APPROVED_SUCCESS'; + // If approving one topic, also give links back to topic... + if (sizeof($topic_info) == 1 && $topic_url) + { + $message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $topic_url . '">', '</a>'); + } + trigger_error($message); } else { - $success_msg = (sizeof($post_id_list) + sizeof($post_approved_list) == 1) ? 'POST_APPROVED_SUCCESS' : 'POSTS_APPROVED_SUCCESS'; - } - } - else - { - $show_notify = false; + $show_notify = false; - if ($config['email_enable'] || $config['jab_enable']) - { - foreach ($post_info as $post_data) + if ($action == 'approve') { - if ($post_data['poster_id'] == ANONYMOUS) - { - continue; - } - else + foreach ($topic_info as $topic_data) { - $show_notify = true; - break; + if ($topic_data['topic_poster'] == ANONYMOUS) + { + continue; + } + else + { + $show_notify = true; + break; + } } } - } - - $template->assign_vars(array( - 'S_NOTIFY_POSTER' => $show_notify, - 'S_APPROVE' => true) - ); - confirm_box(false, 'APPROVE_POST' . ((sizeof($post_id_list) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_approve.html'); - } + $template->assign_vars(array( + 'S_NOTIFY_POSTER' => $show_notify, + 'S_' . strtoupper($action) => true, + )); - $redirect = request_var('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); + confirm_box(false, strtoupper($action) . '_TOPIC' . ((sizeof($topic_id_list) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_approve.html'); + } - if (!$success_msg) - { redirect($redirect); } - else + + /** + * Disapprove Post + * + * @param $post_id_list array IDs of the posts to disapprove/delete + * @param $id mixed Category of the current active module + * @param $mode string Active module + * @return null + */ + static public function disapprove_posts($post_id_list, $id, $mode) { - meta_refresh(3, $redirect); + global $db, $template, $user, $config, $phpbb_container, $phpbb_dispatcher; + global $phpEx, $phpbb_root_path, $request; - // If approving one post, also give links back to post... - $add_message = ''; - if (sizeof($post_id_list) == 1 && !empty($post_url)) + if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve'))) { - $add_message = '<br /><br />' . sprintf($user->lang['RETURN_POST'], '<a href="' . $post_url . '">', '</a>'); + trigger_error('NOT_AUTHORISED'); } - trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], "<a href=\"$redirect\">", '</a>') . $add_message); - } -} - -/** -* Disapprove Post/Topic -*/ -function disapprove_post($post_id_list, $id, $mode) -{ - global $db, $template, $user, $config; - global $phpEx, $phpbb_root_path; - - if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve'))) - { - trigger_error('NOT_AUTHORISED'); - } - - $redirect = request_var('redirect', build_url(array('t', 'mode', 'quickmod')) . "&mode=$mode"); - $reason = utf8_normalize_nfc(request_var('reason', '', true)); - $reason_id = request_var('reason_id', 0); - $success_msg = $additional_msg = ''; + $redirect = $request->variable('redirect', build_url(array('t', 'mode', 'quickmod')) . "&mode=$mode"); + $redirect = reapply_sid($redirect); + $reason = $request->variable('reason', '', true); + $reason_id = $request->variable('reason_id', 0); + $success_msg = $additional_msg = ''; - $s_hidden_fields = build_hidden_fields(array( - 'i' => $id, - 'mode' => $mode, - 'post_id_list' => $post_id_list, - 'action' => 'disapprove', - 'redirect' => $redirect) - ); + $s_hidden_fields = build_hidden_fields(array( + 'i' => $id, + 'mode' => $mode, + 'post_id_list' => $post_id_list, + 'action' => 'disapprove', + 'redirect' => $redirect, + )); - $notify_poster = (isset($_REQUEST['notify_poster'])) ? true : false; - $disapprove_reason = ''; + $notify_poster = $request->is_set('notify_poster'); + $disapprove_reason = ''; - if ($reason_id) - { - $sql = 'SELECT reason_title, reason_description - FROM ' . REPORTS_REASONS_TABLE . " - WHERE reason_id = $reason_id"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (!$row || (!$reason && strtolower($row['reason_title']) == 'other')) + if ($reason_id) { - $additional_msg = $user->lang['NO_REASON_DISAPPROVAL']; - unset($_REQUEST['confirm_key']); - unset($_POST['confirm_key']); - unset($_POST['confirm']); - } - else - { - // If the reason is defined within the language file, we will use the localized version, else just use the database entry... - $disapprove_reason = (strtolower($row['reason_title']) != 'other') ? ((isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])])) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])] : $row['reason_description']) : ''; - $disapprove_reason .= ($reason) ? "\n\n" . $reason : ''; - - if (isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])])) + $sql = 'SELECT reason_title, reason_description + FROM ' . REPORTS_REASONS_TABLE . " + WHERE reason_id = $reason_id"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$row || (!$reason && strtolower($row['reason_title']) == 'other')) { - $disapprove_reason_lang = strtoupper($row['reason_title']); + $additional_msg = $user->lang['NO_REASON_DISAPPROVAL']; + + $request->overwrite('confirm', null, \phpbb\request\request_interface::POST); + $request->overwrite('confirm_key', null, \phpbb\request\request_interface::POST); + $request->overwrite('confirm_key', null, \phpbb\request\request_interface::REQUEST); } + else + { + // If the reason is defined within the language file, we will use the localized version, else just use the database entry... + $disapprove_reason = (strtolower($row['reason_title']) != 'other') ? ((isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])])) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])] : $row['reason_description']) : ''; + $disapprove_reason .= ($reason) ? "\n\n" . $reason : ''; - $email_disapprove_reason = $disapprove_reason; + if (isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])])) + { + $disapprove_reason_lang = strtoupper($row['reason_title']); + } + } } - } - $post_info = get_post_data($post_id_list, 'm_approve'); + $post_info = phpbb_get_post_data($post_id_list, 'm_approve'); - if (confirm_box(true)) - { - $disapprove_log = $disapprove_log_topics = $disapprove_log_posts = array(); - $topic_replies_real = $post_disapprove_list = array(); - - // Build a list of posts to be unapproved and get the related topics real replies count + $is_disapproving = false; foreach ($post_info as $post_id => $post_data) { - $post_disapprove_list[$post_id] = $post_data['topic_id']; - if (!isset($topic_replies_real[$post_data['topic_id']])) + if ($post_data['post_visibility'] == ITEM_DELETED) { - $topic_replies_real[$post_data['topic_id']] = $post_data['topic_replies_real']; + continue; } + + $is_disapproving = true; } - // Now we build the log array - foreach ($post_disapprove_list as $post_id => $topic_id) + if (confirm_box(true)) { - // If the count of disapproved posts for the topic is greater - // than topic's real replies count, the whole topic is disapproved/deleted - if (sizeof(array_keys($post_disapprove_list, $topic_id)) > $topic_replies_real[$topic_id]) + $disapprove_log = $disapprove_log_topics = $disapprove_log_posts = array(); + $topic_posts_unapproved = $post_disapprove_list = $topic_information = array(); + + // Build a list of posts to be disapproved and get the related topics real replies count + foreach ($post_info as $post_id => $post_data) { - // Don't write the log more than once for every topic - if (!isset($disapprove_log_topics[$topic_id])) + $post_disapprove_list[$post_id] = $post_data['topic_id']; + if (!isset($topic_posts_unapproved[$post_data['topic_id']])) { - // Build disapproved topics log - $disapprove_log_topics[$topic_id] = array( - 'type' => 'topic', - 'post_subject' => $post_info[$post_id]['topic_title'], - 'forum_id' => $post_info[$post_id]['forum_id'], - 'topic_id' => 0, // useless to log a topic id, as it will be deleted - ); + $topic_information[$post_data['topic_id']] = $post_data; + $topic_posts_unapproved[$post_data['topic_id']] = 0; } + $topic_posts_unapproved[$post_data['topic_id']]++; } - else + + // Now we build the log array + foreach ($post_disapprove_list as $post_id => $topic_id) { - // Build disapproved posts log - $disapprove_log_posts[] = array( - 'type' => 'post', - 'post_subject' => $post_info[$post_id]['post_subject'], - 'forum_id' => $post_info[$post_id]['forum_id'], - 'topic_id' => $post_info[$post_id]['topic_id'], - ); + // If the count of disapproved posts for the topic is equal + // to the number of unapproved posts in the topic, and there are no different + // posts, we disapprove the hole topic + if ($topic_information[$topic_id]['topic_posts_approved'] == 0 && + $topic_information[$topic_id]['topic_posts_softdeleted'] == 0 && + $topic_information[$topic_id]['topic_posts_unapproved'] == $topic_posts_unapproved[$topic_id]) + { + // Don't write the log more than once for every topic + if (!isset($disapprove_log_topics[$topic_id])) + { + // Build disapproved topics log + $disapprove_log_topics[$topic_id] = array( + 'type' => 'topic', + 'post_subject' => $post_info[$post_id]['topic_title'], + 'forum_id' => $post_info[$post_id]['forum_id'], + 'topic_id' => 0, // useless to log a topic id, as it will be deleted + 'post_username' => ($post_info[$post_id]['poster_id'] == ANONYMOUS && !empty($post_info[$post_id]['post_username'])) ? $post_info[$post_id]['post_username'] : $post_info[$post_id]['username'], + ); + } + } + else + { + // Build disapproved posts log + $disapprove_log_posts[] = array( + 'type' => 'post', + 'post_subject' => $post_info[$post_id]['post_subject'], + 'forum_id' => $post_info[$post_id]['forum_id'], + 'topic_id' => $post_info[$post_id]['topic_id'], + 'post_username' => ($post_info[$post_id]['poster_id'] == ANONYMOUS && !empty($post_info[$post_id]['post_username'])) ? $post_info[$post_id]['post_username'] : $post_info[$post_id]['username'], + ); + } } - } - // Get disapproved posts/topics counts separately - $num_disapproved_topics = sizeof($disapprove_log_topics); - $num_disapproved_posts = sizeof($disapprove_log_posts); + // Get disapproved posts/topics counts separately + $num_disapproved_topics = sizeof($disapprove_log_topics); + $num_disapproved_posts = sizeof($disapprove_log_posts); - // Build the whole log - $disapprove_log = array_merge($disapprove_log_topics, $disapprove_log_posts); + // Build the whole log + $disapprove_log = array_merge($disapprove_log_topics, $disapprove_log_posts); - // Unset unneeded arrays - unset($post_data, $disapprove_log_topics, $disapprove_log_posts); + // Unset unneeded arrays + unset($post_data, $disapprove_log_topics, $disapprove_log_posts); - // Let's do the job - delete disapproved posts - if (sizeof($post_disapprove_list)) - { - if (!function_exists('delete_posts')) + // Let's do the job - delete disapproved posts + if (sizeof($post_disapprove_list)) { - include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); - } + if (!function_exists('delete_posts')) + { + include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); + } - // We do not check for permissions here, because the moderator allowed approval/disapproval should be allowed to delete the disapproved posts - // Note: function delete_posts triggers related forums/topics sync, - // so we don't need to call update_post_information later and to adjust real topic replies or forum topics count manually - delete_posts('post_id', array_keys($post_disapprove_list)); + // We do not check for permissions here, because the moderator allowed approval/disapproval should be allowed to delete the disapproved posts + // Note: function delete_posts triggers related forums/topics sync, + // so we don't need to call update_post_information later and to adjust real topic replies or forum topics count manually + delete_posts('post_id', array_keys($post_disapprove_list)); - foreach ($disapprove_log as $log_data) - { - add_log('mod', $log_data['forum_id'], $log_data['topic_id'], ($log_data['type'] == 'topic') ? 'LOG_TOPIC_DISAPPROVED' : 'LOG_POST_DISAPPROVED', $log_data['post_subject'], $disapprove_reason); + foreach ($disapprove_log as $log_data) + { + if ($is_disapproving) + { + $l_log_message = ($log_data['type'] == 'topic') ? 'LOG_TOPIC_DISAPPROVED' : 'LOG_POST_DISAPPROVED'; + add_log('mod', $log_data['forum_id'], $log_data['topic_id'], $l_log_message, $log_data['post_subject'], $disapprove_reason, $log_data['post_username']); + } + else + { + $l_log_message = ($log_data['type'] == 'topic') ? 'LOG_DELETE_TOPIC' : 'LOG_DELETE_POST'; + add_log('mod', $log_data['forum_id'], $log_data['topic_id'], $l_log_message, $log_data['post_subject'], $log_data['post_username']); + } + } } - } - $messenger = new messenger(); + $phpbb_notifications = $phpbb_container->get('notification_manager'); - // Notify Poster? - if ($notify_poster) - { $lang_reasons = array(); foreach ($post_info as $post_id => $post_data) { - if ($post_data['poster_id'] == ANONYMOUS) + $disapprove_all_posts_in_topic = $topic_information[$topic_id]['topic_posts_approved'] == 0 && + $topic_information[$topic_id]['topic_posts_softdeleted'] == 0 && + $topic_information[$topic_id]['topic_posts_unapproved'] == $topic_posts_unapproved[$topic_id]; + + $phpbb_notifications->delete_notifications('notification.type.post_in_queue', $post_id); + + // Do we disapprove the whole topic? Remove potential notifications + if ($disapprove_all_posts_in_topic) { - continue; + $phpbb_notifications->delete_notifications('notification.type.topic_in_queue', $post_data['topic_id']); } - if (isset($disapprove_reason_lang)) + // Notify Poster? + if ($notify_poster) { - // Okay we need to get the reason from the posters language - if (!isset($lang_reasons[$post_data['user_lang']])) + if ($post_data['poster_id'] == ANONYMOUS) { - // Assign the current users translation as the default, this is not ideal but getting the board default adds another layer of complexity. - $lang_reasons[$post_data['user_lang']] = $user->lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang]; + continue; + } - // Only load up the language pack if the language is different to the current one - if ($post_data['user_lang'] != $user->lang_name && file_exists($phpbb_root_path . '/language/' . $post_data['user_lang'] . '/mcp.' . $phpEx)) + $post_data['disapprove_reason'] = ''; + if (isset($disapprove_reason_lang)) + { + // Okay we need to get the reason from the posters language + if (!isset($lang_reasons[$post_data['user_lang']])) { - // Load up the language pack - $lang = array(); - @include($phpbb_root_path . '/language/' . basename($post_data['user_lang']) . '/mcp.' . $phpEx); + // Assign the current users translation as the default, this is not ideal but getting the board default adds another layer of complexity. + $lang_reasons[$post_data['user_lang']] = $user->lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang]; - // If we find the reason in this language pack use it - if (isset($lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang])) + // Only load up the language pack if the language is different to the current one + if ($post_data['user_lang'] != $user->lang_name && file_exists($phpbb_root_path . '/language/' . $post_data['user_lang'] . '/mcp.' . $phpEx)) { - $lang_reasons[$post_data['user_lang']] = $lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang]; - } + // Load up the language pack + $lang = array(); + @include($phpbb_root_path . '/language/' . basename($post_data['user_lang']) . '/mcp.' . $phpEx); - unset($lang); // Free memory + // If we find the reason in this language pack use it + if (isset($lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang])) + { + $lang_reasons[$post_data['user_lang']] = $lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang]; + } + + unset($lang); // Free memory + } } + + $post_data['disapprove_reason'] = $lang_reasons[$post_data['user_lang']]; + $post_data['disapprove_reason'] .= ($reason) ? "\n\n" . $reason : ''; } - $email_disapprove_reason = $lang_reasons[$post_data['user_lang']]; - $email_disapprove_reason .= ($reason) ? "\n\n" . $reason : ''; + if ($disapprove_all_posts_in_topic && $topic_information[$topic_id]['topic_posts_unapproved'] == 1) + { + // If there is only 1 post when disapproving the topic, + // we send the user a "disapprove topic" notification... + $phpbb_notifications->add_notifications('notification.type.disapprove_topic', $post_data); + } + else + { + // ... otherwise there are multiple unapproved posts and + // all of them are disapproved as posts. + $phpbb_notifications->add_notifications('notification.type.disapprove_post', $post_data); + } } + } - $email_template = ($post_data['post_id'] == $post_data['topic_first_post_id'] && $post_data['post_id'] == $post_data['topic_last_post_id']) ? 'topic_disapproved' : 'post_disapproved'; - - $messenger->template($email_template, $post_data['user_lang']); - - $messenger->to($post_data['user_email'], $post_data['username']); - $messenger->im($post_data['user_jabber'], $post_data['username']); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($post_data['username']), - 'REASON' => htmlspecialchars_decode($email_disapprove_reason), - 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_data['post_subject'])), - 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_data['topic_title']))) - ); - - $messenger->send($post_data['user_notify_type']); + if ($num_disapproved_topics) + { + $success_msg = ($num_disapproved_topics == 1) ? 'TOPIC' : 'TOPICS'; + } + else + { + $success_msg = ($num_disapproved_posts == 1) ? 'POST' : 'POSTS'; } - unset($lang_reasons); - } - unset($post_info, $disapprove_reason, $email_disapprove_reason, $disapprove_reason_lang); + if ($is_disapproving) + { + $success_msg .= '_DISAPPROVED_SUCCESS'; + } + else + { + $success_msg .= '_DELETED_SUCCESS'; + } - $messenger->save_queue(); + // If we came from viewtopic, we try to go back to it. + if (strpos($redirect, $phpbb_root_path . 'viewtopic.' . $phpEx) === 0) + { + if ($num_disapproved_topics == 0) + { + // So we need to remove the post id part from the Url + $redirect = str_replace("&p={$post_id_list[0]}#p{$post_id_list[0]}", '', $redirect); + } + else + { + // However this is only possible if the topic still exists, + // Otherwise we go back to the viewforum page + $redirect = append_sid($phpbb_root_path . 'viewforum.' . $phpEx, 'f=' . $request->variable('f', 0)); + } + } - if ($num_disapproved_topics) - { - $success_msg = ($num_disapproved_topics == 1) ? 'TOPIC_DISAPPROVED_SUCCESS' : 'TOPICS_DISAPPROVED_SUCCESS'; + /** + * Perform additional actions during post(s) disapproval + * + * @event core.disapprove_posts_after + * @var array post_info Array containing info for all posts being disapproved + * @var array topic_information Array containing information for the topics + * @var array topic_posts_unapproved Array containing list of topic ids and the count of disapproved posts in them + * @var array post_disapprove_list Array containing list of posts and their topic id + * @var int num_disapproved_topics Variable containing the number of disapproved topics + * @var int num_disapproved_posts Variable containing the number of disapproved posts + * @var array lang_reasons Array containing the language keys for reasons + * @var string disapprove_reason Variable containing the language key for the success message + * @var string disapprove_reason_lang Variable containing the language key for the success message + * @var bool is_disapproving Variable telling if anything is going to be disapproved + * @var bool notify_poster Variable telling if the post should be notified or not + * @var string success_msg Variable containing the language key for the success message + * @var string redirect Variable containing the redirect url + * @since 3.1.4-RC1 + */ + $vars = array( + 'post_info', + 'topic_information', + 'topic_posts_unapproved', + 'post_disapprove_list', + 'num_disapproved_topics', + 'num_disapproved_posts', + 'lang_reasons', + 'disapprove_reason', + 'disapprove_reason_lang', + 'is_disapproving', + 'notify_poster', + 'success_msg', + 'redirect', + ); + extract($phpbb_dispatcher->trigger_event('core.disapprove_posts_after', compact($vars))); + + unset($lang_reasons, $post_info, $disapprove_reason, $disapprove_reason_lang); + + meta_refresh(3, $redirect); + $message = $user->lang[$success_msg]; + + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $message, + 'REFRESH_DATA' => null, + 'visible' => false, + )); + } + $message .= '<br /><br />' . $user->lang('RETURN_PAGE', '<a href="' . $redirect . '">', '</a>'); + trigger_error($message); } else { - $success_msg = ($num_disapproved_posts == 1) ? 'POST_DISAPPROVED_SUCCESS' : 'POSTS_DISAPPROVED_SUCCESS'; - } - } - else - { - include_once($phpbb_root_path . 'includes/functions_display.' . $phpEx); + if (!function_exists('display_reasons')) + { + include($phpbb_root_path . 'includes/functions_display.' . $phpEx); + } - display_reasons($reason_id); + $show_notify = false; - $show_notify = false; + foreach ($post_info as $post_data) + { + if ($post_data['poster_id'] == ANONYMOUS) + { + continue; + } + else + { + $show_notify = true; + break; + } + } - foreach ($post_info as $post_data) - { - if ($post_data['poster_id'] == ANONYMOUS) + $l_confirm_msg = 'DISAPPROVE_POST'; + $confirm_template = 'mcp_approve.html'; + if ($is_disapproving) { - continue; + display_reasons($reason_id); } else { - $show_notify = true; - break; - } - } + $user->add_lang('posting'); - $template->assign_vars(array( - 'S_NOTIFY_POSTER' => $show_notify, - 'S_APPROVE' => false, - 'REASON' => $reason, - 'ADDITIONAL_MSG' => $additional_msg) - ); + $l_confirm_msg = 'DELETE_POST_PERMANENTLY'; + $confirm_template = 'confirm_delete_body.html'; + } + $l_confirm_msg .= ((sizeof($post_id_list) == 1) ? '' : 'S'); - confirm_box(false, 'DISAPPROVE_POST' . ((sizeof($post_id_list) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_approve.html'); - } + $template->assign_vars(array( + 'S_NOTIFY_POSTER' => $show_notify, + 'S_APPROVE' => false, + 'REASON' => ($is_disapproving) ? $reason : '', + 'ADDITIONAL_MSG' => $additional_msg, + )); - $redirect = request_var('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); + confirm_box(false, $l_confirm_msg, $s_hidden_fields, $confirm_template); + } - if (!$success_msg) - { redirect($redirect); } - else - { - meta_refresh(3, $redirect); - trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], "<a href=\"$redirect\">", '</a>')); - } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_reports.php b/phpBB/includes/mcp/mcp_reports.php index b13c8b20c6..804d48ea97 100644 --- a/phpBB/includes/mcp/mcp_reports.php +++ b/phpBB/includes/mcp/mcp_reports.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * mcp_reports * Handling the reports queue -* @package mcp */ class mcp_reports { @@ -34,7 +36,7 @@ class mcp_reports function main($id, $mode) { global $auth, $db, $user, $template, $cache; - global $config, $phpbb_root_path, $phpEx, $action; + global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container, $phpbb_dispatcher; include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); @@ -72,7 +74,7 @@ class mcp_reports // closed reports are accessed by report id $report_id = request_var('r', 0); - $sql = 'SELECT r.post_id, r.user_id, r.report_id, r.report_closed, report_time, r.report_text, rr.reason_title, rr.reason_description, u.username, u.username_clean, u.user_colour + $sql = 'SELECT r.post_id, r.user_id, r.report_id, r.report_closed, report_time, r.report_text, r.reported_post_text, r.reported_post_uid, r.reported_post_bitfield, r.reported_post_enable_magic_url, r.reported_post_enable_smilies, r.reported_post_enable_bbcode, rr.reason_title, rr.reason_description, u.username, u.username_clean, u.user_colour FROM ' . REPORTS_TABLE . ' r, ' . REPORTS_REASONS_TABLE . ' rr, ' . USERS_TABLE . ' u WHERE ' . (($report_id) ? 'r.report_id = ' . $report_id : "r.post_id = $post_id") . ' AND rr.reason_id = r.reason_id @@ -88,6 +90,10 @@ class mcp_reports trigger_error('NO_REPORT'); } + $phpbb_notifications = $phpbb_container->get('notification_manager'); + + $phpbb_notifications->mark_notifications_read('notification.type.report_post', $post_id, $user->data['user_id']); + if (!$report_id && $report['report_closed']) { trigger_error('REPORT_CLOSED'); @@ -96,7 +102,11 @@ class mcp_reports $post_id = $report['post_id']; $report_id = $report['report_id']; - $post_info = get_post_data(array($post_id), 'm_report', true); + $parse_post_flags = $report['reported_post_enable_bbcode'] ? OPTION_FLAG_BBCODE : 0; + $parse_post_flags += $report['reported_post_enable_smilies'] ? OPTION_FLAG_SMILIES : 0; + $parse_post_flags += $report['reported_post_enable_magic_url'] ? OPTION_FLAG_LINKS : 0; + + $post_info = phpbb_get_post_data(array($post_id), 'm_report', true); if (!sizeof($post_info)) { @@ -117,8 +127,9 @@ class mcp_reports $template->assign_vars(array( 'S_TOPIC_REVIEW' => true, 'S_BBCODE_ALLOWED' => $post_info['enable_bbcode'], - 'TOPIC_TITLE' => $post_info['topic_title']) - ); + 'TOPIC_TITLE' => $post_info['topic_title'], + 'REPORTED_POST_ID' => $post_id, + )); } $topic_tracking_info = $extensions = $attachments = array(); @@ -135,19 +146,14 @@ class mcp_reports } $post_unread = (isset($topic_tracking_info[$post_info['topic_id']]) && $post_info['post_time'] > $topic_tracking_info[$post_info['topic_id']]) ? true : false; + $message = generate_text_for_display( + $report['reported_post_text'], + $report['reported_post_uid'], + $report['reported_post_bitfield'], + $parse_post_flags, + false + ); - // Process message, leave it uncensored - $message = $post_info['post_text']; - - if ($post_info['bbcode_bitfield']) - { - include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode($post_info['bbcode_bitfield']); - $bbcode->bbcode_second_pass($message, $post_info['bbcode_uid'], $post_info['bbcode_bitfield']); - } - - $message = bbcode_nl2br($message); - $message = smiley_text($message); $report['report_text'] = make_clickable(bbcode_nl2br($report['report_text'])); if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id'])) @@ -156,6 +162,7 @@ class mcp_reports FROM ' . ATTACHMENTS_TABLE . ' WHERE post_msg_id = ' . $post_id . ' AND in_message = 0 + AND filetime <= ' . (int) $report['report_time'] . ' ORDER BY filetime DESC'; $result = $db->sql_query($sql); @@ -190,7 +197,7 @@ class mcp_reports 'S_CLOSE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=report_details&f=' . $post_info['forum_id'] . '&p=' . $post_id), 'S_CAN_VIEWIP' => $auth->acl_get('m_info', $post_info['forum_id']), 'S_POST_REPORTED' => $post_info['post_reported'], - 'S_POST_UNAPPROVED' => !$post_info['post_approved'], + 'S_POST_UNAPPROVED' => $post_info['post_visibility'] == ITEM_UNAPPROVED || $post_info['post_visibility'] == ITEM_REAPPROVE, 'S_POST_LOCKED' => $post_info['post_edit_locked'], 'S_REPORT_CLOSED' => $report['report_closed'], 'S_USER_NOTES' => true, @@ -262,7 +269,7 @@ class mcp_reports if ($topic_id) { - $topic_info = get_topic_data(array($topic_id)); + $topic_info = phpbb_get_topic_data(array($topic_id)); if (!sizeof($topic_info)) { @@ -296,16 +303,16 @@ class mcp_reports $global_id = $forum_list[0]; - $sql = 'SELECT SUM(forum_topics) as sum_forum_topics + $sql = 'SELECT SUM(forum_topics_approved) as sum_forum_topics FROM ' . FORUMS_TABLE . ' WHERE ' . $db->sql_in_set('forum_id', $forum_list); $result = $db->sql_query($sql); - $forum_info['forum_topics'] = (int) $db->sql_fetchfield('sum_forum_topics'); + $forum_info['forum_topics_approved'] = (int) $db->sql_fetchfield('sum_forum_topics'); $db->sql_freeresult($result); } else { - $forum_info = get_forum_data(array($forum_id), 'm_report'); + $forum_info = phpbb_get_forum_data(array($forum_id), 'm_report'); if (!sizeof($forum_info)) { @@ -314,11 +321,11 @@ class mcp_reports $forum_info = $forum_info[$forum_id]; $forum_list = array($forum_id); - $global_id = $forum_id; } $forum_list[] = 0; $forum_data = array(); + $pagination = $phpbb_container->get('pagination'); $forum_options = '<option value="0"' . (($forum_id == 0) ? ' selected="selected"' : '') . '>' . $user->lang['ALL_FORUMS'] . '</option>'; foreach ($forum_list_reports as $row) @@ -331,9 +338,9 @@ class mcp_reports $sort_days = $total = 0; $sort_key = $sort_dir = ''; $sort_by_sql = $sort_order_sql = array(); - mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id); + phpbb_mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id); - $forum_topics = ($total == -1) ? $forum_info['forum_topics'] : $total; + $forum_topics = ($total == -1) ? $forum_info['forum_topics_approved'] : $total; $limit_time_sql = ($sort_days) ? 'AND r.report_time >= ' . (time() - ($sort_days * 86400)) : ''; if ($mode == 'reports') @@ -357,6 +364,27 @@ class mcp_reports AND r.pm_id = 0 $limit_time_sql ORDER BY $sort_order_sql"; + + /** + * Alter sql query to get report id of all reports for requested forum and topic or just forum + * + * @event core.mcp_reports_get_reports_query_before + * @var string sql String with the query to be executed + * @var array forum_list List of forums that contain the posts + * @var int topic_id topic_id in the page request + * @var string limit_time_sql String with the SQL code to limit the time interval of the post (Note: May be empty string) + * @var string sort_order_sql String with the ORDER BY SQL code used in this query + * @since 3.1.0-RC4 + */ + $vars = array( + 'sql', + 'forum_list', + 'topic_id', + 'limit_time_sql', + 'sort_order_sql', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_reports_get_reports_query_before', compact($vars))); + $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); $i = 0; @@ -370,7 +398,7 @@ class mcp_reports if (sizeof($report_ids)) { - $sql = 'SELECT t.forum_id, t.topic_id, t.topic_title, p.post_id, p.post_subject, p.post_username, p.poster_id, p.post_time, u.username, u.username_clean, u.user_colour, r.user_id as reporter_id, ru.username as reporter_name, ru.user_colour as reporter_colour, r.report_time, r.report_id + $sql = 'SELECT t.forum_id, t.topic_id, t.topic_title, p.post_id, p.post_subject, p.post_username, p.poster_id, p.post_time, p.post_attachment, u.username, u.username_clean, u.user_colour, r.user_id as reporter_id, ru.username as reporter_name, ru.user_colour as reporter_colour, r.report_time, r.report_id FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . USERS_TABLE . ' u, ' . USERS_TABLE . ' ru WHERE ' . $db->sql_in_set('r.report_id', $report_ids) . ' AND t.topic_id = p.topic_id @@ -384,14 +412,8 @@ class mcp_reports $report_data = $rowset = array(); while ($row = $db->sql_fetchrow($result)) { - $global_topic = ($row['forum_id']) ? false : true; - if ($global_topic) - { - $row['forum_id'] = $global_id; - } - $template->assign_block_vars('postrow', array( - 'U_VIEWFORUM' => (!$global_topic) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : '', + 'U_VIEWFORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']), 'U_VIEWPOST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id'] . '&p=' . $row['post_id']) . '#p' . $row['post_id'], 'U_VIEW_DETAILS' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=reports&start=$start&mode=report_details&f={$row['forum_id']}&r={$row['report_id']}"), @@ -405,19 +427,23 @@ class mcp_reports 'REPORTER' => get_username_string('username', $row['reporter_id'], $row['reporter_name'], $row['reporter_colour']), 'U_REPORTER' => get_username_string('profile', $row['reporter_id'], $row['reporter_name'], $row['reporter_colour']), - 'FORUM_NAME' => (!$global_topic) ? $forum_data[$row['forum_id']]['forum_name'] : $user->lang['GLOBAL_ANNOUNCEMENT'], + 'FORUM_NAME' => $forum_data[$row['forum_id']]['forum_name'], 'POST_ID' => $row['post_id'], 'POST_SUBJECT' => ($row['post_subject']) ? $row['post_subject'] : $user->lang['NO_SUBJECT'], 'POST_TIME' => $user->format_date($row['post_time']), 'REPORT_ID' => $row['report_id'], 'REPORT_TIME' => $user->format_date($row['report_time']), - 'TOPIC_TITLE' => $row['topic_title']) - ); + 'TOPIC_TITLE' => $row['topic_title'], + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['post_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', + )); } $db->sql_freeresult($result); unset($report_ids, $row); } + $base_url = $this->u_action . "&f=$forum_id&t=$topic_id&st=$sort_days&sk=$sort_key&sd=$sort_dir"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total, $config['topics_per_page'], $start); + // Now display the page $template->assign_vars(array( 'L_EXPLAIN' => ($mode == 'reports') ? $user->lang['MCP_REPORTS_OPEN_EXPLAIN'] : $user->lang['MCP_REPORTS_CLOSED_EXPLAIN'], @@ -428,11 +454,9 @@ class mcp_reports 'S_FORUM_OPTIONS' => $forum_options, 'S_CLOSED' => ($mode == 'reports_closed') ? true : false, - 'PAGINATION' => generate_pagination($this->u_action . "&f=$forum_id&t=$topic_id&st=$sort_days&sk=$sort_key&sd=$sort_dir", $total, $config['topics_per_page'], $start), - 'PAGE_NUMBER' => on_page($total, $config['topics_per_page'], $start), 'TOPIC_ID' => $topic_id, 'TOTAL' => $total, - 'TOTAL_REPORTS' => ($total == 1) ? $user->lang['LIST_REPORT'] : sprintf($user->lang['LIST_REPORTS'], $total), + 'TOTAL_REPORTS' => $user->lang('LIST_REPORTS', (int) $total), ) ); @@ -448,7 +472,7 @@ class mcp_reports function close_report($report_id_list, $mode, $action, $pm = false) { global $db, $template, $user, $config, $auth; - global $phpEx, $phpbb_root_path; + global $phpEx, $phpbb_root_path, $phpbb_container; $pm_where = ($pm) ? ' AND r.post_id = 0 ' : ' AND r.pm_id = 0 '; $id_column = ($pm) ? 'pm_id' : 'post_id'; @@ -476,7 +500,7 @@ function close_report($report_id_list, $mode, $action, $pm = false) } else { - if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_report'))) + if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_report'))) { trigger_error('NOT_AUTHORISED'); } @@ -486,7 +510,7 @@ function close_report($report_id_list, $mode, $action, $pm = false) { $redirect = request_var('redirect', build_url(array('mode', 'r', 'quickmod')) . '&mode=reports'); } - elseif ($action == 'delete' && strpos($user->data['session_page'], 'mode=pm_report_details') !== false) + else if ($action == 'delete' && strpos($user->data['session_page'], 'mode=pm_report_details') !== false) { $redirect = request_var('redirect', build_url(array('mode', 'r', 'quickmod')) . '&mode=pm_reports'); } @@ -512,7 +536,7 @@ function close_report($report_id_list, $mode, $action, $pm = false) if (confirm_box(true)) { - $post_info = ($pm) ? get_pm_data($post_id_list) : get_post_data($post_id_list, 'm_report'); + $post_info = ($pm) ? phpbb_get_pm_data($post_id_list) : phpbb_get_post_data($post_id_list, 'm_report'); $sql = "SELECT r.report_id, r.$id_column, r.report_closed, r.user_id, r.user_notify, u.username, u.username_clean, u.user_email, u.user_jabber, u.user_lang, u.user_notify_type FROM " . REPORTS_TABLE . ' r, ' . USERS_TABLE . ' u @@ -585,7 +609,6 @@ function close_report($report_id_list, $mode, $action, $pm = false) } $db->sql_query($sql); - if (sizeof($close_report_posts)) { if ($pm) @@ -622,20 +645,22 @@ function close_report($report_id_list, $mode, $action, $pm = false) } unset($close_report_posts, $close_report_topics); + $phpbb_notifications = $phpbb_container->get('notification_manager'); + foreach ($reports as $report) { if ($pm) { add_log('mod', 0, 0, 'LOG_PM_REPORT_' . strtoupper($action) . 'D', $post_info[$report['pm_id']]['message_subject']); + $phpbb_notifications->delete_notifications('notification.type.report_pm', $report['pm_id']); } else { add_log('mod', $post_info[$report['post_id']]['forum_id'], $post_info[$report['post_id']]['topic_id'], 'LOG_REPORT_' . strtoupper($action) . 'D', $post_info[$report['post_id']]['post_subject']); + $phpbb_notifications->delete_notifications('notification.type.report_post', $report['post_id']); } } - $messenger = new messenger(); - // Notify reporters if (sizeof($notify_reporters)) { @@ -648,30 +673,21 @@ function close_report($report_id_list, $mode, $action, $pm = false) $post_id = $reporter[$id_column]; - $messenger->template((($pm) ? 'pm_report_' : 'report_') . $action . 'd', $reporter['user_lang']); - - $messenger->to($reporter['user_email'], $reporter['username']); - $messenger->im($reporter['user_jabber'], $reporter['username']); - if ($pm) { - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($reporter['username']), - 'CLOSER_NAME' => htmlspecialchars_decode($user->data['username']), - 'PM_SUBJECT' => htmlspecialchars_decode(censor_text($post_info[$post_id]['message_subject'])), - )); + $phpbb_notifications->add_notifications('notification.type.report_pm_closed', array_merge($post_info[$post_id], array( + 'reporter' => $reporter['user_id'], + 'closer_id' => $user->data['user_id'], + 'from_user_id' => $post_info[$post_id]['author_id'], + ))); } else { - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($reporter['username']), - 'CLOSER_NAME' => htmlspecialchars_decode($user->data['username']), - 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_info[$post_id]['post_subject'])), - 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_info[$post_id]['topic_title']))) - ); + $phpbb_notifications->add_notifications('notification.type.report_post_closed', array_merge($post_info[$post_id], array( + 'reporter' => $reporter['user_id'], + 'closer_id' => $user->data['user_id'], + ))); } - - $messenger->send($reporter['user_notify_type']); } } @@ -686,8 +702,6 @@ function close_report($report_id_list, $mode, $action, $pm = false) unset($notify_reporters, $post_info, $reports); - $messenger->save_queue(); - $success_msg = (sizeof($report_id_list) == 1) ? "{$pm_prefix}REPORT_" . strtoupper($action) . 'D_SUCCESS' : "{$pm_prefix}REPORTS_" . strtoupper($action) . 'D_SUCCESS'; } else @@ -725,5 +739,3 @@ function close_report($report_id_list, $mode, $action, $pm = false) trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_forum . $return_topic . sprintf($user->lang['RETURN_PAGE'], "<a href=\"$redirect\">", '</a>')); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 8e0e89e3da..8347830d0f 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -22,14 +25,15 @@ if (!defined('IN_PHPBB')) function mcp_topic_view($id, $mode, $action) { global $phpEx, $phpbb_root_path, $config; - global $template, $db, $user, $auth, $cache; + global $template, $db, $user, $auth, $cache, $phpbb_container, $phpbb_dispatcher; - $url = append_sid("{$phpbb_root_path}mcp.$phpEx?" . extra_url()); + $url = append_sid("{$phpbb_root_path}mcp.$phpEx?" . phpbb_extra_url()); $user->add_lang('viewtopic'); + $pagination = $phpbb_container->get('pagination'); $topic_id = request_var('t', 0); - $topic_info = get_topic_data(array($topic_id), false, true); + $topic_info = phpbb_get_topic_data(array($topic_id), false, true); if (!sizeof($topic_info)) { @@ -85,8 +89,8 @@ function mcp_topic_view($id, $mode, $action) $subject = $topic_info['topic_title']; } - // Approve posts? - if ($action == 'approve' && $auth->acl_get('m_approve', $topic_info['forum_id'])) + // Restore or pprove posts? + if (($action == 'restore' || $action == 'approve') && $auth->acl_get('m_approve', $topic_info['forum_id'])) { include($phpbb_root_path . 'includes/mcp/mcp_queue.' . $phpEx); include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); @@ -99,7 +103,7 @@ function mcp_topic_view($id, $mode, $action) if (!$sort) { - approve_post($post_id_list, $id, $mode); + mcp_queue::approve_posts($action, $post_id_list, $id, $mode); } } @@ -110,20 +114,14 @@ function mcp_topic_view($id, $mode, $action) $sort_days = $total = 0; $sort_key = $sort_dir = ''; $sort_by_sql = $sort_order_sql = array(); - mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $topic_info['forum_id'], $topic_id, $where_sql); + phpbb_mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $topic_info['forum_id'], $topic_id, $where_sql); $limit_time_sql = ($sort_days) ? 'AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); if ($total == -1) { - if ($auth->acl_get('m_approve', $topic_info['forum_id'])) - { - $total = $topic_info['topic_replies_real'] + 1; - } - else - { - $total = $topic_info['topic_replies'] + 1; - } + $total = $phpbb_content_visibility->get_count('topic_posts', $topic_info, $topic_info['forum_id']); } $posts_per_page = max(0, request_var('posts_per_page', intval($config['posts_per_page']))); @@ -136,39 +134,26 @@ function mcp_topic_view($id, $mode, $action) { $start = 0; } - - // Make sure $start is set to the last page if it exceeds the amount - if ($start < 0 || $start >= $total) - { - $start = ($start < 0) ? 0 : floor(($total - 1) / $posts_per_page) * $posts_per_page; - } + $start = $pagination->validate_start($start, $posts_per_page, $total); $sql = 'SELECT u.username, u.username_clean, u.user_colour, p.* FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u WHERE ' . (($action == 'reports') ? 'p.post_reported = 1 AND ' : '') . ' - p.topic_id = ' . $topic_id . ' ' . - ((!$auth->acl_get('m_approve', $topic_info['forum_id'])) ? ' AND p.post_approved = 1 ' : '') . ' + p.topic_id = ' . $topic_id . ' + AND ' . $phpbb_content_visibility->get_visibility_sql('post', $topic_info['forum_id'], 'p.') . ' AND p.poster_id = u.user_id ' . $limit_time_sql . ' ORDER BY ' . $sort_order_sql; $result = $db->sql_query_limit($sql, $posts_per_page, $start); $rowset = $post_id_list = array(); - $bbcode_bitfield = ''; while ($row = $db->sql_fetchrow($result)) { $rowset[] = $row; $post_id_list[] = $row['post_id']; - $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']); } $db->sql_freeresult($result); - if ($bbcode_bitfield !== '') - { - include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode(base64_encode($bbcode_bitfield)); - } - $topic_tracking_info = array(); // Get topic tracking info @@ -183,7 +168,7 @@ function mcp_topic_view($id, $mode, $action) $topic_tracking_info = get_complete_topic_tracking($topic_info['forum_id'], $topic_id); } - $has_unapproved_posts = false; + $has_unapproved_posts = $has_deleted_posts = false; // Grab extensions $extensions = $attachments = array(); @@ -214,13 +199,8 @@ function mcp_topic_view($id, $mode, $action) $message = $row['post_text']; $post_subject = ($row['post_subject'] != '') ? $row['post_subject'] : $topic_info['topic_title']; - if ($row['bbcode_bitfield']) - { - $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']); - } - - $message = bbcode_nl2br($message); - $message = smiley_text($message); + $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; + $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false); if (!empty($attachments[$row['post_id']])) { @@ -228,14 +208,19 @@ function mcp_topic_view($id, $mode, $action) parse_attachments($topic_info['forum_id'], $message, $attachments[$row['post_id']], $update_count); } - if (!$row['post_approved']) + if ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) { $has_unapproved_posts = true; } + if ($row['post_visibility'] == ITEM_DELETED) + { + $has_deleted_posts = true; + } + $post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false; - $template->assign_block_vars('postrow', array( + $post_row = array( 'POST_AUTHOR_FULL' => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), 'POST_AUTHOR_COLOUR' => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), 'POST_AUTHOR' => get_username_string('username', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']), @@ -250,14 +235,49 @@ function mcp_topic_view($id, $mode, $action) 'MINI_POST_IMG' => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'), 'S_POST_REPORTED' => ($row['post_reported'] && $auth->acl_get('m_report', $topic_info['forum_id'])), - 'S_POST_UNAPPROVED' => (!$row['post_approved'] && $auth->acl_get('m_approve', $topic_info['forum_id'])), + 'S_POST_UNAPPROVED' => (($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $topic_info['forum_id'])), + 'S_POST_DELETED' => ($row['post_visibility'] == ITEM_DELETED && $auth->acl_get('m_approve', $topic_info['forum_id'])), 'S_CHECKED' => (($submitted_id_list && !in_array(intval($row['post_id']), $submitted_id_list)) || in_array(intval($row['post_id']), $checked_ids)) ? true : false, 'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false, 'U_POST_DETAILS' => "$url&i=$id&p={$row['post_id']}&mode=post_details" . (($forum_id) ? "&f=$forum_id" : ''), 'U_MCP_APPROVE' => ($auth->acl_get('m_approve', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=approve_details&f=' . $topic_info['forum_id'] . '&p=' . $row['post_id']) : '', - 'U_MCP_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=report_details&f=' . $topic_info['forum_id'] . '&p=' . $row['post_id']) : '') + 'U_MCP_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&mode=report_details&f=' . $topic_info['forum_id'] . '&p=' . $row['post_id']) : '', + ); + + $current_row_number = $i; + + /** + * Event to modify the template data block for topic reviews in the MCP + * + * @event core.mcp_topic_review_modify_row + * @var int id ID of the tab we are displaying + * @var string mode Mode of the MCP page we are displaying + * @var int topic_id The topic ID we are currently reviewing + * @var int forum_id The forum ID we are currently in + * @var int start Start item of this page + * @var int current_row_number Number of the post on this page + * @var array post_row Template block array of the current post + * @var array row Array with original post and user data + * @var array topic_info Array with topic data + * @var int total Total posts count + * @since 3.1.4-RC1 + */ + $vars = array( + 'id', + 'mode', + 'topic_id', + 'forum_id', + 'start', + 'current_row_number', + 'post_row', + 'row', + 'topic_info', + 'total', ); + extract($phpbb_dispatcher->trigger_event('core.mcp_topic_review_modify_row', compact($vars))); + + $template->assign_block_vars('postrow', $post_row); // Display not already displayed Attachments for this post, we already parsed them. ;) if (!empty($attachments[$row['post_id']])) @@ -284,7 +304,7 @@ function mcp_topic_view($id, $mode, $action) // Has the user selected a topic for merge? if ($to_topic_id) { - $to_topic_info = get_topic_data(array($to_topic_id), 'm_merge'); + $to_topic_info = phpbb_get_topic_data(array($to_topic_id), 'm_merge'); if (!sizeof($to_topic_info)) { @@ -307,6 +327,12 @@ function mcp_topic_view($id, $mode, $action) 'post_ids' => $post_id_list, )); + $base_url = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&t={$topic_info['topic_id']}&mode=$mode&action=$action&to_topic_id=$to_topic_id&posts_per_page=$posts_per_page&st=$sort_days&sk=$sort_key&sd=$sort_dir"); + if ($posts_per_page) + { + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total, $posts_per_page, $start); + } + $template->assign_vars(array( 'TOPIC_TITLE' => $topic_info['topic_title'], 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_info['forum_id'] . '&t=' . $topic_info['topic_id']), @@ -320,6 +346,7 @@ function mcp_topic_view($id, $mode, $action) 'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED'), 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'), + 'DELETED_IMG' => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'), 'INFO_IMG' => $user->img('icon_post_info', 'VIEW_INFO'), 'S_MCP_ACTION' => "$url&i=$id&mode=$mode&action=$action&start=$start", @@ -328,6 +355,7 @@ function mcp_topic_view($id, $mode, $action) 'S_CAN_MERGE' => ($auth->acl_get('m_merge', $topic_info['forum_id'])) ? true : false, 'S_CAN_DELETE' => ($auth->acl_get('m_delete', $topic_info['forum_id'])) ? true : false, 'S_CAN_APPROVE' => ($has_unapproved_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false, + 'S_CAN_RESTORE' => ($has_deleted_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false, 'S_CAN_LOCK' => ($auth->acl_get('m_lock', $topic_info['forum_id'])) ? true : false, 'S_CAN_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? true : false, 'S_CAN_SYNC' => $auth->acl_get('m_', $topic_info['forum_id']), @@ -345,9 +373,7 @@ function mcp_topic_view($id, $mode, $action) 'RETURN_TOPIC' => sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f={$topic_info['forum_id']}&t={$topic_info['topic_id']}&start=$start") . '">', '</a>'), 'RETURN_FORUM' => sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", "f={$topic_info['forum_id']}&start=$start") . '">', '</a>'), - 'PAGE_NUMBER' => on_page($total, $posts_per_page, $start), - 'PAGINATION' => (!$posts_per_page) ? '' : generate_pagination(append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&t={$topic_info['topic_id']}&mode=$mode&action=$action&to_topic_id=$to_topic_id&posts_per_page=$posts_per_page&st=$sort_days&sk=$sort_key&sd=$sort_dir"), $total, $posts_per_page, $start), - 'TOTAL_POSTS' => ($total == 1) ? $user->lang['VIEW_TOPIC_POST'] : sprintf($user->lang['VIEW_TOPIC_POSTS'], $total), + 'TOTAL_POSTS' => $user->lang('VIEW_TOPIC_POSTS', (int) $total), )); } @@ -368,13 +394,13 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) return; } - if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_split'))) + if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_split'))) { return; } $post_id = $post_id_list[0]; - $post_info = get_post_data(array($post_id)); + $post_info = phpbb_get_post_data(array($post_id)); if (!sizeof($post_info)) { @@ -398,7 +424,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) return; } - $forum_info = get_forum_data(array($to_forum_id), 'f_post'); + $forum_info = phpbb_get_forum_data(array($to_forum_id), 'f_post'); if (!sizeof($forum_info)) { @@ -438,13 +464,13 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) $sort_days = $total = 0; $sort_key = $sort_dir = ''; $sort_by_sql = $sort_order_sql = array(); - mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id); + phpbb_mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id); $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : ''; if ($sort_order_sql[0] == 'u') { - $sql = 'SELECT p.post_id, p.forum_id, p.post_approved + $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u WHERE p.topic_id = $topic_id AND p.poster_id = u.user_id @@ -453,7 +479,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) } else { - $sql = 'SELECT p.post_id, p.forum_id, p.post_approved + $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility FROM ' . POSTS_TABLE . " p WHERE p.topic_id = $topic_id $limit_time_sql @@ -466,7 +492,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) while ($row = $db->sql_fetchrow($result)) { // If split from selected post (split_beyond), we split the unapproved items too. - if (!$row['post_approved'] && !$auth->acl_get('m_approve', $row['forum_id'])) + if (($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) && !$auth->acl_get('m_approve', $row['forum_id'])) { // continue; } @@ -493,10 +519,10 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) $icon_id = request_var('icon', 0); $sql_ary = array( - 'forum_id' => $to_forum_id, - 'topic_title' => $subject, - 'icon_id' => $icon_id, - 'topic_approved'=> 1 + 'forum_id' => $to_forum_id, + 'topic_title' => $subject, + 'icon_id' => $icon_id, + 'topic_visibility' => 1 ); $sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); @@ -505,7 +531,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) $to_topic_id = $db->sql_nextid(); move_posts($post_id_list, $to_topic_id); - $topic_info = get_topic_data(array($topic_id)); + $topic_info = phpbb_get_topic_data(array($topic_id)); $topic_info = $topic_info[$topic_id]; add_log('mod', $to_forum_id, $to_topic_id, 'LOG_SPLIT_DESTINATION', $subject); @@ -567,23 +593,15 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) // Link back to both topics $return_link = sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $post_info['forum_id'] . '&t=' . $post_info['topic_id']) . '">', '</a>') . '<br /><br />' . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_forum_id . '&t=' . $to_topic_id) . '">', '</a>'); - } - else - { - confirm_box(false, ($action == 'split_all') ? 'SPLIT_TOPIC_ALL' : 'SPLIT_TOPIC_BEYOND', $s_hidden_fields); - } - - $redirect = request_var('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); + $redirect = request_var('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&t=$to_topic_id"); + $redirect = reapply_sid($redirect); - if (!$success_msg) - { - return; + meta_refresh(3, $redirect); + trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link); } else { - meta_refresh(3, append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$to_forum_id&t=$to_topic_id")); - trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link); + confirm_box(false, ($action == 'split_all') ? 'SPLIT_TOPIC_ALL' : 'SPLIT_TOPIC_BEYOND', $s_hidden_fields); } } @@ -600,14 +618,22 @@ function merge_posts($topic_id, $to_topic_id) return; } - $topic_data = get_topic_data(array($to_topic_id), 'm_merge'); + $sync_topics = array($topic_id, $to_topic_id); - if (!sizeof($topic_data)) + $topic_data = phpbb_get_topic_data($sync_topics, 'm_merge'); + + if (!sizeof($topic_data) || empty($topic_data[$to_topic_id])) { $template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']); return; } + $sync_forums = array(); + foreach ($topic_data as $data) + { + $sync_forums[$data['forum_id']] = $data['forum_id']; + } + $topic_data = $topic_data[$to_topic_id]; $post_id_list = request_var('post_id_list', array(0)); @@ -619,7 +645,7 @@ function merge_posts($topic_id, $to_topic_id) return; } - if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_merge'))) + if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_merge'))) { return; } @@ -642,7 +668,7 @@ function merge_posts($topic_id, $to_topic_id) { $to_forum_id = $topic_data['forum_id']; - move_posts($post_id_list, $to_topic_id); + move_posts($post_id_list, $to_topic_id, false); add_log('mod', $to_forum_id, $to_topic_id, 'LOG_MERGE', $topic_data['topic_title']); // Message and return links @@ -650,7 +676,7 @@ function merge_posts($topic_id, $to_topic_id) // Does the original topic still exist? If yes, link back to it $sql = 'SELECT forum_id - FROM ' . TOPICS_TABLE . ' + FROM ' . POSTS_TABLE . ' WHERE topic_id = ' . $topic_id; $result = $db->sql_query_limit($sql, 1); $row = $db->sql_fetchrow($result); @@ -674,26 +700,22 @@ function merge_posts($topic_id, $to_topic_id) phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', array($topic_id), $to_topic_id); } + // Re-sync the topics and forums because the auto-sync was deactivated in the call of move_posts() + sync('topic_reported', 'topic_id', $sync_topics); + sync('topic_attachment', 'topic_id', $sync_topics); + sync('topic', 'topic_id', $sync_topics, true); + sync('forum', 'forum_id', $sync_forums, true, true); + // Link to the new topic $return_link .= (($return_link) ? '<br /><br />' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_forum_id . '&t=' . $to_topic_id) . '">', '</a>'); - } - else - { - confirm_box(false, 'MERGE_POSTS', $s_hidden_fields); - } - - $redirect = request_var('redirect', "index.$phpEx"); - $redirect = reapply_sid($redirect); + $redirect = request_var('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&t=$to_topic_id"); + $redirect = reapply_sid($redirect); - if (!$success_msg) - { - return; + meta_refresh(3, $redirect); + trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link); } else { - meta_refresh(3, append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$to_forum_id&t=$to_topic_id")); - trigger_error($user->lang[$success_msg] . '<br /><br />' . $return_link); + confirm_box(false, 'MERGE_POSTS', $s_hidden_fields); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_warn.php b/phpBB/includes/mcp/mcp_warn.php index 1016204ff8..d724b8703b 100644 --- a/phpBB/includes/mcp/mcp_warn.php +++ b/phpBB/includes/mcp/mcp_warn.php @@ -1,10 +1,13 @@ <?php /** * -* @package mcp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * mcp_warn * Handling warning the users -* @package mcp */ class mcp_warn { @@ -97,9 +99,6 @@ class mcp_warn 'U_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $row['user_id']), 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'USERNAME' => $row['username'], - 'USERNAME_COLOUR' => ($row['user_colour']) ? '#' . $row['user_colour'] : '', - 'U_USER' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['user_id']), 'WARNING_TIME' => $user->format_date($row['user_last_warning']), 'WARNINGS' => $row['user_warnings'], @@ -119,9 +118,6 @@ class mcp_warn 'U_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $row['user_id']), 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'USERNAME' => $row['username'], - 'USERNAME_COLOUR' => ($row['user_colour']) ? '#' . $row['user_colour'] : '', - 'U_USER' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['user_id']), 'WARNING_TIME' => $user->format_date($row['warning_time']), 'WARNINGS' => $row['user_warnings'], @@ -135,10 +131,11 @@ class mcp_warn */ function mcp_warn_list_view($action) { - global $phpEx, $phpbb_root_path, $config; + global $phpEx, $phpbb_root_path, $config, $phpbb_container; global $template, $db, $user, $auth; $user->add_lang('memberlist'); + $pagination = $phpbb_container->get('pagination'); $start = request_var('start', 0); $st = request_var('st', 0); @@ -167,15 +164,15 @@ class mcp_warn 'U_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $row['user_id']), 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), - 'USERNAME' => $row['username'], - 'USERNAME_COLOUR' => ($row['user_colour']) ? '#' . $row['user_colour'] : '', - 'U_USER' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['user_id']), 'WARNING_TIME' => $user->format_date($row['user_last_warning']), 'WARNINGS' => $row['user_warnings'], )); } + $base_url = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=warn&mode=list&st=$st&sk=$sk&sd=$sd"); + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $user_count, $config['topics_per_page'], $start); + $template->assign_vars(array( 'U_POST_ACTION' => $this->u_action, 'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false, @@ -183,9 +180,7 @@ class mcp_warn 'S_SELECT_SORT_KEY' => $s_sort_key, 'S_SELECT_SORT_DAYS' => $s_limit_days, - 'PAGE_NUMBER' => on_page($user_count, $config['topics_per_page'], $start), - 'PAGINATION' => generate_pagination(append_sid("{$phpbb_root_path}mcp.$phpEx", "i=warn&mode=list&st=$st&sk=$sk&sd=$sd"), $user_count, $config['topics_per_page'], $start), - 'TOTAL_USERS' => ($user_count == 1) ? $user->lang['LIST_USER'] : sprintf($user->lang['LIST_USERS'], $user_count), + 'TOTAL_USERS' => $user->lang('LIST_USERS', (int) $user_count), )); } @@ -195,7 +190,7 @@ class mcp_warn function mcp_warn_post_view($action) { global $phpEx, $phpbb_root_path, $config; - global $template, $db, $user, $auth; + global $template, $db, $user, $auth, $phpbb_dispatcher; $post_id = request_var('p', 0); $forum_id = request_var('f', 0); @@ -252,7 +247,7 @@ class mcp_warn // Check if can send a notification if ($config['allow_privmsg']) { - $auth2 = new auth(); + $auth2 = new \phpbb\auth\auth(); $auth2->acl($user_row); $s_can_notify = ($auth2->acl_get('u_readpm')) ? true : false; unset($auth2); @@ -272,44 +267,82 @@ class mcp_warn { if (check_form_key('mcp_warn')) { - add_warning($user_row, $warning, $notify, $post_id); - $msg = $user->lang['USER_WARNING_ADDED']; + $s_mcp_warn_post = true; + + /** + * Event for before warning a user for a post. + * + * @event core.mcp_warn_post_before + * @var array user_row The entire user row + * @var string warning The warning message + * @var bool notify If true, we notify the user for the warning + * @var int post_id The post id for which the warning is added + * @var bool s_mcp_warn_post If true, we add the warning else we omit it + * @since 3.1.0-b4 + */ + $vars = array( + 'user_row', + 'warning', + 'notify', + 'post_id', + 's_mcp_warn_post', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_warn_post_before', compact($vars))); + + if ($s_mcp_warn_post) + { + add_warning($user_row, $warning, $notify, $post_id); + $message = $user->lang['USER_WARNING_ADDED']; + + /** + * Event for after warning a user for a post. + * + * @event core.mcp_warn_post_after + * @var array user_row The entire user row + * @var string warning The warning message + * @var bool notify If true, the user was notified for the warning + * @var int post_id The post id for which the warning is added + * @var string message Message displayed to the moderator + * @since 3.1.0-b4 + */ + $vars = array( + 'user_row', + 'warning', + 'notify', + 'post_id', + 'message', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_warn_post_after', compact($vars))); + } } else { - $msg = $user->lang['FORM_INVALID']; + $message = $user->lang['FORM_INVALID']; + } + + if (!empty($message)) + { + $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=notes&mode=user_notes&u=$user_id"); + meta_refresh(2, $redirect); + trigger_error($message . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>')); } - $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=notes&mode=user_notes&u=$user_id"); - meta_refresh(2, $redirect); - trigger_error($msg . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>')); } // OK, they didn't submit a warning so lets build the page for them to do so // We want to make the message available here as a reminder // Parse the message and subject - $message = censor_text($user_row['post_text']); - - // Second parse bbcode here - if ($user_row['bbcode_bitfield']) - { - include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - - $bbcode = new bbcode($user_row['bbcode_bitfield']); - $bbcode->bbcode_second_pass($message, $user_row['bbcode_uid'], $user_row['bbcode_bitfield']); - } - - $message = bbcode_nl2br($message); - $message = smiley_text($message); + $parse_flags = OPTION_FLAG_SMILIES | ($user_row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0); + $message = generate_text_for_display($user_row['post_text'], $user_row['bbcode_uid'], $user_row['bbcode_bitfield'], $parse_flags, true); // Generate the appropriate user information for the user we are looking at - if (!function_exists('get_user_avatar')) + if (!function_exists('phpbb_get_user_rank')) { include($phpbb_root_path . 'includes/functions_display.' . $phpEx); } - get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src); - $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']); + $user_rank_data = phpbb_get_user_rank($user_row, $user_row['user_posts']); + $avatar_img = phpbb_get_user_avatar($user_row); $template->assign_vars(array( 'U_POST_ACTION' => $this->u_action, @@ -317,13 +350,13 @@ class mcp_warn 'POST' => $message, 'USERNAME' => $user_row['username'], 'USER_COLOR' => (!empty($user_row['user_colour'])) ? $user_row['user_colour'] : '', - 'RANK_TITLE' => $rank_title, + 'RANK_TITLE' => $user_rank_data['title'], 'JOINED' => $user->format_date($user_row['user_regdate']), 'POSTS' => ($user_row['user_posts']) ? $user_row['user_posts'] : 0, 'WARNINGS' => ($user_row['user_warnings']) ? $user_row['user_warnings'] : 0, 'AVATAR_IMG' => $avatar_img, - 'RANK_IMG' => $rank_img, + 'RANK_IMG' => $user_rank_data['img'], 'L_WARNING_POST_DEFAULT' => sprintf($user->lang['WARNING_POST_DEFAULT'], generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&p=$post_id#p$post_id"), @@ -337,7 +370,7 @@ class mcp_warn function mcp_warn_user_view($action) { global $phpEx, $phpbb_root_path, $config, $module; - global $template, $db, $user, $auth; + global $template, $db, $user, $auth, $phpbb_dispatcher; $user_id = request_var('u', 0); $username = request_var('username', '', true); @@ -375,7 +408,7 @@ class mcp_warn // Check if can send a notification if ($config['allow_privmsg']) { - $auth2 = new auth(); + $auth2 = new \phpbb\auth\auth(); $auth2->acl($user_row); $s_can_notify = ($auth2->acl_get('u_readpm')) ? true : false; unset($auth2); @@ -395,32 +428,76 @@ class mcp_warn { if (check_form_key('mcp_warn')) { - add_warning($user_row, $warning, $notify); - $msg = $user->lang['USER_WARNING_ADDED']; + $s_mcp_warn_user = true; + + /** + * Event for before warning a user from MCP. + * + * @event core.mcp_warn_user_before + * @var array user_row The entire user row + * @var string warning The warning message + * @var bool notify If true, we notify the user for the warning + * @var bool s_mcp_warn_user If true, we add the warning else we omit it + * @since 3.1.0-b4 + */ + $vars = array( + 'user_row', + 'warning', + 'notify', + 's_mcp_warn_user', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_warn_user_before', compact($vars))); + + if ($s_mcp_warn_user) + { + add_warning($user_row, $warning, $notify); + $message = $user->lang['USER_WARNING_ADDED']; + + /** + * Event for after warning a user from MCP. + * + * @event core.mcp_warn_user_after + * @var array user_row The entire user row + * @var string warning The warning message + * @var bool notify If true, the user was notified for the warning + * @var string message Message displayed to the moderator + * @since 3.1.0-b4 + */ + $vars = array( + 'user_row', + 'warning', + 'notify', + 'message', + ); + extract($phpbb_dispatcher->trigger_event('core.mcp_warn_user_after', compact($vars))); + } } else { - $msg = $user->lang['FORM_INVALID']; + $message = $user->lang['FORM_INVALID']; + } + + if (!empty($message)) + { + $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=notes&mode=user_notes&u=$user_id"); + meta_refresh(2, $redirect); + trigger_error($message . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>')); } - $redirect = append_sid("{$phpbb_root_path}mcp.$phpEx", "i=notes&mode=user_notes&u=$user_id"); - meta_refresh(2, $redirect); - trigger_error($msg . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>')); } // Generate the appropriate user information for the user we are looking at - if (!function_exists('get_user_avatar')) + if (!function_exists('phpbb_get_user_rank')) { include($phpbb_root_path . 'includes/functions_display.' . $phpEx); } - - get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src); - $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']); + $user_rank_data = phpbb_get_user_rank($user_row, $user_row['user_posts']); + $avatar_img = phpbb_get_user_avatar($user_row); // OK, they didn't submit a warning so lets build the page for them to do so $template->assign_vars(array( 'U_POST_ACTION' => $this->u_action, - 'RANK_TITLE' => $rank_title, + 'RANK_TITLE' => $user_rank_data['title'], 'JOINED' => $user->format_date($user_row['user_regdate']), 'POSTS' => ($user_row['user_posts']) ? $user_row['user_posts'] : 0, 'WARNINGS' => ($user_row['user_warnings']) ? $user_row['user_warnings'] : 0, @@ -431,7 +508,7 @@ class mcp_warn 'U_PROFILE' => get_username_string('profile', $user_row['user_id'], $user_row['username'], $user_row['user_colour']), 'AVATAR_IMG' => $avatar_img, - 'RANK_IMG' => $rank_img, + 'RANK_IMG' => $user_rank_data['img'], 'S_CAN_NOTIFY' => $s_can_notify, )); @@ -458,7 +535,7 @@ function add_warning($user_row, $warning, $send_pm = true, $post_id = 0) $message_parser = new parse_message(); - $message_parser->message = sprintf($lang['WARNING_PM_BODY'], $warning); + $message_parser->message = $user->lang('WARNING_PM_BODY', $warning); $message_parser->parse(true, true, true, false, false, true, true); $pm_data = array( @@ -476,7 +553,7 @@ function add_warning($user_row, $warning, $send_pm = true, $post_id = 0) 'address_list' => array('u' => array($user_row['user_id'] => 'to')), ); - submit_pm('post', $lang['WARNING_PM_SUBJECT'], $pm_data, false); + submit_pm('post', $user->lang('WARNING_PM_SUBJECT'), $pm_data, false); } add_log('admin', 'LOG_USER_WARNING', $user_row['username']); @@ -507,5 +584,3 @@ function add_warning($user_row, $warning, $send_pm = true, $post_id = 0) add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_USER_WARNING', $user_row['username']); } - -?>
\ No newline at end of file diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index a134fab5d3..63e027cd66 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,13 +21,25 @@ if (!defined('IN_PHPBB')) if (!class_exists('bbcode')) { + // The following lines are for extensions which include message_parser.php + // while $phpbb_root_path and $phpEx are out of the script scope + // which may lead to the 'Undefined variable' and 'failed to open stream' errors + if (!isset($phpbb_root_path)) + { + global $phpbb_root_path; + } + + if (!isset($phpEx)) + { + global $phpEx; + } + include($phpbb_root_path . 'includes/bbcode.' . $phpEx); } /** * BBCODE FIRSTPASS * BBCODE first pass class (functions for parsing messages for db storage) -* @package phpBB3 */ class bbcode_firstpass extends bbcode { @@ -104,6 +119,8 @@ class bbcode_firstpass extends bbcode */ function bbcode_init($allow_custom_bbcode = true) { + global $phpbb_dispatcher; + static $rowset; // This array holds all bbcode data. BBCodes will be processed in this @@ -163,6 +180,21 @@ class bbcode_firstpass extends bbcode 'regexp' => array($row['first_pass_match'] => str_replace('$uid', $this->bbcode_uid, $row['first_pass_replace'])) ); } + + $bbcodes = $this->bbcodes; + + /** + * Event to modify the bbcode data for later parsing + * + * @event core.modify_bbcode_init + * @var array bbcodes Array of bbcode data for use in parsing + * @var array rowset Array of bbcode data from the database + * @since 3.1.0-a3 + */ + $vars = array('bbcodes', 'rowset'); + extract($phpbb_dispatcher->trigger_event('core.modify_bbcode_init', compact($vars))); + + $this->bbcodes = $bbcodes; } /** @@ -210,7 +242,7 @@ class bbcode_firstpass extends bbcode if ($config['max_' . $this->mode . '_font_size'] && $config['max_' . $this->mode . '_font_size'] < $stx) { - $this->warn_msg[] = sprintf($user->lang['MAX_FONT_SIZE_EXCEEDED'], $config['max_' . $this->mode . '_font_size']); + $this->warn_msg[] = $user->lang('MAX_FONT_SIZE_EXCEEDED', (int) $config['max_' . $this->mode . '_font_size']); return '[size=' . $stx . ']' . $in . '[/size]'; } @@ -294,7 +326,7 @@ class bbcode_firstpass extends bbcode $in = str_replace(' ', '%20', $in); // Checking urls - if (!preg_match('#^' . get_preg_expression('url') . '$#i', $in) && !preg_match('#^' . get_preg_expression('www_url') . '$#i', $in)) + if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $in) && !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $in)) { return '[img]' . $in . '[/img]'; } @@ -319,13 +351,13 @@ class bbcode_firstpass extends bbcode if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $stats[1]) { $error = true; - $this->warn_msg[] = sprintf($user->lang['MAX_IMG_HEIGHT_EXCEEDED'], $config['max_' . $this->mode . '_img_height']); + $this->warn_msg[] = $user->lang('MAX_IMG_HEIGHT_EXCEEDED', (int) $config['max_' . $this->mode . '_img_height']); } if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $stats[0]) { $error = true; - $this->warn_msg[] = sprintf($user->lang['MAX_IMG_WIDTH_EXCEEDED'], $config['max_' . $this->mode . '_img_width']); + $this->warn_msg[] = $user->lang('MAX_IMG_WIDTH_EXCEEDED', (int) $config['max_' . $this->mode . '_img_width']); } } } @@ -362,8 +394,8 @@ class bbcode_firstpass extends bbcode $in = str_replace(' ', '%20', $in); // Make sure $in is a URL. - if (!preg_match('#^' . get_preg_expression('url') . '$#i', $in) && - !preg_match('#^' . get_preg_expression('www_url') . '$#i', $in)) + if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $in) && + !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $in)) { return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; } @@ -374,13 +406,13 @@ class bbcode_firstpass extends bbcode if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $height) { $error = true; - $this->warn_msg[] = sprintf($user->lang['MAX_FLASH_HEIGHT_EXCEEDED'], $config['max_' . $this->mode . '_img_height']); + $this->warn_msg[] = $user->lang('MAX_FLASH_HEIGHT_EXCEEDED', (int) $config['max_' . $this->mode . '_img_height']); } if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $width) { $error = true; - $this->warn_msg[] = sprintf($user->lang['MAX_FLASH_WIDTH_EXCEEDED'], $config['max_' . $this->mode . '_img_width']); + $this->warn_msg[] = $user->lang('MAX_FLASH_WIDTH_EXCEEDED', (int) $config['max_' . $this->mode . '_img_width']); } } @@ -703,17 +735,6 @@ class bbcode_firstpass extends bbcode { global $config, $user; - /** - * If you change this code, make sure the cases described within the following reports are still working: - * #3572 - [quote="[test]test"]test [ test[/quote] - (correct: parsed) - * #14667 - [quote]test[/quote] test ] and [ test [quote]test[/quote] (correct: parsed) - * #14770 - [quote="["]test[/quote] (correct: parsed) - * [quote="[i]test[/i]"]test[/quote] (correct: parsed) - * [quote="[quote]test[/quote]"]test[/quote] (correct: parsed - Username displayed as [quote]test[/quote]) - * #20735 - [quote]test[/[/b]quote] test [/quote][/quote] test - (correct: quoted: "test[/[/b]quote] test" / non-quoted: "[/quote] test" - also failed if layout distorted) - * #40565 - [quote="a"]a[/quote][quote="a]a[/quote] (correct: first quote tag parsed, second quote tag unparsed) - */ - $in = str_replace("\r\n", "\n", str_replace('\"', '"', trim($in))); if (!$in) @@ -771,8 +792,16 @@ class bbcode_firstpass extends bbcode // the buffer holds a valid opening tag if ($config['max_quote_depth'] && sizeof($close_tags) >= $config['max_quote_depth']) { - // there are too many nested quotes - $error_ary['quote_depth'] = sprintf($user->lang['QUOTE_DEPTH_EXCEEDED'], $config['max_quote_depth']); + if ($config['max_quote_depth'] == 1) + { + // Depth 1 - no nesting is allowed + $error_ary['quote_depth'] = $user->lang('QUOTE_NO_NESTING'); + } + else + { + // There are too many nested quotes + $error_ary['quote_depth'] = $user->lang('QUOTE_DEPTH_EXCEEDED', (int) $config['max_quote_depth']); + } $out .= $buffer . $tok; $tok = '[]'; @@ -957,9 +986,9 @@ class bbcode_firstpass extends bbcode $url = str_replace(' ', '%20', $url); // Checking urls - if (preg_match('#^' . get_preg_expression('url') . '$#i', $url) || - preg_match('#^' . get_preg_expression('www_url') . '$#i', $url) || - preg_match('#^' . preg_quote(generate_board_url(), '#') . get_preg_expression('relative_url') . '$#i', $url)) + if (preg_match('#^' . get_preg_expression('url') . '$#iu', $url) || + preg_match('#^' . get_preg_expression('www_url') . '$#iu', $url) || + preg_match('#^' . preg_quote(generate_board_url(), '#') . get_preg_expression('relative_url') . '$#iu', $url)) { $valid = true; } @@ -1044,7 +1073,6 @@ class bbcode_firstpass extends bbcode /** * Main message parser for posting, pm, etc. takes raw message * and parses it for attachments, bbcode and smilies -* @package phpBB3 */ class parse_message extends bbcode_firstpass { @@ -1062,6 +1090,18 @@ class parse_message extends bbcode_firstpass var $mode; /** + * The plupload object used for dealing with attachments + * @var \phpbb\plupload\plupload + */ + protected $plupload; + + /** + * The mimetype guesser object used for attachment mimetypes + * @var \phpbb\mimetype\guesser + */ + protected $mimetype_guesser; + + /** * Init - give message here or manually */ function parse_message($message = '') @@ -1076,7 +1116,7 @@ class parse_message extends bbcode_firstpass */ function parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $allow_url_bbcode = true, $update_this_message = true, $mode = 'post') { - global $config, $db, $user; + global $config, $db, $user, $phpbb_dispatcher; $this->mode = $mode; @@ -1117,7 +1157,7 @@ class parse_message extends bbcode_firstpass // Maximum message length check. 0 disables this check completely. if ((int) $config['max_' . $mode . '_chars'] > 0 && $message_length > (int) $config['max_' . $mode . '_chars']) { - $this->warn_msg[] = sprintf($user->lang['TOO_MANY_CHARS_' . strtoupper($mode)], $message_length, (int) $config['max_' . $mode . '_chars']); + $this->warn_msg[] = $user->lang('CHARS_' . strtoupper($mode) . '_CONTAINS', $message_length) . '<br />' . $user->lang('TOO_MANY_CHARS_LIMIT', (int) $config['max_' . $mode . '_chars']); return (!$update_this_message) ? $return_message : $this->warn_msg; } @@ -1126,11 +1166,63 @@ class parse_message extends bbcode_firstpass { if (!$message_length || $message_length < (int) $config['min_post_chars']) { - $this->warn_msg[] = (!$message_length) ? $user->lang['TOO_FEW_CHARS'] : sprintf($user->lang['TOO_FEW_CHARS_LIMIT'], $message_length, (int) $config['min_post_chars']); + $this->warn_msg[] = (!$message_length) ? $user->lang['TOO_FEW_CHARS'] : ($user->lang('CHARS_POST_CONTAINS', $message_length) . '<br />' . $user->lang('TOO_FEW_CHARS_LIMIT', (int) $config['min_post_chars'])); return (!$update_this_message) ? $return_message : $this->warn_msg; } } + /** + * This event can be used for additional message checks/cleanup before parsing + * + * @event core.message_parser_check_message + * @var bool allow_bbcode Do we allow BBCodes + * @var bool allow_magic_url Do we allow magic urls + * @var bool allow_smilies Do we allow smilies + * @var bool allow_img_bbcode Do we allow image BBCode + * @var bool allow_flash_bbcode Do we allow flash BBCode + * @var bool allow_quote_bbcode Do we allow quote BBCode + * @var bool allow_url_bbcode Do we allow url BBCode + * @var bool update_this_message Do we alter the parsed message + * @var string mode Posting mode + * @var string message The message text to parse + * @var string bbcode_bitfield The bbcode_bitfield before parsing + * @var string bbcode_uid The bbcode_uid before parsing + * @var bool return Do we return after the event is triggered if $warn_msg is not empty + * @var array warn_msg Array of the warning messages + * @since 3.1.2-RC1 + * @change 3.1.3-RC1 Added vars $bbcode_bitfield and $bbcode_uid + */ + $message = $this->message; + $warn_msg = $this->warn_msg; + $return = false; + $bbcode_bitfield = $this->bbcode_bitfield; + $bbcode_uid = $this->bbcode_uid; + $vars = array( + 'allow_bbcode', + 'allow_magic_url', + 'allow_smilies', + 'allow_img_bbcode', + 'allow_flash_bbcode', + 'allow_quote_bbcode', + 'allow_url_bbcode', + 'update_this_message', + 'mode', + 'message', + 'bbcode_bitfield', + 'bbcode_uid', + 'return', + 'warn_msg', + ); + extract($phpbb_dispatcher->trigger_event('core.message_parser_check_message', compact($vars))); + $this->message = $message; + $this->warn_msg = $warn_msg; + $this->bbcode_bitfield = $bbcode_bitfield; + $this->bbcode_uid = $bbcode_uid; + if ($return && !empty($this->warn_msg)) + { + return (!$update_this_message) ? $return_message : $this->warn_msg; + } + // Prepare BBcode (just prepares some tags for better parsing) if ($allow_bbcode && strpos($this->message, '[') !== false) { @@ -1173,6 +1265,15 @@ class parse_message extends bbcode_firstpass } } + // Check for out-of-bounds characters that are currently + // not supported by utf8_bin in MySQL + if (preg_match_all('/[\x{10000}-\x{10FFFF}]/u', $this->message, $matches)) + { + $character_list = implode('<br />', $matches[0]); + $this->warn_msg[] = $user->lang('UNSUPPORTED_CHARACTERS_MESSAGE', $character_list); + return $update_this_message ? $this->warn_msg : $return_message; + } + // Check for "empty" message. We do not check here for maximum length, because bbcode, smilies, etc. can add to the length. // The maximum length check happened before any parsings. if ($mode === 'post' && utf8_clean_string($this->message) === '') @@ -1204,6 +1305,8 @@ class parse_message extends bbcode_firstpass */ function format_display($allow_bbcode, $allow_magic_url, $allow_smilies, $update_this_message = true) { + global $phpbb_dispatcher; + // If false, then the parsed message get returned but internal message not processed. if (!$update_this_message) { @@ -1232,6 +1335,28 @@ class parse_message extends bbcode_firstpass $this->message = bbcode_nl2br($this->message); $this->message = smiley_text($this->message, !$allow_smilies); + $text = $this->message; + $uid = $this->bbcode_uid; + + /** + * Event to modify the text after it is parsed + * + * @event core.modify_format_display_text_after + * @var string text The message text to parse + * @var string uid The bbcode uid + * @var bool allow_bbcode Do we allow bbcodes + * @var bool allow_magic_url Do we allow magic urls + * @var bool allow_smilies Do we allow smilies + * @var bool update_this_message Do we update the internal message + * with the parsed result + * @since 3.1.0-a3 + */ + $vars = array('text', 'uid', 'allow_bbcode', 'allow_magic_url', 'allow_smilies', 'update_this_message'); + extract($phpbb_dispatcher->trigger_event('core.modify_format_display_text_after', compact($vars))); + + $this->message = $text; + $this->bbcode_uid = $uid; + if (!$update_this_message) { unset($this->message); @@ -1296,7 +1421,7 @@ class parse_message extends bbcode_firstpass // NOTE: obtain_* function? chaching the table contents? // For now setting the ttl to 10 minutes - switch ($db->sql_layer) + switch ($db->get_sql_layer()) { case 'mssql': case 'mssql_odbc': @@ -1306,12 +1431,6 @@ class parse_message extends bbcode_firstpass ORDER BY LEN(code) DESC'; break; - case 'firebird': - $sql = 'SELECT * - FROM ' . SMILIES_TABLE . ' - ORDER BY CHAR_LENGTH(code) DESC'; - break; - // LENGTH supported by MySQL, IBM DB2, Oracle and Access for sure... default: $sql = 'SELECT * @@ -1364,13 +1483,14 @@ class parse_message extends bbcode_firstpass */ function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false) { - global $config, $auth, $user, $phpbb_root_path, $phpEx, $db; + global $config, $auth, $user, $phpbb_root_path, $phpEx, $db, $request; $error = array(); $num_attachments = sizeof($this->attachment_data); $this->filename_data['filecomment'] = utf8_normalize_nfc(request_var('filecomment', '', true)); - $upload_file = (isset($_FILES[$form_name]) && $_FILES[$form_name]['name'] != 'none' && trim($_FILES[$form_name]['name'])) ? true : false; + $upload = $request->file($form_name); + $upload_file = (!empty($upload) && $upload['name'] !== 'none' && trim($upload['name'])); $add_file = (isset($_POST['add_file'])) ? true : false; $delete_file = (isset($_POST['delete_file'])) ? true : false; @@ -1425,6 +1545,7 @@ class parse_message extends bbcode_firstpass 'is_orphan' => 1, 'real_filename' => $filedata['real_filename'], 'attach_comment'=> $this->filename_data['filecomment'], + 'filesize' => $filedata['filesize'], ); $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); @@ -1445,12 +1566,17 @@ class parse_message extends bbcode_firstpass } else { - $error[] = sprintf($user->lang['TOO_MANY_ATTACHMENTS'], $cfg['max_attachments']); + $error[] = $user->lang('TOO_MANY_ATTACHMENTS', (int) $cfg['max_attachments']); } } if ($preview || $refresh || sizeof($error)) { + if (isset($this->plupload) && $this->plupload->is_active()) + { + $json_response = new \phpbb\json_response(); + } + // Perform actions on temporary attachments if ($delete_file) { @@ -1495,13 +1621,17 @@ class parse_message extends bbcode_firstpass // Reindex Array $this->attachment_data = array_values($this->attachment_data); + if (isset($this->plupload) && $this->plupload->is_active()) + { + $json_response->send($this->attachment_data); + } } } else if (($add_file || $preview) && $upload_file) { if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id)) { - $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message); + $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message, false, $this->mimetype_guesser, $this->plupload); $error = array_merge($error, $filedata['error']); if (!sizeof($error)) @@ -1527,16 +1657,39 @@ class parse_message extends bbcode_firstpass 'is_orphan' => 1, 'real_filename' => $filedata['real_filename'], 'attach_comment'=> $this->filename_data['filecomment'], + 'filesize' => $filedata['filesize'], ); $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message); $this->filename_data['filecomment'] = ''; + + if (isset($this->plupload) && $this->plupload->is_active()) + { + $download_url = append_sid("{$phpbb_root_path}download/file.{$phpEx}", 'mode=view&id=' . $new_entry['attach_id']); + + // Send the client the attachment data to maintain state + $json_response->send(array('data' => $this->attachment_data, 'download_url' => $download_url)); + } } } else { - $error[] = sprintf($user->lang['TOO_MANY_ATTACHMENTS'], $cfg['max_attachments']); + $error[] = $user->lang('TOO_MANY_ATTACHMENTS', (int) $cfg['max_attachments']); + } + + if (!empty($error) && isset($this->plupload) && $this->plupload->is_active()) + { + // If this is a plupload (and thus ajax) request, give the + // client the first error we have + $json_response->send(array( + 'jsonrpc' => '2.0', + 'id' => 'id', + 'error' => array( + 'code' => 105, + 'message' => current($error), + ), + )); } } } @@ -1553,9 +1706,10 @@ class parse_message extends bbcode_firstpass function get_submitted_attachment_data($check_user_id = false) { global $user, $db, $phpbb_root_path, $phpEx, $config; + global $request; $this->filename_data['filecomment'] = utf8_normalize_nfc(request_var('filecomment', '', true)); - $attachment_data = (isset($_POST['attachment_data'])) ? $_POST['attachment_data'] : array(); + $attachment_data = $request->variable('attachment_data', array(0 => array('' => '')), true, \phpbb\request\request_interface::POST); $this->attachment_data = array(); $check_user_id = ($check_user_id === false) ? $user->data['user_id'] : $check_user_id; @@ -1583,7 +1737,7 @@ class parse_message extends bbcode_firstpass if (sizeof($not_orphan)) { // Get the attachment data, based on the poster id... - $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment + $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize FROM ' . ATTACHMENTS_TABLE . ' WHERE ' . $db->sql_in_set('attach_id', array_keys($not_orphan)) . ' AND poster_id = ' . $check_user_id; @@ -1593,7 +1747,7 @@ class parse_message extends bbcode_firstpass { $pos = $not_orphan[$row['attach_id']]; $this->attachment_data[$pos] = $row; - set_var($this->attachment_data[$pos]['attach_comment'], $_POST['attachment_data'][$pos]['attach_comment'], 'string', true); + $this->attachment_data[$pos]['attach_comment'] = $attachment_data[$pos]['attach_comment']; unset($not_orphan[$row['attach_id']]); } @@ -1608,7 +1762,7 @@ class parse_message extends bbcode_firstpass // Regenerate newly uploaded attachments if (sizeof($orphan)) { - $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment + $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize FROM ' . ATTACHMENTS_TABLE . ' WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan)) . ' AND poster_id = ' . $user->data['user_id'] . ' @@ -1619,7 +1773,7 @@ class parse_message extends bbcode_firstpass { $pos = $orphan[$row['attach_id']]; $this->attachment_data[$pos] = $row; - set_var($this->attachment_data[$pos]['attach_comment'], $_POST['attachment_data'][$pos]['attach_comment'], 'string', true); + $this->attachment_data[$pos]['attach_comment'] = $attachment_data[$pos]['attach_comment']; unset($orphan[$row['attach_id']]); } @@ -1697,6 +1851,28 @@ class parse_message extends bbcode_firstpass $poll['poll_max_options'] = ($poll['poll_max_options'] < 1) ? 1 : (($poll['poll_max_options'] > $config['max_poll_options']) ? $config['max_poll_options'] : $poll['poll_max_options']); } -} -?>
\ No newline at end of file + /** + * Setter function for passing the plupload object + * + * @param \phpbb\plupload\plupload $plupload The plupload object + * + * @return null + */ + public function set_plupload(\phpbb\plupload\plupload $plupload) + { + $this->plupload = $plupload; + } + + /** + * Setter function for passing the mimetype_guesser object + * + * @param \phpbb\mimetype\guesser $mimetype_guesser The mimetype_guesser object + * + * @return null + */ + public function set_mimetype_guesser(\phpbb\mimetype\guesser $mimetype_guesser) + { + $this->mimetype_guesser = $mimetype_guesser; + } +} diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php index 3268775cb6..63ea432863 100644 --- a/phpBB/includes/questionnaire/questionnaire.php +++ b/phpBB/includes/questionnaire/questionnaire.php @@ -1,10 +1,13 @@ <?php /** * -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -88,7 +91,6 @@ class phpbb_questionnaire_data_collector /** * Questionnaire PHP data provider -* @package phpBB3 */ class phpbb_questionnaire_php_data_provider { @@ -132,7 +134,6 @@ class phpbb_questionnaire_php_data_provider /** * Questionnaire System data provider -* @package phpBB3 */ class phpbb_questionnaire_system_data_provider { @@ -148,23 +149,15 @@ class phpbb_questionnaire_system_data_provider */ function get_data() { - // Start discovering the IPV4 server address, if available - $server_address = '0.0.0.0'; - - if (!empty($_SERVER['SERVER_ADDR'])) - { - $server_address = $_SERVER['SERVER_ADDR']; - } + global $request; - // Running on IIS? - if (!empty($_SERVER['LOCAL_ADDR'])) - { - $server_address = $_SERVER['LOCAL_ADDR']; - } + // Start discovering the IPV4 server address, if available + // Try apache, IIS, fall back to 0.0.0.0 + $server_address = htmlspecialchars_decode($request->server('SERVER_ADDR', $request->server('LOCAL_ADDR', '0.0.0.0'))); return array( 'os' => PHP_OS, - 'httpd' => $_SERVER['SERVER_SOFTWARE'], + 'httpd' => htmlspecialchars_decode($request->server('SERVER_SOFTWARE')), // we don't want the real IP address (for privacy policy reasons) but only // a network address to see whether your installation is running on a private or public network. 'private_ip' => $this->is_private_ip($server_address), @@ -220,7 +213,6 @@ class phpbb_questionnaire_system_data_provider /** * Questionnaire phpBB data provider -* @package phpBB3 */ class phpbb_questionnaire_phpbb_data_provider { @@ -265,10 +257,13 @@ class phpbb_questionnaire_phpbb_data_provider */ function get_data() { - global $phpbb_root_path, $phpEx; - include("{$phpbb_root_path}config.$phpEx"); + global $phpbb_root_path, $phpEx, $phpbb_config_php_file; + + extract($phpbb_config_php_file->get_all()); unset($dbhost, $dbport, $dbname, $dbuser, $dbpasswd); // Just a precaution + $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms); + // Only send certain config vars $config_vars = array( 'active_sessions' => true, @@ -313,7 +308,6 @@ class phpbb_questionnaire_phpbb_data_provider 'avatar_max_width' => true, 'avatar_min_height' => true, 'avatar_min_width' => true, - 'board_dst' => true, 'board_email_form' => true, 'board_hide_emails' => true, 'board_timezone' => true, @@ -482,17 +476,16 @@ class phpbb_questionnaire_phpbb_data_provider } } - global $db; + global $db, $request; $result['dbms'] = $dbms; $result['acm_type'] = $acm_type; - $result['load_extensions'] = $load_extensions; $result['user_agent'] = 'Unknown'; $result['dbms_version'] = $db->sql_server_info(true); // Try to get user agent vendor and version $match = array(); - $user_agent = (!empty($_SERVER['HTTP_USER_AGENT'])) ? (string) $_SERVER['HTTP_USER_AGENT'] : ''; + $user_agent = $request->header('User-Agent'); $agents = array('firefox', 'msie', 'opera', 'chrome', 'safari', 'mozilla', 'seamonkey', 'konqueror', 'netscape', 'gecko', 'navigator', 'mosaic', 'lynx', 'amaya', 'omniweb', 'avant', 'camino', 'flock', 'aol'); // We check here 1 by 1 because some strings occur after others (for example Mozilla [...] Firefox/) @@ -508,5 +501,3 @@ class phpbb_questionnaire_phpbb_data_provider return $result; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php deleted file mode 100644 index f28b8885e7..0000000000 --- a/phpBB/includes/search/fulltext_mysql.php +++ /dev/null @@ -1,943 +0,0 @@ -<?php -/** -* -* @package search -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* @ignore -*/ -include_once($phpbb_root_path . 'includes/search/search.' . $phpEx); - -/** -* fulltext_mysql -* Fulltext search for MySQL -* @package search -*/ -class fulltext_mysql extends search_backend -{ - var $stats = array(); - var $word_length = array(); - var $split_words = array(); - var $search_query; - var $common_words = array(); - var $pcre_properties = false; - var $mbstring_regex = false; - - function fulltext_mysql(&$error) - { - global $config; - - $this->word_length = array('min' => $config['fulltext_mysql_min_word_len'], 'max' => $config['fulltext_mysql_max_word_len']); - - if (version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) - { - // While this is the proper range of PHP versions, PHP may not be linked with the bundled PCRE lib and instead with an older version - if (@preg_match('/\p{L}/u', 'a') !== false) - { - $this->pcre_properties = true; - } - } - - if (function_exists('mb_ereg')) - { - $this->mbstring_regex = true; - mb_regex_encoding('UTF-8'); - } - - $error = false; - } - - /** - * Checks for correct MySQL version and stores min/max word length in the config - */ - function init() - { - global $db, $user; - - if ($db->sql_layer != 'mysql4' && $db->sql_layer != 'mysqli') - { - return $user->lang['FULLTEXT_MYSQL_INCOMPATIBLE_VERSION']; - } - - $result = $db->sql_query('SHOW TABLE STATUS LIKE \'' . POSTS_TABLE . '\''); - $info = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $engine = ''; - if (isset($info['Engine'])) - { - $engine = $info['Engine']; - } - else if (isset($info['Type'])) - { - $engine = $info['Type']; - } - - $fulltext_supported = - $engine === 'MyISAM' || - // FULLTEXT is supported on InnoDB since MySQL 5.6.4 according to - // http://dev.mysql.com/doc/refman/5.6/en/innodb-storage-engine.html - $engine === 'InnoDB' && - phpbb_version_compare($db->sql_server_info(true), '5.6.4', '>='); - - if (!$fulltext_supported) - { - return $user->lang['FULLTEXT_MYSQL_NOT_SUPPORTED']; - } - - $sql = 'SHOW VARIABLES - LIKE \'ft\_%\''; - $result = $db->sql_query($sql); - - $mysql_info = array(); - while ($row = $db->sql_fetchrow($result)) - { - $mysql_info[$row['Variable_name']] = $row['Value']; - } - $db->sql_freeresult($result); - - set_config('fulltext_mysql_max_word_len', $mysql_info['ft_max_word_len']); - set_config('fulltext_mysql_min_word_len', $mysql_info['ft_min_word_len']); - - return false; - } - - /** - * Splits keywords entered by a user into an array of words stored in $this->split_words - * Stores the tidied search query in $this->search_query - * - * @param string &$keywords Contains the keyword as entered by the user - * @param string $terms is either 'all' or 'any' - * @return bool false if no valid keywords were found and otherwise true - */ - function split_keywords(&$keywords, $terms) - { - global $config, $user; - - if ($terms == 'all') - { - $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#(^|\s)\+#', '#(^|\s)-#', '#(^|\s)\|#'); - $replace = array(' +', ' |', ' -', ' +', ' -', ' |'); - - $keywords = preg_replace($match, $replace, $keywords); - } - - // Filter out as above - $split_keywords = preg_replace("#[\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords))); - - // Split words - if ($this->pcre_properties) - { - $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); - } - else if ($this->mbstring_regex) - { - $split_keywords = mb_ereg_replace('([^\w\'*"()])', '\\1\\1', str_replace('\'\'', '\' \'', trim($split_keywords))); - } - else - { - $split_keywords = preg_replace('#([^\w\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords))); - } - - if ($this->pcre_properties) - { - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches); - $this->split_words = $matches[1]; - } - else if ($this->mbstring_regex) - { - mb_ereg_search_init($split_keywords, '(?:[^\w*"()]|^)([+\-|]?(?:[\w*"()]+\'?)*[\w*"()])(?:[^\w*"()]|$)'); - - while (($word = mb_ereg_search_regs())) - { - $this->split_words[] = $word[1]; - } - } - else - { - $matches = array(); - preg_match_all('#(?:[^\w*"()]|^)([+\-|]?(?:[\w*"()]+\'?)*[\w*"()])(?:[^\w*"()]|$)#u', $split_keywords, $matches); - $this->split_words = $matches[1]; - } - - // We limit the number of allowed keywords to minimize load on the database - if ($config['max_num_search_keywords'] && sizeof($this->split_words) > $config['max_num_search_keywords']) - { - trigger_error($user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', $config['max_num_search_keywords'], sizeof($this->split_words))); - } - - // to allow phrase search, we need to concatenate quoted words - $tmp_split_words = array(); - $phrase = ''; - foreach ($this->split_words as $word) - { - if ($phrase) - { - $phrase .= ' ' . $word; - if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1) - { - $tmp_split_words[] = $phrase; - $phrase = ''; - } - } - else if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1) - { - $phrase = $word; - } - else - { - $tmp_split_words[] = $word . ' '; - } - } - if ($phrase) - { - $tmp_split_words[] = $phrase; - } - - $this->split_words = $tmp_split_words; - - unset($tmp_split_words); - unset($phrase); - - foreach ($this->split_words as $i => $word) - { - $clean_word = preg_replace('#^[+\-|"]#', '', $word); - - // check word length - $clean_len = utf8_strlen(str_replace('*', '', $clean_word)); - if (($clean_len < $config['fulltext_mysql_min_word_len']) || ($clean_len > $config['fulltext_mysql_max_word_len'])) - { - $this->common_words[] = $word; - unset($this->split_words[$i]); - } - } - - if ($terms == 'any') - { - $this->search_query = ''; - foreach ($this->split_words as $word) - { - if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0) || (strpos($word, '|') === 0)) - { - $word = substr($word, 1); - } - $this->search_query .= $word . ' '; - } - } - else - { - $this->search_query = ''; - foreach ($this->split_words as $word) - { - if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0)) - { - $this->search_query .= $word . ' '; - } - else if (strpos($word, '|') === 0) - { - $this->search_query .= substr($word, 1) . ' '; - } - else - { - $this->search_query .= '+' . $word . ' '; - } - } - } - - $this->search_query = utf8_htmlspecialchars($this->search_query); - - if ($this->search_query) - { - $this->split_words = array_values($this->split_words); - sort($this->split_words); - return true; - } - return false; - } - - /** - * Turns text into an array of words - */ - function split_message($text) - { - global $config; - - // Split words - if ($this->pcre_properties) - { - $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); - } - else if ($this->mbstring_regex) - { - $text = mb_ereg_replace('([^\w\'*])', '\\1\\1', str_replace('\'\'', '\' \'', trim($text))); - } - else - { - $text = preg_replace('#([^\w\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text))); - } - - if ($this->pcre_properties) - { - $matches = array(); - preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches); - $text = $matches[1]; - } - else if ($this->mbstring_regex) - { - mb_ereg_search_init($text, '(?:[^\w*]|^)([+\-|]?(?:[\w*]+\'?)*[\w*])(?:[^\w*]|$)'); - - $text = array(); - while (($word = mb_ereg_search_regs())) - { - $text[] = $word[1]; - } - } - else - { - $matches = array(); - preg_match_all('#(?:[^\w*]|^)([+\-|]?(?:[\w*]+\'?)*[\w*])(?:[^\w*]|$)#u', $text, $matches); - $text = $matches[1]; - } - - // remove too short or too long words - $text = array_values($text); - for ($i = 0, $n = sizeof($text); $i < $n; $i++) - { - $text[$i] = trim($text[$i]); - if (utf8_strlen($text[$i]) < $config['fulltext_mysql_min_word_len'] || utf8_strlen($text[$i]) > $config['fulltext_mysql_max_word_len']) - { - unset($text[$i]); - } - } - - return array_values($text); - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first. - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - * - * @access public - */ - function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) - { - global $config, $db; - - // No keywords? No posts. - if (!$this->search_query) - { - return false; - } - - // generate a search_key from all the options to identify the results - $search_key = md5(implode('#', array( - implode(', ', $this->split_words), - $type, - $fields, - $terms, - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - implode(',', $m_approve_fid_ary), - implode(',', $author_ary) - ))); - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - $join_topic = ($type == 'posts') ? false : true; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $join_topic = true; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - // Build some display specific sql strings - switch ($fields) - { - case 'titleonly': - $sql_match = 'p.post_subject'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - case 'msgonly': - $sql_match = 'p.post_text'; - $sql_match_where = ''; - break; - - case 'firstpost': - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ' AND p.post_id = t.topic_first_post_id'; - $join_topic = true; - break; - - default: - $sql_match = 'p.post_subject, p.post_text'; - $sql_match_where = ''; - break; - } - - if (!sizeof($m_approve_fid_ary)) - { - $m_approve_fid_sql = ' AND p.post_approved = 1'; - } - else if ($m_approve_fid_ary === array(-1)) - { - $m_approve_fid_sql = ''; - } - else - { - $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')'; - } - - $sql_select = (!$result_count) ? 'SQL_CALC_FOUND_ROWS ' : ''; - $sql_select = ($type == 'posts') ? $sql_select . 'p.post_id' : 'DISTINCT ' . $sql_select . 't.topic_id'; - $sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : ''; - $field = ($type == 'posts') ? 'post_id' : 'topic_id'; - if (sizeof($author_ary) && $author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = ' AND (' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else if (sizeof($author_ary)) - { - $sql_author = ' AND ' . $db->sql_in_set('p.poster_id', $author_ary); - } - else - { - $sql_author = ''; - } - - $sql_where_options = $sql_sort_join; - $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : ''; - $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : ''; - $sql_where_options .= (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; - $sql_where_options .= $m_approve_fid_sql; - $sql_where_options .= $sql_author; - $sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; - $sql_where_options .= $sql_match_where; - - $sql = "SELECT $sql_select - FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p - WHERE MATCH ($sql_match) AGAINST ('" . $db->sql_escape(htmlspecialchars_decode($this->search_query)) . "' IN BOOLEAN MODE) - $sql_where_options - ORDER BY $sql_sort"; - $result = $db->sql_query_limit($sql, $config['search_block_size'], $start); - - while ($row = $db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $db->sql_freeresult($result); - - $id_ary = array_unique($id_ary); - - if (!sizeof($id_ary)) - { - return false; - } - - // if the total result count is not cached yet, retrieve it from the db - if (!$result_count) - { - $sql = 'SELECT FOUND_ROWS() as result_count'; - $result = $db->sql_query($sql); - $result_count = (int) $db->sql_fetchfield('result_count'); - $db->sql_freeresult($result); - - if (!$result_count) - { - return false; - } - } - - // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page - $this->save_ids($search_key, implode(' ', $this->split_words), $author_ary, $result_count, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $result_count; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - * - * @access public - */ - function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) - { - global $config, $db; - - // No author? No posts. - if (!sizeof($author_ary)) - { - return 0; - } - - // generate a search_key from all the options to identify the results - $search_key = md5(implode('#', array( - '', - $type, - ($firstpost_only) ? 'firstpost' : '', - '', - '', - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - implode(',', $m_approve_fid_ary), - implode(',', $author_ary), - $author_name, - ))); - - // try reading the results from cache - $result_count = 0; - if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $result_count; - } - - $id_ary = array(); - - // Create some display specific sql strings - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $db->sql_in_set('p.poster_id', $author_ary); - } - $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; - $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : ''; - $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; - $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : ''; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster '; - break; - - case 't': - $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : ''; - $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : ''; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - if (!sizeof($m_approve_fid_ary)) - { - $m_approve_fid_sql = ' AND p.post_approved = 1'; - } - else if ($m_approve_fid_ary == array(-1)) - { - $m_approve_fid_sql = ''; - } - else - { - $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')'; - } - - // If the cache was completely empty count the results - $calc_results = ($result_count) ? '' : 'SQL_CALC_FOUND_ROWS '; - - // Build the query for really selecting the post_ids - if ($type == 'posts') - { - $sql = "SELECT {$calc_results}p.post_id - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - $sql_sort_join - $sql_time - ORDER BY $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = "SELECT {$calc_results}t.topic_id - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id - ORDER BY $sql_sort"; - $field = 'topic_id'; - } - - // Only read one block of posts from the db and then cache it - $result = $db->sql_query_limit($sql, $config['search_block_size'], $start); - - while ($row = $db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $db->sql_freeresult($result); - - // retrieve the total result count if needed - if (!$result_count) - { - $sql = 'SELECT FOUND_ROWS() as result_count'; - $result = $db->sql_query($sql); - $result_count = (int) $db->sql_fetchfield('result_count'); - $db->sql_freeresult($result); - - if (!$result_count) - { - return false; - } - } - - if (sizeof($id_ary)) - { - $this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, $per_page); - - return $result_count; - } - return false; - } - - /** - * Destroys cached search results, that contained one of the new words in a post so the results won't be outdated. - * - * @param string $mode contains the post mode: edit, post, reply, quote ... - */ - function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - global $db; - - // Split old and new post/subject to obtain array of words - $split_text = $this->split_message($message); - $split_title = ($subject) ? $this->split_message($subject) : array(); - - $words = array_unique(array_merge($split_text, $split_title)); - - unset($split_text); - unset($split_title); - - // destroy cached search results containing any of the words removed or added - $this->destroy_cache($words, array($poster_id)); - - unset($words); - } - - /** - * Destroy cached results, that might be outdated after deleting a post - */ - function index_remove($post_ids, $author_ids, $forum_ids) - { - $this->destroy_cache(array(), array_unique($author_ids)); - } - - /** - * Destroy old cache entries - */ - function tidy() - { - global $db, $config; - - // destroy too old cached search results - $this->destroy_cache(array()); - - set_config('search_last_gc', time(), true); - } - - /** - * Create fulltext index - */ - function create_index($acp_module, $u_action) - { - global $db; - - // Make sure we can actually use MySQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $alter = array(); - - if (!isset($this->stats['post_subject'])) - { - if ($db->sql_layer == 'mysqli' || version_compare($db->sql_server_info(true), '4.1.3', '>=')) - { - $alter[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL'; - } - else - { - $alter[] = 'MODIFY post_subject text NOT NULL'; - } - $alter[] = 'ADD FULLTEXT (post_subject)'; - } - - if (!isset($this->stats['post_text'])) - { - if ($db->sql_layer == 'mysqli' || version_compare($db->sql_server_info(true), '4.1.3', '>=')) - { - $alter[] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL'; - } - else - { - $alter[] = 'MODIFY post_text mediumtext NOT NULL'; - } - $alter[] = 'ADD FULLTEXT (post_text)'; - } - - if (!isset($this->stats['post_content'])) - { - $alter[] = 'ADD FULLTEXT post_content (post_subject, post_text)'; - } - - if (sizeof($alter)) - { - $db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter)); - } - - $db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); - - return false; - } - - /** - * Drop fulltext index - */ - function delete_index($acp_module, $u_action) - { - global $db; - - // Make sure we can actually use MySQL with fulltext indexes - if ($error = $this->init()) - { - return $error; - } - - if (empty($this->stats)) - { - $this->get_stats(); - } - - $alter = array(); - - if (isset($this->stats['post_subject'])) - { - $alter[] = 'DROP INDEX post_subject'; - } - - if (isset($this->stats['post_text'])) - { - $alter[] = 'DROP INDEX post_text'; - } - - if (isset($this->stats['post_content'])) - { - $alter[] = 'DROP INDEX post_content'; - } - - if (sizeof($alter)) - { - $db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter)); - } - - $db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); - - return false; - } - - /** - * Returns true if both FULLTEXT indexes exist - */ - function index_created() - { - if (empty($this->stats)) - { - $this->get_stats(); - } - - return (isset($this->stats['post_text']) && isset($this->stats['post_subject']) && isset($this->stats['post_content'])) ? true : false; - } - - /** - * Returns an associative array containing information about the indexes - */ - function index_stats() - { - global $user; - - if (empty($this->stats)) - { - $this->get_stats(); - } - - return array( - $user->lang['FULLTEXT_MYSQL_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0, - ); - } - - function get_stats() - { - global $db; - - if (strpos($db->sql_layer, 'mysql') === false) - { - $this->stats = array(); - return; - } - - $sql = 'SHOW INDEX - FROM ' . POSTS_TABLE; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - // deal with older MySQL versions which didn't use Index_type - $index_type = (isset($row['Index_type'])) ? $row['Index_type'] : $row['Comment']; - - if ($index_type == 'FULLTEXT') - { - if ($row['Key_name'] == 'post_text') - { - $this->stats['post_text'] = $row; - } - else if ($row['Key_name'] == 'post_subject') - { - $this->stats['post_subject'] = $row; - } - else if ($row['Key_name'] == 'post_content') - { - $this->stats['post_content'] = $row; - } - } - } - $db->sql_freeresult($result); - - $this->stats['total_posts'] = empty($this->stats) ? 0 : $db->get_estimated_row_count(POSTS_TABLE); - } - - /** - * Display a note, that UTF-8 support is not available with certain versions of PHP - */ - function acp() - { - global $user, $config; - - $tpl = ' - <dl> - <dt><label>' . $user->lang['FULLTEXT_MYSQL_PCRE'] . '</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_PCRE_EXPLAIN'] . '</span></dt> - <dd>' . (($this->pcre_properties) ? $user->lang['YES'] : $user->lang['NO']) . ' (PHP ' . PHP_VERSION . ')</dd> - </dl> - <dl> - <dt><label>' . $user->lang['FULLTEXT_MYSQL_MBSTRING'] . '</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_MBSTRING_EXPLAIN'] . '</span></dt> - <dd>' . (($this->mbstring_regex) ? $user->lang['YES'] : $user->lang['NO']). '</dd> - </dl> - <dl> - <dt><label>' . $user->lang['MIN_SEARCH_CHARS'] . ':</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN'] . '</span></dt> - <dd>' . $config['fulltext_mysql_min_word_len'] . '</dd> - </dl> - <dl> - <dt><label>' . $user->lang['MAX_SEARCH_CHARS'] . ':</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN'] . '</span></dt> - <dd>' . $config['fulltext_mysql_max_word_len'] . '</dd> - </dl> - '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => array() - ); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php deleted file mode 100644 index 948911bbfe..0000000000 --- a/phpBB/includes/search/fulltext_native.php +++ /dev/null @@ -1,1742 +0,0 @@ -<?php -/** -* -* @package search -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* @ignore -*/ -include_once($phpbb_root_path . 'includes/search/search.' . $phpEx); - -/** -* fulltext_native -* phpBB's own db driven fulltext search, version 2 -* @package search -*/ -class fulltext_native extends search_backend -{ - var $stats = array(); - var $word_length = array(); - var $search_query; - var $common_words = array(); - - var $must_contain_ids = array(); - var $must_not_contain_ids = array(); - var $must_exclude_one_ids = array(); - - /** - * Initialises the fulltext_native search backend with min/max word length and makes sure the UTF-8 normalizer is loaded. - * - * @param boolean|string &$error is passed by reference and should either be set to false on success or an error message on failure. - * - * @access public - */ - function fulltext_native(&$error) - { - global $phpbb_root_path, $phpEx, $config; - - $this->word_length = array('min' => $config['fulltext_native_min_chars'], 'max' => $config['fulltext_native_max_chars']); - - /** - * Load the UTF tools - */ - if (!class_exists('utf_normalizer')) - { - include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx); - } - - - $error = false; - } - - /** - * This function fills $this->search_query with the cleaned user search query. - * - * If $terms is 'any' then the words will be extracted from the search query - * and combined with | inside brackets. They will afterwards be treated like - * an standard search query. - * - * Then it analyses the query and fills the internal arrays $must_not_contain_ids, - * $must_contain_ids and $must_exclude_one_ids which are later used by keyword_search(). - * - * @param string $keywords contains the search query string as entered by the user - * @param string $terms is either 'all' (use search query as entered, default words to 'must be contained in post') - * or 'any' (find all posts containing at least one of the given words) - * @return boolean false if no valid keywords were found and otherwise true - * - * @access public - */ - function split_keywords($keywords, $terms) - { - global $db, $user, $config; - - $tokens = '+-|()*'; - - $keywords = trim($this->cleanup($keywords, $tokens)); - - // allow word|word|word without brackets - if ((strpos($keywords, ' ') === false) && (strpos($keywords, '|') !== false) && (strpos($keywords, '(') === false)) - { - $keywords = '(' . $keywords . ')'; - } - - $open_bracket = $space = false; - for ($i = 0, $n = strlen($keywords); $i < $n; $i++) - { - if ($open_bracket !== false) - { - switch ($keywords[$i]) - { - case ')': - if ($open_bracket + 1 == $i) - { - $keywords[$i - 1] = '|'; - $keywords[$i] = '|'; - } - $open_bracket = false; - break; - case '(': - $keywords[$i] = '|'; - break; - case '+': - case '-': - case ' ': - $keywords[$i] = '|'; - break; - case '*': - if ($i === 0 || ($keywords[$i - 1] !== '*' && strcspn($keywords[$i - 1], $tokens) === 0)) - { - if ($i === $n - 1 || ($keywords[$i + 1] !== '*' && strcspn($keywords[$i + 1], $tokens) === 0)) - { - $keywords = substr($keywords, 0, $i) . substr($keywords, $i + 1); - } - } - break; - } - } - else - { - switch ($keywords[$i]) - { - case ')': - $keywords[$i] = ' '; - break; - case '(': - $open_bracket = $i; - $space = false; - break; - case '|': - $keywords[$i] = ' '; - break; - case '-': - case '+': - $space = $keywords[$i]; - break; - case ' ': - if ($space !== false) - { - $keywords[$i] = $space; - } - break; - default: - $space = false; - } - } - } - - if ($open_bracket) - { - $keywords .= ')'; - } - - $match = array( - '# +#', - '#\|\|+#', - '#(\+|\-)(?:\+|\-)+#', - '#\(\|#', - '#\|\)#', - ); - $replace = array( - ' ', - '|', - '$1', - '(', - ')', - ); - - $keywords = preg_replace($match, $replace, $keywords); - $num_keywords = sizeof(explode(' ', $keywords)); - - // We limit the number of allowed keywords to minimize load on the database - if ($config['max_num_search_keywords'] && $num_keywords > $config['max_num_search_keywords']) - { - trigger_error($user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', $config['max_num_search_keywords'], $num_keywords)); - } - - // $keywords input format: each word separated by a space, words in a bracket are not separated - - // the user wants to search for any word, convert the search query - if ($terms == 'any') - { - $words = array(); - - preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $words); - if (sizeof($words[1])) - { - $keywords = '(' . implode('|', $words[1]) . ')'; - } - } - - // set the search_query which is shown to the user - $this->search_query = $keywords; - - $exact_words = array(); - preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words); - $exact_words = $exact_words[1]; - - $common_ids = $words = array(); - - if (sizeof($exact_words)) - { - $sql = 'SELECT word_id, word_text, word_common - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $db->sql_in_set('word_text', $exact_words) . ' - ORDER BY word_count ASC'; - $result = $db->sql_query($sql); - - // store an array of words and ids, remove common words - while ($row = $db->sql_fetchrow($result)) - { - if ($row['word_common']) - { - $this->common_words[] = $row['word_text']; - $common_ids[$row['word_text']] = (int) $row['word_id']; - continue; - } - - $words[$row['word_text']] = (int) $row['word_id']; - } - $db->sql_freeresult($result); - } - - // Handle +, - without preceeding whitespace character - $match = array('#(\S)\+#', '#(\S)-#'); - $replace = array('$1 +', '$1 +'); - - $keywords = preg_replace($match, $replace, $keywords); - - // now analyse the search query, first split it using the spaces - $query = explode(' ', $keywords); - - $this->must_contain_ids = array(); - $this->must_not_contain_ids = array(); - $this->must_exclude_one_ids = array(); - - $mode = ''; - $ignore_no_id = true; - - foreach ($query as $word) - { - if (empty($word)) - { - continue; - } - - // words which should not be included - if ($word[0] == '-') - { - $word = substr($word, 1); - - // a group of which at least one may not be in the resulting posts - if ($word[0] == '(') - { - $word = array_unique(explode('|', substr($word, 1, -1))); - $mode = 'must_exclude_one'; - } - // one word which should not be in the resulting posts - else - { - $mode = 'must_not_contain'; - } - $ignore_no_id = true; - } - // words which have to be included - else - { - // no prefix is the same as a +prefix - if ($word[0] == '+') - { - $word = substr($word, 1); - } - - // a group of words of which at least one word should be in every resulting post - if ($word[0] == '(') - { - $word = array_unique(explode('|', substr($word, 1, -1))); - } - $ignore_no_id = false; - $mode = 'must_contain'; - } - - if (empty($word)) - { - continue; - } - - // if this is an array of words then retrieve an id for each - if (is_array($word)) - { - $non_common_words = array(); - $id_words = array(); - foreach ($word as $i => $word_part) - { - if (strpos($word_part, '*') !== false) - { - $id_words[] = '\'' . $db->sql_escape(str_replace('*', '%', $word_part)) . '\''; - $non_common_words[] = $word_part; - } - else if (isset($words[$word_part])) - { - $id_words[] = $words[$word_part]; - $non_common_words[] = $word_part; - } - else - { - $len = utf8_strlen($word_part); - if ($len < $this->word_length['min'] || $len > $this->word_length['max']) - { - $this->common_words[] = $word_part; - } - } - } - if (sizeof($id_words)) - { - sort($id_words); - if (sizeof($id_words) > 1) - { - $this->{$mode . '_ids'}[] = $id_words; - } - else - { - $mode = ($mode == 'must_exclude_one') ? 'must_not_contain' : $mode; - $this->{$mode . '_ids'}[] = $id_words[0]; - } - } - // throw an error if we shall not ignore unexistant words - else if (!$ignore_no_id && sizeof($non_common_words)) - { - trigger_error(sprintf($user->lang['WORDS_IN_NO_POST'], implode(', ', $non_common_words))); - } - unset($non_common_words); - } - // else we only need one id - else if (($wildcard = strpos($word, '*') !== false) || isset($words[$word])) - { - if ($wildcard) - { - $len = utf8_strlen(str_replace('*', '', $word)); - if ($len >= $this->word_length['min'] && $len <= $this->word_length['max']) - { - $this->{$mode . '_ids'}[] = '\'' . $db->sql_escape(str_replace('*', '%', $word)) . '\''; - } - else - { - $this->common_words[] = $word; - } - } - else - { - $this->{$mode . '_ids'}[] = $words[$word]; - } - } - else - { - if (!isset($common_ids[$word])) - { - $len = utf8_strlen($word); - if ($len < $this->word_length['min'] || $len > $this->word_length['max']) - { - $this->common_words[] = $word; - } - } - } - } - - // Return true if all words are not common words - if (sizeof($exact_words) - sizeof($this->common_words) > 0) - { - return true; - } - return false; - } - - /** - * Performs a search on keywords depending on display specific params. You have to run split_keywords() first. - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - * - * @access public - */ - function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) - { - global $config, $db; - - // No keywords? No posts. - if (empty($this->search_query)) - { - return false; - } - - // we can't search for negatives only - if (empty($this->must_contain_ids)) - { - return false; - } - - $must_contain_ids = $this->must_contain_ids; - $must_not_contain_ids = $this->must_not_contain_ids; - $must_exclude_one_ids = $this->must_exclude_one_ids; - - sort($must_contain_ids); - sort($must_not_contain_ids); - sort($must_exclude_one_ids); - - // generate a search_key from all the options to identify the results - $search_key = md5(implode('#', array( - serialize($must_contain_ids), - serialize($must_not_contain_ids), - serialize($must_exclude_one_ids), - $type, - $fields, - $terms, - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - implode(',', $m_approve_fid_ary), - implode(',', $author_ary), - $author_name, - ))); - - // try reading the results from cache - $total_results = 0; - if ($this->obtain_ids($search_key, $total_results, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $total_results; - } - - $id_ary = array(); - - $sql_where = array(); - $group_by = false; - $m_num = 0; - $w_num = 0; - - $sql_array = array( - 'SELECT' => ($type == 'posts') ? 'p.post_id' : 'p.topic_id', - 'FROM' => array( - SEARCH_WORDMATCH_TABLE => array(), - SEARCH_WORDLIST_TABLE => array(), - ), - 'LEFT_JOIN' => array(array( - 'FROM' => array(POSTS_TABLE => 'p'), - 'ON' => 'm0.post_id = p.post_id', - )), - ); - - $title_match = ''; - $left_join_topics = false; - $group_by = true; - // Build some display specific sql strings - switch ($fields) - { - case 'titleonly': - $title_match = 'title_match = 1'; - $group_by = false; - // no break - case 'firstpost': - $left_join_topics = true; - $sql_where[] = 'p.post_id = t.topic_first_post_id'; - break; - - case 'msgonly': - $title_match = 'title_match = 0'; - $group_by = false; - break; - } - - if ($type == 'topics') - { - $left_join_topics = true; - $group_by = true; - } - - /** - * @todo Add a query optimizer (handle stuff like "+(4|3) +4") - */ - - foreach ($this->must_contain_ids as $subquery) - { - if (is_array($subquery)) - { - $group_by = true; - - $word_id_sql = array(); - $word_ids = array(); - foreach ($subquery as $id) - { - if (is_string($id)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num), - 'ON' => "w$w_num.word_text LIKE $id" - ); - $word_ids[] = "w$w_num.word_id"; - - $w_num++; - } - else - { - $word_ids[] = $id; - } - } - - $sql_where[] = $db->sql_in_set("m$m_num.word_id", $word_ids); - - unset($word_id_sql); - unset($word_ids); - } - else if (is_string($subquery)) - { - $sql_array['FROM'][SEARCH_WORDLIST_TABLE][] = 'w' . $w_num; - - $sql_where[] = "w$w_num.word_text LIKE $subquery"; - $sql_where[] = "m$m_num.word_id = w$w_num.word_id"; - - $group_by = true; - $w_num++; - } - else - { - $sql_where[] = "m$m_num.word_id = $subquery"; - } - - $sql_array['FROM'][SEARCH_WORDMATCH_TABLE][] = 'm' . $m_num; - - if ($title_match) - { - $sql_where[] = "m$m_num.$title_match"; - } - - if ($m_num != 0) - { - $sql_where[] = "m$m_num.post_id = m0.post_id"; - } - $m_num++; - } - - foreach ($this->must_not_contain_ids as $key => $subquery) - { - if (is_string($subquery)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num), - 'ON' => "w$w_num.word_text LIKE $subquery" - ); - - $this->must_not_contain_ids[$key] = "w$w_num.word_id"; - - $group_by = true; - $w_num++; - } - } - - if (sizeof($this->must_not_contain_ids)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num), - 'ON' => $db->sql_in_set("m$m_num.word_id", $this->must_not_contain_ids) . (($title_match) ? " AND m$m_num.$title_match" : '') . " AND m$m_num.post_id = m0.post_id" - ); - - $sql_where[] = "m$m_num.word_id IS NULL"; - $m_num++; - } - - foreach ($this->must_exclude_one_ids as $ids) - { - $is_null_joins = array(); - foreach ($ids as $id) - { - if (is_string($id)) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num), - 'ON' => "w$w_num.word_text LIKE $id" - ); - $id = "w$w_num.word_id"; - - $group_by = true; - $w_num++; - } - - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num), - 'ON' => "m$m_num.word_id = $id AND m$m_num.post_id = m0.post_id" . (($title_match) ? " AND m$m_num.$title_match" : '') - ); - $is_null_joins[] = "m$m_num.word_id IS NULL"; - - $m_num++; - } - $sql_where[] = '(' . implode(' OR ', $is_null_joins) . ')'; - } - - if (!sizeof($m_approve_fid_ary)) - { - $sql_where[] = 'p.post_approved = 1'; - } - else if ($m_approve_fid_ary !== array(-1)) - { - $sql_where[] = '(p.post_approved = 1 OR ' . $db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')'; - } - - if ($topic_id) - { - $sql_where[] = 'p.topic_id = ' . $topic_id; - } - - if (sizeof($author_ary)) - { - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $db->sql_in_set('p.poster_id', $author_ary); - } - $sql_where[] = $sql_author; - } - - if (sizeof($ex_fid_ary)) - { - $sql_where[] = $db->sql_in_set('p.forum_id', $ex_fid_ary, true); - } - - if ($sort_days) - { - $sql_where[] = 'p.post_time >= ' . (time() - ($sort_days * 86400)); - } - - $sql_array['WHERE'] = implode(' AND ', $sql_where); - - $is_mysql = false; - // if the total result count is not cached yet, retrieve it from the db - if (!$total_results) - { - $sql = ''; - $sql_array_count = $sql_array; - - if ($left_join_topics) - { - $sql_array_count['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_TABLE => 't'), - 'ON' => 'p.topic_id = t.topic_id' - ); - } - - switch ($db->sql_layer) - { - case 'mysql4': - case 'mysqli': - - // 3.x does not support SQL_CALC_FOUND_ROWS - // $sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT']; - $is_mysql = true; - - break; - - case 'sqlite': - $sql_array_count['SELECT'] = ($type == 'posts') ? 'DISTINCT p.post_id' : 'DISTINCT p.topic_id'; - $sql = 'SELECT COUNT(' . (($type == 'posts') ? 'post_id' : 'topic_id') . ') as total_results - FROM (' . $db->sql_build_query('SELECT', $sql_array_count) . ')'; - - // no break - - default: - $sql_array_count['SELECT'] = ($type == 'posts') ? 'COUNT(DISTINCT p.post_id) AS total_results' : 'COUNT(DISTINCT p.topic_id) AS total_results'; - $sql = (!$sql) ? $db->sql_build_query('SELECT', $sql_array_count) : $sql; - - $result = $db->sql_query($sql); - $total_results = (int) $db->sql_fetchfield('total_results'); - $db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - break; - } - - unset($sql_array_count, $sql); - } - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - - switch ($sql_sort[0]) - { - case 'u': - $sql_array['FROM'][USERS_TABLE] = 'u'; - $sql_where[] = 'u.user_id = p.poster_id '; - break; - - case 't': - $left_join_topics = true; - break; - - case 'f': - $sql_array['FROM'][FORUMS_TABLE] = 'f'; - $sql_where[] = 'f.forum_id = p.forum_id'; - break; - } - - if ($left_join_topics) - { - $sql_array['LEFT_JOIN'][] = array( - 'FROM' => array(TOPICS_TABLE => 't'), - 'ON' => 'p.topic_id = t.topic_id' - ); - } - - $sql_array['WHERE'] = implode(' AND ', $sql_where); - $sql_array['GROUP_BY'] = ($group_by) ? (($type == 'posts') ? 'p.post_id' : 'p.topic_id') . ', ' . $sort_by_sql[$sort_key] : ''; - $sql_array['ORDER_BY'] = $sql_sort; - - unset($sql_where, $sql_sort, $group_by); - - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query_limit($sql, $config['search_block_size'], $start); - - while ($row = $db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[(($type == 'posts') ? 'post_id' : 'topic_id')]; - } - $db->sql_freeresult($result); - - if (!sizeof($id_ary)) - { - return false; - } - - // if we use mysql and the total result count is not cached yet, retrieve it from the db - if (!$total_results && $is_mysql) - { - // Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it. - $sql_array_copy = $sql_array; - $sql_array_copy['SELECT'] = 'SQL_CALC_FOUND_ROWS p.post_id '; - - $sql = $db->sql_build_query('SELECT', $sql_array_copy); - unset($sql_array_copy); - - $db->sql_query($sql); - $db->sql_freeresult($result); - - $sql = 'SELECT FOUND_ROWS() as total_results'; - $result = $db->sql_query($sql); - $total_results = (int) $db->sql_fetchfield('total_results'); - $db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - } - - // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page - $this->save_ids($search_key, $this->search_query, $author_ary, $total_results, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, (int) $per_page); - - return $total_results; - } - - /** - * Performs a search on an author's posts without caring about message contents. Depends on display specific params - * - * @param string $type contains either posts or topics depending on what should be searched for - * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string $sort_key is the key of $sort_by_sql for the selected sorting - * @param string $sort_dir is either a or d representing ASC and DESC - * @param string $sort_days specifies the maximum amount of days a post may be old - * @param array $ex_fid_ary specifies an array of forum ids which should not be searched - * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts - * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array $author_ary an array of author ids - * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return boolean|int total number of results - * - * @access public - */ - function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) - { - global $config, $db; - - // No author? No posts. - if (!sizeof($author_ary)) - { - return 0; - } - - // generate a search_key from all the options to identify the results - $search_key = md5(implode('#', array( - '', - $type, - ($firstpost_only) ? 'firstpost' : '', - '', - '', - $sort_days, - $sort_key, - $topic_id, - implode(',', $ex_fid_ary), - implode(',', $m_approve_fid_ary), - implode(',', $author_ary), - $author_name, - ))); - - // try reading the results from cache - $total_results = 0; - if ($this->obtain_ids($search_key, $total_results, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE) - { - return $total_results; - } - - $id_ary = array(); - - // Create some display specific sql strings - if ($author_name) - { - // first one matches post of registered users, second one guests and deleted users - $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; - } - else - { - $sql_author = $db->sql_in_set('p.poster_id', $author_ary); - } - $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; - $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; - $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : ''; - $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : ''; - - // Build sql strings for sorting - $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); - $sql_sort_table = $sql_sort_join = ''; - switch ($sql_sort[0]) - { - case 'u': - $sql_sort_table = USERS_TABLE . ' u, '; - $sql_sort_join = ' AND u.user_id = p.poster_id '; - break; - - case 't': - $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : ''; - $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : ''; - break; - - case 'f': - $sql_sort_table = FORUMS_TABLE . ' f, '; - $sql_sort_join = ' AND f.forum_id = p.forum_id '; - break; - } - - if (!sizeof($m_approve_fid_ary)) - { - $m_approve_fid_sql = ' AND p.post_approved = 1'; - } - else if ($m_approve_fid_ary == array(-1)) - { - $m_approve_fid_sql = ''; - } - else - { - $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')'; - } - - $select = ($type == 'posts') ? 'p.post_id' : 't.topic_id'; - $is_mysql = false; - - // If the cache was completely empty count the results - if (!$total_results) - { - switch ($db->sql_layer) - { - case 'mysql4': - case 'mysqli': -// $select = 'SQL_CALC_FOUND_ROWS ' . $select; - $is_mysql = true; - break; - - default: - if ($type == 'posts') - { - $sql = 'SELECT COUNT(p.post_id) as total_results - FROM ' . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - $sql_time"; - } - else - { - if ($db->sql_layer == 'sqlite') - { - $sql = 'SELECT COUNT(topic_id) as total_results - FROM (SELECT DISTINCT t.topic_id'; - } - else - { - $sql = 'SELECT COUNT(DISTINCT t.topic_id) as total_results'; - } - - $sql .= ' FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - AND t.topic_id = p.topic_id - $sql_time" . (($db->sql_layer == 'sqlite') ? ')' : ''); - } - $result = $db->sql_query($sql); - - $total_results = (int) $db->sql_fetchfield('total_results'); - $db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - break; - } - } - - // Build the query for really selecting the post_ids - if ($type == 'posts') - { - $sql = "SELECT $select - FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t' : '') . " - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - $sql_sort_join - $sql_time - ORDER BY $sql_sort"; - $field = 'post_id'; - } - else - { - $sql = "SELECT $select - FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p - WHERE $sql_author - $sql_topic_id - $sql_firstpost - $m_approve_fid_sql - $sql_fora - AND t.topic_id = p.topic_id - $sql_sort_join - $sql_time - GROUP BY t.topic_id, " . $sort_by_sql[$sort_key] . ' - ORDER BY ' . $sql_sort; - $field = 'topic_id'; - } - - // Only read one block of posts from the db and then cache it - $result = $db->sql_query_limit($sql, $config['search_block_size'], $start); - - while ($row = $db->sql_fetchrow($result)) - { - $id_ary[] = (int) $row[$field]; - } - $db->sql_freeresult($result); - - if (!$total_results && $is_mysql) - { - // Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it. - $sql = str_replace('SELECT ' . $select, 'SELECT DISTINCT SQL_CALC_FOUND_ROWS p.post_id', $sql); - - $db->sql_query($sql); - $db->sql_freeresult($result); - - $sql = 'SELECT FOUND_ROWS() as total_results'; - $result = $db->sql_query($sql); - $total_results = (int) $db->sql_fetchfield('total_results'); - $db->sql_freeresult($result); - - if (!$total_results) - { - return false; - } - } - - if (sizeof($id_ary)) - { - $this->save_ids($search_key, '', $author_ary, $total_results, $id_ary, $start, $sort_dir); - $id_ary = array_slice($id_ary, 0, $per_page); - - return $total_results; - } - return false; - } - - /** - * Split a text into words of a given length - * - * The text is converted to UTF-8, cleaned up, and split. Then, words that - * conform to the defined length range are returned in an array. - * - * NOTE: duplicates are NOT removed from the return array - * - * @param string $text Text to split, encoded in UTF-8 - * @return array Array of UTF-8 words - * - * @access private - */ - function split_message($text) - { - global $phpbb_root_path, $phpEx, $user; - - $match = $words = array(); - - /** - * Taken from the original code - */ - // Do not index code - $match[] = '#\[code(?:=.*?)?(\:?[0-9a-z]{5,})\].*?\[\/code(\:?[0-9a-z]{5,})\]#is'; - // BBcode - $match[] = '#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?[0-9a-z]{5,})\]#'; - - $min = $this->word_length['min']; - $max = $this->word_length['max']; - - $isset_min = $min - 1; - - /** - * Clean up the string, remove HTML tags, remove BBCodes - */ - $word = strtok($this->cleanup(preg_replace($match, ' ', strip_tags($text)), -1), ' '); - - while (strlen($word)) - { - if (strlen($word) > 255 || strlen($word) <= $isset_min) - { - /** - * Words longer than 255 bytes are ignored. This will have to be - * changed whenever we change the length of search_wordlist.word_text - * - * Words shorter than $isset_min bytes are ignored, too - */ - $word = strtok(' '); - continue; - } - - $len = utf8_strlen($word); - - /** - * Test whether the word is too short to be indexed. - * - * Note that this limit does NOT apply to CJK and Hangul - */ - if ($len < $min) - { - /** - * Note: this could be optimized. If the codepoint is lower than Hangul's range - * we know that it will also be lower than CJK ranges - */ - if ((strncmp($word, UTF8_HANGUL_FIRST, 3) < 0 || strncmp($word, UTF8_HANGUL_LAST, 3) > 0) - && (strncmp($word, UTF8_CJK_FIRST, 3) < 0 || strncmp($word, UTF8_CJK_LAST, 3) > 0) - && (strncmp($word, UTF8_CJK_B_FIRST, 4) < 0 || strncmp($word, UTF8_CJK_B_LAST, 4) > 0)) - { - $word = strtok(' '); - continue; - } - } - - $words[] = $word; - $word = strtok(' '); - } - - return $words; - } - - /** - * Updates wordlist and wordmatch tables when a message is posted or changed - * - * @param string $mode Contains the post mode: edit, post, reply, quote - * @param int $post_id The id of the post which is modified/created - * @param string &$message New or updated post content - * @param string &$subject New or updated post subject - * @param int $poster_id Post author's user id - * @param int $forum_id The id of the forum in which the post is located - * - * @access public - */ - function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) - { - global $config, $db, $user; - - if (!$config['fulltext_native_load_upd']) - { - /** - * The search indexer is disabled, return - */ - return; - } - - // Split old and new post/subject to obtain array of 'words' - $split_text = $this->split_message($message); - $split_title = $this->split_message($subject); - - $cur_words = array('post' => array(), 'title' => array()); - - $words = array(); - if ($mode == 'edit') - { - $words['add']['post'] = array(); - $words['add']['title'] = array(); - $words['del']['post'] = array(); - $words['del']['title'] = array(); - - $sql = 'SELECT w.word_id, w.word_text, m.title_match - FROM ' . SEARCH_WORDLIST_TABLE . ' w, ' . SEARCH_WORDMATCH_TABLE . " m - WHERE m.post_id = $post_id - AND w.word_id = m.word_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $which = ($row['title_match']) ? 'title' : 'post'; - $cur_words[$which][$row['word_text']] = $row['word_id']; - } - $db->sql_freeresult($result); - - $words['add']['post'] = array_diff($split_text, array_keys($cur_words['post'])); - $words['add']['title'] = array_diff($split_title, array_keys($cur_words['title'])); - $words['del']['post'] = array_diff(array_keys($cur_words['post']), $split_text); - $words['del']['title'] = array_diff(array_keys($cur_words['title']), $split_title); - } - else - { - $words['add']['post'] = $split_text; - $words['add']['title'] = $split_title; - $words['del']['post'] = array(); - $words['del']['title'] = array(); - } - unset($split_text); - unset($split_title); - - // Get unique words from the above arrays - $unique_add_words = array_unique(array_merge($words['add']['post'], $words['add']['title'])); - - // We now have unique arrays of all words to be added and removed and - // individual arrays of added and removed words for text and title. What - // we need to do now is add the new words (if they don't already exist) - // and then add (or remove) matches between the words and this post - if (sizeof($unique_add_words)) - { - $sql = 'SELECT word_id, word_text - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $db->sql_in_set('word_text', $unique_add_words); - $result = $db->sql_query($sql); - - $word_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $word_ids[$row['word_text']] = $row['word_id']; - } - $db->sql_freeresult($result); - $new_words = array_diff($unique_add_words, array_keys($word_ids)); - - $db->sql_transaction('begin'); - if (sizeof($new_words)) - { - $sql_ary = array(); - - foreach ($new_words as $word) - { - $sql_ary[] = array('word_text' => (string) $word, 'word_count' => 0); - } - $db->sql_return_on_error(true); - $db->sql_multi_insert(SEARCH_WORDLIST_TABLE, $sql_ary); - $db->sql_return_on_error(false); - } - unset($new_words, $sql_ary); - } - else - { - $db->sql_transaction('begin'); - } - - // now update the search match table, remove links to removed words and add links to new words - foreach ($words['del'] as $word_in => $word_ary) - { - $title_match = ($word_in == 'title') ? 1 : 0; - - if (sizeof($word_ary)) - { - $sql_in = array(); - foreach ($word_ary as $word) - { - $sql_in[] = $cur_words[$word_in][$word]; - } - - $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' - WHERE ' . $db->sql_in_set('word_id', $sql_in) . ' - AND post_id = ' . intval($post_id) . " - AND title_match = $title_match"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count - 1 - WHERE ' . $db->sql_in_set('word_id', $sql_in) . ' - AND word_count > 0'; - $db->sql_query($sql); - - unset($sql_in); - } - } - - $db->sql_return_on_error(true); - foreach ($words['add'] as $word_in => $word_ary) - { - $title_match = ($word_in == 'title') ? 1 : 0; - - if (sizeof($word_ary)) - { - $sql = 'INSERT INTO ' . SEARCH_WORDMATCH_TABLE . ' (post_id, word_id, title_match) - SELECT ' . (int) $post_id . ', word_id, ' . (int) $title_match . ' - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $db->sql_in_set('word_text', $word_ary); - $db->sql_query($sql); - - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count + 1 - WHERE ' . $db->sql_in_set('word_text', $word_ary); - $db->sql_query($sql); - } - } - $db->sql_return_on_error(false); - - $db->sql_transaction('commit'); - - // destroy cached search results containing any of the words removed or added - $this->destroy_cache(array_unique(array_merge($words['add']['post'], $words['add']['title'], $words['del']['post'], $words['del']['title'])), array($poster_id)); - - unset($unique_add_words); - unset($words); - unset($cur_words); - } - - /** - * Removes entries from the wordmatch table for the specified post_ids - */ - function index_remove($post_ids, $author_ids, $forum_ids) - { - global $db; - - if (sizeof($post_ids)) - { - $sql = 'SELECT w.word_id, w.word_text, m.title_match - FROM ' . SEARCH_WORDMATCH_TABLE . ' m, ' . SEARCH_WORDLIST_TABLE . ' w - WHERE ' . $db->sql_in_set('m.post_id', $post_ids) . ' - AND w.word_id = m.word_id'; - $result = $db->sql_query($sql); - - $message_word_ids = $title_word_ids = $word_texts = array(); - while ($row = $db->sql_fetchrow($result)) - { - if ($row['title_match']) - { - $title_word_ids[] = $row['word_id']; - } - else - { - $message_word_ids[] = $row['word_id']; - } - $word_texts[] = $row['word_text']; - } - $db->sql_freeresult($result); - - if (sizeof($title_word_ids)) - { - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count - 1 - WHERE ' . $db->sql_in_set('word_id', $title_word_ids) . ' - AND word_count > 0'; - $db->sql_query($sql); - } - - if (sizeof($message_word_ids)) - { - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_count = word_count - 1 - WHERE ' . $db->sql_in_set('word_id', $message_word_ids) . ' - AND word_count > 0'; - $db->sql_query($sql); - } - - unset($title_word_ids); - unset($message_word_ids); - - $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); - } - - $this->destroy_cache(array_unique($word_texts), array_unique($author_ids)); - } - - /** - * Tidy up indexes: Tag 'common words' and remove - * words no longer referenced in the match table - */ - function tidy() - { - global $db, $config; - - // Is the fulltext indexer disabled? If yes then we need not - // carry on ... it's okay ... I know when I'm not wanted boo hoo - if (!$config['fulltext_native_load_upd']) - { - set_config('search_last_gc', time(), true); - return; - } - - $destroy_cache_words = array(); - - // Remove common words - if ($config['num_posts'] >= 100 && $config['fulltext_native_common_thres']) - { - $common_threshold = ((double) $config['fulltext_native_common_thres']) / 100.0; - // First, get the IDs of common words - $sql = 'SELECT word_id, word_text - FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE word_count > ' . floor($config['num_posts'] * $common_threshold) . ' - OR word_common = 1'; - $result = $db->sql_query($sql); - - $sql_in = array(); - while ($row = $db->sql_fetchrow($result)) - { - $sql_in[] = $row['word_id']; - $destroy_cache_words[] = $row['word_text']; - } - $db->sql_freeresult($result); - - if (sizeof($sql_in)) - { - // Flag the words - $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' - SET word_common = 1 - WHERE ' . $db->sql_in_set('word_id', $sql_in); - $db->sql_query($sql); - - // by setting search_last_gc to the new time here we make sure that if a user reloads because the - // following query takes too long, he won't run into it again - set_config('search_last_gc', time(), true); - - // Delete the matches - $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' - WHERE ' . $db->sql_in_set('word_id', $sql_in); - $db->sql_query($sql); - } - unset($sql_in); - } - - if (sizeof($destroy_cache_words)) - { - // destroy cached search results containing any of the words that are now common or were removed - $this->destroy_cache(array_unique($destroy_cache_words)); - } - - set_config('search_last_gc', time(), true); - } - - /** - * Deletes all words from the index - */ - function delete_index($acp_module, $u_action) - { - global $db; - - switch ($db->sql_layer) - { - case 'sqlite': - case 'firebird': - $db->sql_query('DELETE FROM ' . SEARCH_WORDLIST_TABLE); - $db->sql_query('DELETE FROM ' . SEARCH_WORDMATCH_TABLE); - $db->sql_query('DELETE FROM ' . SEARCH_RESULTS_TABLE); - break; - - default: - $db->sql_query('TRUNCATE TABLE ' . SEARCH_WORDLIST_TABLE); - $db->sql_query('TRUNCATE TABLE ' . SEARCH_WORDMATCH_TABLE); - $db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); - break; - } - } - - /** - * Returns true if both FULLTEXT indexes exist - */ - function index_created() - { - if (!sizeof($this->stats)) - { - $this->get_stats(); - } - - return ($this->stats['total_words'] && $this->stats['total_matches']) ? true : false; - } - - /** - * Returns an associative array containing information about the indexes - */ - function index_stats() - { - global $user; - - if (!sizeof($this->stats)) - { - $this->get_stats(); - } - - return array( - $user->lang['TOTAL_WORDS'] => $this->stats['total_words'], - $user->lang['TOTAL_MATCHES'] => $this->stats['total_matches']); - } - - function get_stats() - { - global $db; - - $this->stats['total_words'] = $db->get_estimated_row_count(SEARCH_WORDLIST_TABLE); - $this->stats['total_matches'] = $db->get_estimated_row_count(SEARCH_WORDMATCH_TABLE); - } - - /** - * Clean up a text to remove non-alphanumeric characters - * - * This method receives a UTF-8 string, normalizes and validates it, replaces all - * non-alphanumeric characters with strings then returns the result. - * - * Any number of "allowed chars" can be passed as a UTF-8 string in NFC. - * - * @param string $text Text to split, in UTF-8 (not normalized or sanitized) - * @param string $allowed_chars String of special chars to allow - * @param string $encoding Text encoding - * @return string Cleaned up text, only alphanumeric chars are left - * - * @todo normalizer::cleanup being able to be used? - */ - function cleanup($text, $allowed_chars = null, $encoding = 'utf-8') - { - global $phpbb_root_path, $phpEx; - static $conv = array(), $conv_loaded = array(); - $words = $allow = array(); - - // Convert the text to UTF-8 - $encoding = strtolower($encoding); - if ($encoding != 'utf-8') - { - $text = utf8_recode($text, $encoding); - } - - $utf_len_mask = array( - "\xC0" => 2, - "\xD0" => 2, - "\xE0" => 3, - "\xF0" => 4 - ); - - /** - * Replace HTML entities and NCRs - */ - $text = htmlspecialchars_decode(utf8_decode_ncr($text), ENT_QUOTES); - - /** - * Load the UTF-8 normalizer - * - * If we use it more widely, an instance of that class should be held in a - * a global variable instead - */ - utf_normalizer::nfc($text); - - /** - * The first thing we do is: - * - * - convert ASCII-7 letters to lowercase - * - remove the ASCII-7 non-alpha characters - * - remove the bytes that should not appear in a valid UTF-8 string: 0xC0, - * 0xC1 and 0xF5-0xFF - * - * @todo in theory, the third one is already taken care of during normalization and those chars should have been replaced by Unicode replacement chars - */ - $sb_match = "ISTCPAMELRDOJBNHFGVWUQKYXZ\r\n\t!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\xC0\xC1\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"; - $sb_replace = 'istcpamelrdojbnhfgvwuqkyxz '; - - /** - * This is the list of legal ASCII chars, it is automatically extended - * with ASCII chars from $allowed_chars - */ - $legal_ascii = ' eaisntroludcpmghbfvq10xy2j9kw354867z'; - - /** - * Prepare an array containing the extra chars to allow - */ - if (isset($allowed_chars[0])) - { - $pos = 0; - $len = strlen($allowed_chars); - do - { - $c = $allowed_chars[$pos]; - - if ($c < "\x80") - { - /** - * ASCII char - */ - $sb_pos = strpos($sb_match, $c); - if (is_int($sb_pos)) - { - /** - * Remove the char from $sb_match and its corresponding - * replacement in $sb_replace - */ - $sb_match = substr($sb_match, 0, $sb_pos) . substr($sb_match, $sb_pos + 1); - $sb_replace = substr($sb_replace, 0, $sb_pos) . substr($sb_replace, $sb_pos + 1); - $legal_ascii .= $c; - } - - ++$pos; - } - else - { - /** - * UTF-8 char - */ - $utf_len = $utf_len_mask[$c & "\xF0"]; - $allow[substr($allowed_chars, $pos, $utf_len)] = 1; - $pos += $utf_len; - } - } - while ($pos < $len); - } - - $text = strtr($text, $sb_match, $sb_replace); - $ret = ''; - - $pos = 0; - $len = strlen($text); - - do - { - /** - * Do all consecutive ASCII chars at once - */ - if ($spn = strspn($text, $legal_ascii, $pos)) - { - $ret .= substr($text, $pos, $spn); - $pos += $spn; - } - - if ($pos >= $len) - { - return $ret; - } - - /** - * Capture the UTF char - */ - $utf_len = $utf_len_mask[$text[$pos] & "\xF0"]; - $utf_char = substr($text, $pos, $utf_len); - $pos += $utf_len; - - if (($utf_char >= UTF8_HANGUL_FIRST && $utf_char <= UTF8_HANGUL_LAST) - || ($utf_char >= UTF8_CJK_FIRST && $utf_char <= UTF8_CJK_LAST) - || ($utf_char >= UTF8_CJK_B_FIRST && $utf_char <= UTF8_CJK_B_LAST)) - { - /** - * All characters within these ranges are valid - * - * We separate them with a space in order to index each character - * individually - */ - $ret .= ' ' . $utf_char . ' '; - continue; - } - - if (isset($allow[$utf_char])) - { - /** - * The char is explicitly allowed - */ - $ret .= $utf_char; - continue; - } - - if (isset($conv[$utf_char])) - { - /** - * The char is mapped to something, maybe to itself actually - */ - $ret .= $conv[$utf_char]; - continue; - } - - /** - * The char isn't mapped, but did we load its conversion table? - * - * The search indexer table is split into blocks. The block number of - * each char is equal to its codepoint right-shifted for 11 bits. It - * means that out of the 11, 16 or 21 meaningful bits of a 2-, 3- or - * 4- byte sequence we only keep the leftmost 0, 5 or 10 bits. Thus, - * all UTF chars encoded in 2 bytes are in the same first block. - */ - if (isset($utf_char[2])) - { - if (isset($utf_char[3])) - { - /** - * 1111 0nnn 10nn nnnn 10nx xxxx 10xx xxxx - * 0000 0111 0011 1111 0010 0000 - */ - $idx = ((ord($utf_char[0]) & 0x07) << 7) | ((ord($utf_char[1]) & 0x3F) << 1) | ((ord($utf_char[2]) & 0x20) >> 5); - } - else - { - /** - * 1110 nnnn 10nx xxxx 10xx xxxx - * 0000 0111 0010 0000 - */ - $idx = ((ord($utf_char[0]) & 0x07) << 1) | ((ord($utf_char[1]) & 0x20) >> 5); - } - } - else - { - /** - * 110x xxxx 10xx xxxx - * 0000 0000 0000 0000 - */ - $idx = 0; - } - - /** - * Check if the required conv table has been loaded already - */ - if (!isset($conv_loaded[$idx])) - { - $conv_loaded[$idx] = 1; - $file = $phpbb_root_path . 'includes/utf/data/search_indexer_' . $idx . '.' . $phpEx; - - if (file_exists($file)) - { - $conv += include($file); - } - } - - if (isset($conv[$utf_char])) - { - $ret .= $conv[$utf_char]; - } - else - { - /** - * We add an entry to the conversion table so that we - * don't have to convert to codepoint and perform the checks - * that are above this block - */ - $conv[$utf_char] = ' '; - $ret .= ' '; - } - } - while (1); - - return $ret; - } - - /** - * Returns a list of options for the ACP to display - */ - function acp() - { - global $user, $config; - - - /** - * if we need any options, copied from fulltext_native for now, will have to be adjusted or removed - */ - - $tpl = ' - <dl> - <dt><label for="fulltext_native_load_upd">' . $user->lang['YES_SEARCH_UPDATE'] . ':</label><br /><span>' . $user->lang['YES_SEARCH_UPDATE_EXPLAIN'] . '</span></dt> - <dd><label><input type="radio" id="fulltext_native_load_upd" name="config[fulltext_native_load_upd]" value="1"' . (($config['fulltext_native_load_upd']) ? ' checked="checked"' : '') . ' class="radio" /> ' . $user->lang['YES'] . '</label><label><input type="radio" name="config[fulltext_native_load_upd]" value="0"' . ((!$config['fulltext_native_load_upd']) ? ' checked="checked"' : '') . ' class="radio" /> ' . $user->lang['NO'] . '</label></dd> - </dl> - <dl> - <dt><label for="fulltext_native_min_chars">' . $user->lang['MIN_SEARCH_CHARS'] . ':</label><br /><span>' . $user->lang['MIN_SEARCH_CHARS_EXPLAIN'] . '</span></dt> - <dd><input id="fulltext_native_min_chars" type="text" size="3" maxlength="3" name="config[fulltext_native_min_chars]" value="' . (int) $config['fulltext_native_min_chars'] . '" /></dd> - </dl> - <dl> - <dt><label for="fulltext_native_max_chars">' . $user->lang['MAX_SEARCH_CHARS'] . ':</label><br /><span>' . $user->lang['MAX_SEARCH_CHARS_EXPLAIN'] . '</span></dt> - <dd><input id="fulltext_native_max_chars" type="text" size="3" maxlength="3" name="config[fulltext_native_max_chars]" value="' . (int) $config['fulltext_native_max_chars'] . '" /></dd> - </dl> - <dl> - <dt><label for="fulltext_native_common_thres">' . $user->lang['COMMON_WORD_THRESHOLD'] . ':</label><br /><span>' . $user->lang['COMMON_WORD_THRESHOLD_EXPLAIN'] . '</span></dt> - <dd><input id="fulltext_native_common_thres" type="text" size="3" maxlength="3" name="config[fulltext_native_common_thres]" value="' . (double) $config['fulltext_native_common_thres'] . '" /> %</dd> - </dl> - '; - - // These are fields required in the config table - return array( - 'tpl' => $tpl, - 'config' => array('fulltext_native_load_upd' => 'bool', 'fulltext_native_min_chars' => 'integer:0:255', 'fulltext_native_max_chars' => 'integer:0:255', 'fulltext_native_common_thres' => 'double:0:100') - ); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/search/index.htm b/phpBB/includes/search/index.htm deleted file mode 100644 index ee1f723a7d..0000000000 --- a/phpBB/includes/search/index.htm +++ /dev/null @@ -1,10 +0,0 @@ -<html> -<head> -<title></title> -<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> -</head> - -<body bgcolor="#FFFFFF" text="#000000"> - -</body> -</html> diff --git a/phpBB/includes/search/search.php b/phpBB/includes/search/search.php deleted file mode 100644 index df7c8a0892..0000000000 --- a/phpBB/includes/search/search.php +++ /dev/null @@ -1,320 +0,0 @@ -<?php -/** -* -* @package search -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* @ignore -*/ -define('SEARCH_RESULT_NOT_IN_CACHE', 0); -define('SEARCH_RESULT_IN_CACHE', 1); -define('SEARCH_RESULT_INCOMPLETE', 2); - -/** -* search_backend -* optional base class for search plugins providing simple caching based on ACM -* and functions to retrieve ignore_words and synonyms -* @package search -*/ -class search_backend -{ - var $ignore_words = array(); - var $match_synonym = array(); - var $replace_synonym = array(); - - function search_backend(&$error) - { - // This class cannot be used as a search plugin - $error = true; - } - - /** - * Retrieves a language dependend list of words that should be ignored by the search - */ - function get_ignore_words() - { - if (!sizeof($this->ignore_words)) - { - global $user, $phpEx; - - $words = array(); - - if (file_exists("{$user->lang_path}{$user->lang_name}/search_ignore_words.$phpEx")) - { - // include the file containing ignore words - include("{$user->lang_path}{$user->lang_name}/search_ignore_words.$phpEx"); - } - - $this->ignore_words = $words; - unset($words); - } - } - - /** - * Stores a list of synonyms that should be replaced in $this->match_synonym and $this->replace_synonym and caches them - */ - function get_synonyms() - { - if (!sizeof($this->match_synonym)) - { - global $user, $phpEx; - - $synonyms = array(); - - if (file_exists("{$user->lang_path}{$user->lang_name}/search_synonyms.$phpEx")) - { - // include the file containing synonyms - include("{$user->lang_path}{$user->lang_name}/search_synonyms.$phpEx"); - } - - $this->match_synonym = array_keys($synonyms); - $this->replace_synonym = array_values($synonyms); - - unset($synonyms); - } - } - - /** - * Retrieves cached search results - * - * @param int &$result_count will contain the number of all results for the search (not only for the current page) - * @param array &$id_ary is filled with the ids belonging to the requested page that are stored in the cache - * - * @return int SEARCH_RESULT_NOT_IN_CACHE or SEARCH_RESULT_IN_CACHE or SEARCH_RESULT_INCOMPLETE - */ - function obtain_ids($search_key, &$result_count, &$id_ary, $start, $per_page, $sort_dir) - { - global $cache; - - if (!($stored_ids = $cache->get('_search_results_' . $search_key))) - { - // no search results cached for this search_key - return SEARCH_RESULT_NOT_IN_CACHE; - } - else - { - $result_count = $stored_ids[-1]; - $reverse_ids = ($stored_ids[-2] != $sort_dir) ? true : false; - $complete = true; - - // change the start to the actual end of the current request if the sort direction differs - // from the dirction in the cache and reverse the ids later - if ($reverse_ids) - { - $start = $result_count - $start - $per_page; - - // the user requested a page past the last index - if ($start < 0) - { - return SEARCH_RESULT_NOT_IN_CACHE; - } - } - - for ($i = $start, $n = $start + $per_page; ($i < $n) && ($i < $result_count); $i++) - { - if (!isset($stored_ids[$i])) - { - $complete = false; - } - else - { - $id_ary[] = $stored_ids[$i]; - } - } - unset($stored_ids); - - if ($reverse_ids) - { - $id_ary = array_reverse($id_ary); - } - - if (!$complete) - { - return SEARCH_RESULT_INCOMPLETE; - } - return SEARCH_RESULT_IN_CACHE; - } - } - - /** - * Caches post/topic ids - * - * @param array &$id_ary contains a list of post or topic ids that shall be cached, the first element - * must have the absolute index $start in the result set. - */ - function save_ids($search_key, $keywords, $author_ary, $result_count, &$id_ary, $start, $sort_dir) - { - global $cache, $config, $db, $user; - - $length = min(sizeof($id_ary), $config['search_block_size']); - - // nothing to cache so exit - if (!$length) - { - return; - } - - $store_ids = array_slice($id_ary, 0, $length); - - // create a new resultset if there is none for this search_key yet - // or add the ids to the existing resultset - if (!($store = $cache->get('_search_results_' . $search_key))) - { - // add the current keywords to the recent searches in the cache which are listed on the search page - if (!empty($keywords) || sizeof($author_ary)) - { - $sql = 'SELECT search_time - FROM ' . SEARCH_RESULTS_TABLE . ' - WHERE search_key = \'' . $db->sql_escape($search_key) . '\''; - $result = $db->sql_query($sql); - - if (!$db->sql_fetchrow($result)) - { - $sql_ary = array( - 'search_key' => $search_key, - 'search_time' => time(), - 'search_keywords' => $keywords, - 'search_authors' => ' ' . implode(' ', $author_ary) . ' ' - ); - - $sql = 'INSERT INTO ' . SEARCH_RESULTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - } - $db->sql_freeresult($result); - } - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_last_search = ' . time() . ' - WHERE user_id = ' . $user->data['user_id']; - $db->sql_query($sql); - - $store = array(-1 => $result_count, -2 => $sort_dir); - $id_range = range($start, $start + $length - 1); - } - else - { - // we use one set of results for both sort directions so we have to calculate the indizes - // for the reversed array and we also have to reverse the ids themselves - if ($store[-2] != $sort_dir) - { - $store_ids = array_reverse($store_ids); - $id_range = range($store[-1] - $start - $length, $store[-1] - $start - 1); - } - else - { - $id_range = range($start, $start + $length - 1); - } - } - - $store_ids = array_combine($id_range, $store_ids); - - // append the ids - if (is_array($store_ids)) - { - $store += $store_ids; - - // if the cache is too big - if (sizeof($store) - 2 > 20 * $config['search_block_size']) - { - // remove everything in front of two blocks in front of the current start index - for ($i = 0, $n = $id_range[0] - 2 * $config['search_block_size']; $i < $n; $i++) - { - if (isset($store[$i])) - { - unset($store[$i]); - } - } - - // remove everything after two blocks after the current stop index - end($id_range); - for ($i = $store[-1] - 1, $n = current($id_range) + 2 * $config['search_block_size']; $i > $n; $i--) - { - if (isset($store[$i])) - { - unset($store[$i]); - } - } - } - $cache->put('_search_results_' . $search_key, $store, $config['search_store_results']); - - $sql = 'UPDATE ' . SEARCH_RESULTS_TABLE . ' - SET search_time = ' . time() . ' - WHERE search_key = \'' . $db->sql_escape($search_key) . '\''; - $db->sql_query($sql); - } - - unset($store); - unset($store_ids); - unset($id_range); - } - - /** - * Removes old entries from the search results table and removes searches with keywords that contain a word in $words. - */ - function destroy_cache($words, $authors = false) - { - global $db, $cache, $config; - - // clear all searches that searched for the specified words - if (sizeof($words)) - { - $sql_where = ''; - foreach ($words as $word) - { - $sql_where .= " OR search_keywords " . $db->sql_like_expression($db->any_char . $word . $db->any_char); - } - - $sql = 'SELECT search_key - FROM ' . SEARCH_RESULTS_TABLE . " - WHERE search_keywords LIKE '%*%' $sql_where"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $cache->destroy('_search_results_' . $row['search_key']); - } - $db->sql_freeresult($result); - } - - // clear all searches that searched for the specified authors - if (is_array($authors) && sizeof($authors)) - { - $sql_where = ''; - foreach ($authors as $author) - { - $sql_where .= (($sql_where) ? ' OR ' : '') . 'search_authors ' . $db->sql_like_expression($db->any_char . ' ' . (int) $author . ' ' . $db->any_char); - } - - $sql = 'SELECT search_key - FROM ' . SEARCH_RESULTS_TABLE . " - WHERE $sql_where"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $cache->destroy('_search_results_' . $row['search_key']); - } - $db->sql_freeresult($result); - } - - $sql = 'DELETE - FROM ' . SEARCH_RESULTS_TABLE . ' - WHERE search_time < ' . (time() - $config['search_store_results']); - $db->sql_query($sql); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php deleted file mode 100644 index 04b15b17d3..0000000000 --- a/phpBB/includes/session.php +++ /dev/null @@ -1,2473 +0,0 @@ -<?php -/** -* -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Session class -* @package phpBB3 -*/ -class session -{ - var $cookie_data = array(); - var $page = array(); - var $data = array(); - var $browser = ''; - var $forwarded_for = ''; - var $host = ''; - var $session_id = ''; - var $ip = ''; - var $load = 0; - var $time_now = 0; - var $update_session_page = true; - - /** - * Extract current session page - * - * @param string $root_path current root path (phpbb_root_path) - */ - function extract_current_page($root_path) - { - $page_array = array(); - - // First of all, get the request uri... - $script_name = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : getenv('PHP_SELF'); - $args = (!empty($_SERVER['QUERY_STRING'])) ? explode('&', $_SERVER['QUERY_STRING']) : explode('&', getenv('QUERY_STRING')); - - // If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support... - if (!$script_name) - { - $script_name = (!empty($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : getenv('REQUEST_URI'); - $script_name = (($pos = strpos($script_name, '?')) !== false) ? substr($script_name, 0, $pos) : $script_name; - $page_array['failover'] = 1; - } - - // Replace backslashes and doubled slashes (could happen on some proxy setups) - $script_name = str_replace(array('\\', '//'), '/', $script_name); - - // Now, remove the sid and let us get a clean query string... - $use_args = array(); - - // Since some browser do not encode correctly we need to do this with some "special" characters... - // " -> %22, ' => %27, < -> %3C, > -> %3E - $find = array('"', "'", '<', '>'); - $replace = array('%22', '%27', '%3C', '%3E'); - - foreach ($args as $key => $argument) - { - if (strpos($argument, 'sid=') === 0) - { - continue; - } - - $use_args[] = str_replace($find, $replace, $argument); - } - unset($args); - - // The following examples given are for an request uri of {path to the phpbb directory}/adm/index.php?i=10&b=2 - - // The current query string - $query_string = trim(implode('&', $use_args)); - - // basenamed page name (for example: index.php) - $page_name = (substr($script_name, -1, 1) == '/') ? '' : basename($script_name); - $page_name = urlencode(htmlspecialchars($page_name)); - - // current directory within the phpBB root (for example: adm) - $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($root_path))); - $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./'))); - $intersection = array_intersect_assoc($root_dirs, $page_dirs); - - $root_dirs = array_diff_assoc($root_dirs, $intersection); - $page_dirs = array_diff_assoc($page_dirs, $intersection); - - $page_dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs); - - if ($page_dir && substr($page_dir, -1, 1) == '/') - { - $page_dir = substr($page_dir, 0, -1); - } - - // Current page from phpBB root (for example: adm/index.php?i=10&b=2) - $page = (($page_dir) ? $page_dir . '/' : '') . $page_name . (($query_string) ? "?$query_string" : ''); - - // The script path from the webroot to the current directory (for example: /phpBB3/adm/) : always prefixed with / and ends in / - $script_path = trim(str_replace('\\', '/', dirname($script_name))); - - // The script path from the webroot to the phpBB root (for example: /phpBB3/) - $script_dirs = explode('/', $script_path); - array_splice($script_dirs, -sizeof($page_dirs)); - $root_script_path = implode('/', $script_dirs) . (sizeof($root_dirs) ? '/' . implode('/', $root_dirs) : ''); - - // We are on the base level (phpBB root == webroot), lets adjust the variables a bit... - if (!$root_script_path) - { - $root_script_path = ($page_dir) ? str_replace($page_dir, '', $script_path) : $script_path; - } - - $script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/'; - $root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/'; - - $forum_id = (isset($_REQUEST['f']) && $_REQUEST['f'] > 0 && $_REQUEST['f'] < 16777215) ? (int) $_REQUEST['f'] : 0; - - $page_array += array( - 'page_name' => $page_name, - 'page_dir' => $page_dir, - - 'query_string' => $query_string, - 'script_path' => str_replace(' ', '%20', htmlspecialchars($script_path)), - 'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)), - - 'page' => $page, - 'forum' => $forum_id, - ); - - return $page_array; - } - - /** - * Get valid hostname/port. HTTP_HOST is used, SERVER_NAME if HTTP_HOST not present. - */ - function extract_current_hostname() - { - global $config; - - // Get hostname - $host = (!empty($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : ((!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME')); - - // Should be a string and lowered - $host = (string) strtolower($host); - - // If host is equal the cookie domain or the server name (if config is set), then we assume it is valid - if ((isset($config['cookie_domain']) && $host === $config['cookie_domain']) || (isset($config['server_name']) && $host === $config['server_name'])) - { - return $host; - } - - // Is the host actually a IP? If so, we use the IP... (IPv4) - if (long2ip(ip2long($host)) === $host) - { - return $host; - } - - // Now return the hostname (this also removes any port definition). The http:// is prepended to construct a valid URL, hosts never have a scheme assigned - $host = @parse_url('http://' . $host); - $host = (!empty($host['host'])) ? $host['host'] : ''; - - // Remove any portions not removed by parse_url (#) - $host = str_replace('#', '', $host); - - // If, by any means, the host is now empty, we will use a "best approach" way to guess one - if (empty($host)) - { - if (!empty($config['server_name'])) - { - $host = $config['server_name']; - } - else if (!empty($config['cookie_domain'])) - { - $host = (strpos($config['cookie_domain'], '.') === 0) ? substr($config['cookie_domain'], 1) : $config['cookie_domain']; - } - else - { - // Set to OS hostname or localhost - $host = (function_exists('php_uname')) ? php_uname('n') : 'localhost'; - } - } - - // It may be still no valid host, but for sure only a hostname (we may further expand on the cookie domain... if set) - return $host; - } - - /** - * Start session management - * - * This is where all session activity begins. We gather various pieces of - * information from the client and server. We test to see if a session already - * exists. If it does, fine and dandy. If it doesn't we'll go on to create a - * new one ... pretty logical heh? We also examine the system load (if we're - * running on a system which makes such information readily available) and - * halt if it's above an admin definable limit. - * - * @param bool $update_session_page if true the session page gets updated. - * This can be set to circumvent certain scripts to update the users last visited page. - */ - function session_begin($update_session_page = true) - { - global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path; - - // Give us some basic information - $this->time_now = time(); - $this->cookie_data = array('u' => 0, 'k' => ''); - $this->update_session_page = $update_session_page; - $this->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : ''; - $this->referer = (!empty($_SERVER['HTTP_REFERER'])) ? htmlspecialchars((string) $_SERVER['HTTP_REFERER']) : ''; - $this->forwarded_for = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? htmlspecialchars((string) $_SERVER['HTTP_X_FORWARDED_FOR']) : ''; - - $this->host = $this->extract_current_hostname(); - $this->page = $this->extract_current_page($phpbb_root_path); - - // if the forwarded for header shall be checked we have to validate its contents - if ($config['forwarded_for_check']) - { - $this->forwarded_for = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->forwarded_for)); - - // split the list of IPs - $ips = explode(' ', $this->forwarded_for); - foreach ($ips as $ip) - { - // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly - if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) - { - // contains invalid data, don't use the forwarded for header - $this->forwarded_for = ''; - break; - } - } - } - else - { - $this->forwarded_for = ''; - } - - if (isset($_COOKIE[$config['cookie_name'] . '_sid']) || isset($_COOKIE[$config['cookie_name'] . '_u'])) - { - $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true); - $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true); - $this->session_id = request_var($config['cookie_name'] . '_sid', '', false, true); - - $SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid='; - $_SID = (defined('NEED_SID')) ? $this->session_id : ''; - - if (empty($this->session_id)) - { - $this->session_id = $_SID = request_var('sid', ''); - $SID = '?sid=' . $this->session_id; - $this->cookie_data = array('u' => 0, 'k' => ''); - } - } - else - { - $this->session_id = $_SID = request_var('sid', ''); - $SID = '?sid=' . $this->session_id; - } - - $_EXTRA_URL = array(); - - // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests - // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. - $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? (string) $_SERVER['REMOTE_ADDR'] : ''; - $this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip)); - - // split the list of IPs - $ips = explode(' ', trim($this->ip)); - - // Default IP if REMOTE_ADDR is invalid - $this->ip = '127.0.0.1'; - - foreach ($ips as $ip) - { - if (preg_match(get_preg_expression('ipv4'), $ip)) - { - $this->ip = $ip; - } - else if (preg_match(get_preg_expression('ipv6'), $ip)) - { - // Quick check for IPv4-mapped address in IPv6 - if (stripos($ip, '::ffff:') === 0) - { - $ipv4 = substr($ip, 7); - - if (preg_match(get_preg_expression('ipv4'), $ipv4)) - { - $ip = $ipv4; - } - } - - $this->ip = $ip; - } - else - { - // We want to use the last valid address in the chain - // Leave foreach loop when address is invalid - break; - } - } - - $this->load = false; - - // Load limit check (if applicable) - if ($config['limit_load'] || $config['limit_search_load']) - { - if ((function_exists('sys_getloadavg') && $load = sys_getloadavg()) || ($load = explode(' ', @file_get_contents('/proc/loadavg')))) - { - $this->load = array_slice($load, 0, 1); - $this->load = floatval($this->load[0]); - } - else - { - set_config('limit_load', '0'); - set_config('limit_search_load', '0'); - } - } - - // if no session id is set, redirect to index.php - if (defined('NEED_SID') && (!isset($_GET['sid']) || $this->session_id !== $_GET['sid'])) - { - send_status_line(401, 'Unauthorized'); - redirect(append_sid("{$phpbb_root_path}index.$phpEx")); - } - - // if session id is set - if (!empty($this->session_id)) - { - $sql = 'SELECT u.*, s.* - FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u - WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "' - AND u.user_id = s.session_user_id"; - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Did the session exist in the DB? - if (isset($this->data['user_id'])) - { - // Validate IP length according to admin ... enforces an IP - // check on bots if admin requires this -// $quadcheck = ($config['ip_check_bot'] && $this->data['user_type'] & USER_BOT) ? 4 : $config['ip_check']; - - if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false) - { - $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']); - $u_ip = short_ipv6($this->ip, $config['ip_check']); - } - else - { - $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); - $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); - } - - $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : ''; - $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : ''; - - $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; - $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : ''; - - // referer checks - // The @ before $config['referer_validation'] suppresses notices present while running the updater - $check_referer_path = (@$config['referer_validation'] == REFERER_VALIDATE_PATH); - $referer_valid = true; - - // we assume HEAD and TRACE to be foul play and thus only whitelist GET - if (@$config['referer_validation'] && isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) !== 'get') - { - $referer_valid = $this->validate_referer($check_referer_path); - } - - if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for && $referer_valid) - { - $session_expired = false; - - // Check whether the session is still valid if we have one - $method = basename(trim($config['auth_method'])); - include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); - - $method = 'validate_session_' . $method; - if (function_exists($method)) - { - if (!$method($this->data)) - { - $session_expired = true; - } - } - - if (!$session_expired) - { - // Check the session length timeframe if autologin is not enabled. - // Else check the autologin length... and also removing those having autologin enabled but no longer allowed board-wide. - if (!$this->data['session_autologin']) - { - if ($this->data['session_time'] < $this->time_now - ($config['session_length'] + 60)) - { - $session_expired = true; - } - } - else if (!$config['allow_autologin'] || ($config['max_autologin_time'] && $this->data['session_time'] < $this->time_now - (86400 * (int) $config['max_autologin_time']) + 60)) - { - $session_expired = true; - } - } - - if (!$session_expired) - { - // Only update session DB a minute or so after last update or if page changes - if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) - { - $sql_ary = array('session_time' => $this->time_now); - - if ($this->update_session_page) - { - $sql_ary['session_page'] = substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - } - - $db->sql_return_on_error(true); - - $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE session_id = '" . $db->sql_escape($this->session_id) . "'"; - $result = $db->sql_query($sql); - - $db->sql_return_on_error(false); - - // If the database is not yet updated, there will be an error due to the session_forum_id - // @todo REMOVE for 3.0.2 - if ($result === false) - { - unset($sql_ary['session_forum_id']); - - $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE session_id = '" . $db->sql_escape($this->session_id) . "'"; - $db->sql_query($sql); - } - - if ($this->data['user_id'] != ANONYMOUS && !empty($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts']) - { - $this->leave_newly_registered(); - } - } - - $this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; - $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false; - $this->data['user_lang'] = basename($this->data['user_lang']); - - return true; - } - } - else - { - // Added logging temporarly to help debug bugs... - if (defined('DEBUG_EXTRA') && $this->data['user_id'] != ANONYMOUS) - { - if ($referer_valid) - { - add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for)); - } - else - { - add_log('critical', 'LOG_REFERER_INVALID', $this->referer); - } - } - } - } - } - - // If we reach here then no (valid) session exists. So we'll create a new one - return $this->session_create(); - } - - /** - * Create a new session - * - * If upon trying to start a session we discover there is nothing existing we - * jump here. Additionally this method is called directly during login to regenerate - * the session for the specific user. In this method we carry out a number of tasks; - * garbage collection, (search)bot checking, banned user comparison. Basically - * though this method will result in a new session for a specific user. - */ - function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true) - { - global $SID, $_SID, $db, $config, $cache, $phpbb_root_path, $phpEx; - - $this->data = array(); - - /* Garbage collection ... remove old sessions updating user information - // if necessary. It means (potentially) 11 queries but only infrequently - if ($this->time_now > $config['session_last_gc'] + $config['session_gc']) - { - $this->session_gc(); - }*/ - - // Do we allow autologin on this board? No? Then override anything - // that may be requested here - if (!$config['allow_autologin']) - { - $this->cookie_data['k'] = $persist_login = false; - } - - /** - * Here we do a bot check, oh er saucy! No, not that kind of bot - * check. We loop through the list of bots defined by the admin and - * see if we have any useragent and/or IP matches. If we do, this is a - * bot, act accordingly - */ - $bot = false; - $active_bots = $cache->obtain_bots(); - - foreach ($active_bots as $row) - { - if ($row['bot_agent'] && preg_match('#' . str_replace('\*', '.*?', preg_quote($row['bot_agent'], '#')) . '#i', $this->browser)) - { - $bot = $row['user_id']; - } - - // If ip is supplied, we will make sure the ip is matching too... - if ($row['bot_ip'] && ($bot || !$row['bot_agent'])) - { - // Set bot to false, then we only have to set it to true if it is matching - $bot = false; - - foreach (explode(',', $row['bot_ip']) as $bot_ip) - { - $bot_ip = trim($bot_ip); - - if (!$bot_ip) - { - continue; - } - - if (strpos($this->ip, $bot_ip) === 0) - { - $bot = (int) $row['user_id']; - break; - } - } - } - - if ($bot) - { - break; - } - } - - $method = basename(trim($config['auth_method'])); - include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); - - $method = 'autologin_' . $method; - if (function_exists($method)) - { - $user_data = $method(); - - if ($user_id === false || (isset($user_data['user_id']) && $user_id == $user_data['user_id'])) - { - $this->data = $user_data; - } - - if (sizeof($this->data)) - { - $this->cookie_data['k'] = ''; - $this->cookie_data['u'] = $this->data['user_id']; - } - } - - // If we're presented with an autologin key we'll join against it. - // Else if we've been passed a user_id we'll grab data based on that - if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data)) - { - $sql = 'SELECT u.* - FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k - WHERE u.user_id = ' . (int) $this->cookie_data['u'] . ' - AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ") - AND k.user_id = u.user_id - AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; - $result = $db->sql_query($sql); - $user_data = $db->sql_fetchrow($result); - - if ($user_id === false || (isset($user_data['user_id']) && $user_id == $user_data['user_id'])) - { - $this->data = $user_data; - $bot = false; - } - - $db->sql_freeresult($result); - } - - if ($user_id !== false && !sizeof($this->data)) - { - $this->cookie_data['k'] = ''; - $this->cookie_data['u'] = $user_id; - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $this->cookie_data['u'] . ' - AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - $bot = false; - } - - // Bot user, if they have a SID in the Request URI we need to get rid of it - // otherwise they'll index this page with the SID, duplicate content oh my! - if ($bot && isset($_GET['sid'])) - { - send_status_line(301, 'Moved Permanently'); - redirect(build_url(array('sid'))); - } - - // If no data was returned one or more of the following occurred: - // Key didn't match one in the DB - // User does not exist - // User is inactive - // User is bot - if (!sizeof($this->data) || !is_array($this->data)) - { - $this->cookie_data['k'] = ''; - $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS; - - if (!$bot) - { - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $this->cookie_data['u']; - } - else - { - // We give bots always the same session if it is not yet expired. - $sql = 'SELECT u.*, s.* - FROM ' . USERS_TABLE . ' u - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) - WHERE u.user_id = ' . (int) $bot; - } - - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - if ($this->data['user_id'] != ANONYMOUS && !$bot) - { - $this->data['session_last_visit'] = (isset($this->data['session_time']) && $this->data['session_time']) ? $this->data['session_time'] : (($this->data['user_lastvisit']) ? $this->data['user_lastvisit'] : time()); - } - else - { - $this->data['session_last_visit'] = $this->time_now; - } - - // Force user id to be integer... - $this->data['user_id'] = (int) $this->data['user_id']; - - // At this stage we should have a filled data array, defined cookie u and k data. - // data array should contain recent session info if we're a real user and a recent - // session exists in which case session_id will also be set - - // Is user banned? Are they excluded? Won't return on ban, exists within method - if ($this->data['user_type'] != USER_FOUNDER) - { - if (!$config['forwarded_for_check']) - { - $this->check_ban($this->data['user_id'], $this->ip); - } - else - { - $ips = explode(' ', $this->forwarded_for); - $ips[] = $this->ip; - $this->check_ban($this->data['user_id'], $ips); - } - } - - $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; - $this->data['is_bot'] = ($bot) ? true : false; - - // If our friend is a bot, we re-assign a previously assigned session - if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id']) - { - // Only assign the current session if the ip, browser and forwarded_for match... - if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false) - { - $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']); - $u_ip = short_ipv6($this->ip, $config['ip_check']); - } - else - { - $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); - $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); - } - - $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : ''; - $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : ''; - - $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; - $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : ''; - - if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for) - { - $this->session_id = $this->data['session_id']; - - // Only update session DB a minute or so after last update or if page changes - if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) - { - $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now; - - $sql_ary = array('session_time' => $this->time_now, 'session_last_visit' => $this->time_now, 'session_admin' => 0); - - if ($this->update_session_page) - { - $sql_ary['session_page'] = substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - } - - $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE session_id = '" . $db->sql_escape($this->session_id) . "'"; - $db->sql_query($sql); - - // Update the last visit time - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $this->data['session_time'] . ' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - } - - $SID = '?sid='; - $_SID = ''; - return true; - } - else - { - // If the ip and browser does not match make sure we only have one bot assigned to one session - $db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']); - } - } - - $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false; - $set_admin = ($set_admin && $this->data['is_registered']) ? true : false; - - // Create or update the session - $sql_ary = array( - 'session_user_id' => (int) $this->data['user_id'], - 'session_start' => (int) $this->time_now, - 'session_last_visit' => (int) $this->data['session_last_visit'], - 'session_time' => (int) $this->time_now, - 'session_browser' => (string) trim(substr($this->browser, 0, 149)), - 'session_forwarded_for' => (string) $this->forwarded_for, - 'session_ip' => (string) $this->ip, - 'session_autologin' => ($session_autologin) ? 1 : 0, - 'session_admin' => ($set_admin) ? 1 : 0, - 'session_viewonline' => ($viewonline) ? 1 : 0, - ); - - if ($this->update_session_page) - { - $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - } - - $db->sql_return_on_error(true); - - $sql = 'DELETE - FROM ' . SESSIONS_TABLE . ' - WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\' - AND session_user_id = ' . ANONYMOUS; - - if (!defined('IN_ERROR_HANDLER') && (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows())) - { - // Limit new sessions in 1 minute period (if required) - if (empty($this->data['session_time']) && $config['active_sessions']) - { -// $db->sql_return_on_error(false); - - $sql = 'SELECT COUNT(session_id) AS sessions - FROM ' . SESSIONS_TABLE . ' - WHERE session_time >= ' . ($this->time_now - 60); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ((int) $row['sessions'] > (int) $config['active_sessions']) - { - send_status_line(503, 'Service Unavailable'); - trigger_error('BOARD_UNAVAILABLE'); - } - } - } - - // Since we re-create the session id here, the inserted row must be unique. Therefore, we display potential errors. - // Commented out because it will not allow forums to update correctly -// $db->sql_return_on_error(false); - - // Something quite important: session_page always holds the *last* page visited, except for the *first* visit. - // We are not able to simply have an empty session_page btw, therefore we need to tell phpBB how to detect this special case. - // If the session id is empty, we have a completely new one and will set an "identifier" here. This identifier is able to be checked later. - if (empty($this->data['session_id'])) - { - // This is a temporary variable, only set for the very first visit - $this->data['session_created'] = true; - } - - $this->session_id = $this->data['session_id'] = md5(unique_id()); - - $sql_ary['session_id'] = (string) $this->session_id; - $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199); - $sql_ary['session_forum_id'] = $this->page['forum']; - - $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - $db->sql_query($sql); - - $db->sql_return_on_error(false); - - // Regenerate autologin/persistent login key - if ($session_autologin) - { - $this->set_login_key(); - } - - // refresh data - $SID = '?sid=' . $this->session_id; - $_SID = $this->session_id; - $this->data = array_merge($this->data, $sql_ary); - - if (!$bot) - { - $cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000); - - $this->set_cookie('u', $this->cookie_data['u'], $cookie_expire); - $this->set_cookie('k', $this->cookie_data['k'], $cookie_expire); - $this->set_cookie('sid', $this->session_id, $cookie_expire); - - unset($cookie_expire); - - $sql = 'SELECT COUNT(session_id) AS sessions - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . (int) $this->data['user_id'] . ' - AND session_time >= ' . (int) ($this->time_now - (max($config['session_length'], $config['form_token_lifetime']))); - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ((int) $row['sessions'] <= 1 || empty($this->data['user_form_salt'])) - { - $this->data['user_form_salt'] = unique_id(); - // Update the form key - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - } - } - else - { - $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now; - - // Update the last visit time - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $this->data['session_time'] . ' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - - $SID = '?sid='; - $_SID = ''; - } - - return true; - } - - /** - * Kills a session - * - * This method does what it says on the tin. It will delete a pre-existing session. - * It resets cookie information (destroying any autologin key within that cookie data) - * and update the users information from the relevant session data. It will then - * grab guest user information. - */ - function session_kill($new_session = true) - { - global $SID, $_SID, $db, $config, $phpbb_root_path, $phpEx; - - $sql = 'DELETE FROM ' . SESSIONS_TABLE . " - WHERE session_id = '" . $db->sql_escape($this->session_id) . "' - AND session_user_id = " . (int) $this->data['user_id']; - $db->sql_query($sql); - - // Allow connecting logout with external auth method logout - $method = basename(trim($config['auth_method'])); - include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); - - $method = 'logout_' . $method; - if (function_exists($method)) - { - $method($this->data, $new_session); - } - - if ($this->data['user_id'] != ANONYMOUS) - { - // Delete existing session, update last visit info first! - if (!isset($this->data['session_time'])) - { - $this->data['session_time'] = time(); - } - - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $this->data['session_time'] . ' - WHERE user_id = ' . (int) $this->data['user_id']; - $db->sql_query($sql); - - if ($this->cookie_data['k']) - { - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $this->data['user_id'] . " - AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; - $db->sql_query($sql); - } - - // Reset the data array - $this->data = array(); - - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . ANONYMOUS; - $result = $db->sql_query($sql); - $this->data = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - $cookie_expire = $this->time_now - 31536000; - $this->set_cookie('u', '', $cookie_expire); - $this->set_cookie('k', '', $cookie_expire); - $this->set_cookie('sid', '', $cookie_expire); - unset($cookie_expire); - - $SID = '?sid='; - $this->session_id = $_SID = ''; - - // To make sure a valid session is created we create one for the anonymous user - if ($new_session) - { - $this->session_create(ANONYMOUS); - } - - return true; - } - - /** - * Session garbage collection - * - * This looks a lot more complex than it really is. Effectively we are - * deleting any sessions older than an admin definable limit. Due to the - * way in which we maintain session data we have to ensure we update user - * data before those sessions are destroyed. In addition this method - * removes autologin key information that is older than an admin defined - * limit. - */ - function session_gc() - { - global $db, $config, $phpbb_root_path, $phpEx; - - $batch_size = 10; - - if (!$this->time_now) - { - $this->time_now = time(); - } - - // Firstly, delete guest sessions - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . ANONYMOUS . ' - AND session_time < ' . (int) ($this->time_now - $config['session_length']); - $db->sql_query($sql); - - // Get expired sessions, only most recent for each user - $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time - FROM ' . SESSIONS_TABLE . ' - WHERE session_time < ' . ($this->time_now - $config['session_length']) . ' - GROUP BY session_user_id, session_page'; - $result = $db->sql_query_limit($sql, $batch_size); - - $del_user_id = array(); - $del_sessions = 0; - - while ($row = $db->sql_fetchrow($result)) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' - WHERE user_id = " . (int) $row['session_user_id']; - $db->sql_query($sql); - - $del_user_id[] = (int) $row['session_user_id']; - $del_sessions++; - } - $db->sql_freeresult($result); - - if (sizeof($del_user_id)) - { - // Delete expired sessions - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . ' - AND session_time < ' . ($this->time_now - $config['session_length']); - $db->sql_query($sql); - } - - if ($del_sessions < $batch_size) - { - // Less than 10 users, update gc timer ... else we want gc - // called again to delete other sessions - set_config('session_last_gc', $this->time_now, true); - - if ($config['max_autologin_time']) - { - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time'])); - $db->sql_query($sql); - } - - // only called from CRON; should be a safe workaround until the infrastructure gets going - if (!class_exists('phpbb_captcha_factory')) - { - include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx); - } - phpbb_captcha_factory::garbage_collect($config['captcha_plugin']); - - $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' - WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']); - $db->sql_query($sql); - } - - return; - } - - /** - * Sets a cookie - * - * Sets a cookie of the given name with the specified data for the given length of time. If no time is specified, a session cookie will be set. - * - * @param string $name Name of the cookie, will be automatically prefixed with the phpBB cookie name. track becomes [cookie_name]_track then. - * @param string $cookiedata The data to hold within the cookie - * @param int $cookietime The expiration time as UNIX timestamp. If 0 is provided, a session cookie is set. - */ - function set_cookie($name, $cookiedata, $cookietime) - { - global $config; - - $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata); - $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime); - $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == '127.0.0.1' || strpos($config['cookie_domain'], '.') === false) ? '' : '; domain=' . $config['cookie_domain']; - - header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false); - } - - /** - * Check for banned user - * - * Checks whether the supplied user is banned by id, ip or email. If no parameters - * are passed to the method pre-existing session data is used. If $return is false - * this routine does not return on finding a banned user, it outputs a relevant - * message and stops execution. - * - * @param string|array $user_ips Can contain a string with one IP or an array of multiple IPs - */ - function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false) - { - global $config, $db; - - if (defined('IN_CHECK_BAN')) - { - return; - } - - $banned = false; - $cache_ttl = 3600; - $where_sql = array(); - - $sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end - FROM ' . BANLIST_TABLE . ' - WHERE '; - - // Determine which entries to check, only return those - if ($user_email === false) - { - $where_sql[] = "ban_email = ''"; - } - - if ($user_ips === false) - { - $where_sql[] = "(ban_ip = '' OR ban_exclude = 1)"; - } - - if ($user_id === false) - { - $where_sql[] = '(ban_userid = 0 OR ban_exclude = 1)'; - } - else - { - $cache_ttl = ($user_id == ANONYMOUS) ? 3600 : 0; - $_sql = '(ban_userid = ' . $user_id; - - if ($user_email !== false) - { - $_sql .= " OR ban_email <> ''"; - } - - if ($user_ips !== false) - { - $_sql .= " OR ban_ip <> ''"; - } - - $_sql .= ')'; - - $where_sql[] = $_sql; - } - - $sql .= (sizeof($where_sql)) ? implode(' AND ', $where_sql) : ''; - $result = $db->sql_query($sql, $cache_ttl); - - $ban_triggered_by = 'user'; - while ($row = $db->sql_fetchrow($result)) - { - if ($row['ban_end'] && $row['ban_end'] < time()) - { - continue; - } - - $ip_banned = false; - if (!empty($row['ban_ip'])) - { - if (!is_array($user_ips)) - { - $ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips); - } - else - { - foreach ($user_ips as $user_ip) - { - if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip)) - { - $ip_banned = true; - break; - } - } - } - } - - if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) || - $ip_banned || - (!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email))) - { - if (!empty($row['ban_exclude'])) - { - $banned = false; - break; - } - else - { - $banned = true; - $ban_row = $row; - - if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) - { - $ban_triggered_by = 'user'; - } - else if ($ip_banned) - { - $ban_triggered_by = 'ip'; - } - else - { - $ban_triggered_by = 'email'; - } - - // Don't break. Check if there is an exclude rule for this user - } - } - } - $db->sql_freeresult($result); - - if ($banned && !$return) - { - global $template; - - // If the session is empty we need to create a valid one... - if (empty($this->session_id)) - { - // This seems to be no longer needed? - #14971 -// $this->session_create(ANONYMOUS); - } - - // Initiate environment ... since it won't be set at this stage - $this->setup(); - - // Logout the user, banned users are unable to use the normal 'logout' link - if ($this->data['user_id'] != ANONYMOUS) - { - $this->session_kill(); - } - - // We show a login box here to allow founders accessing the board if banned by IP - if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS) - { - global $phpEx; - - $this->setup('ucp'); - $this->data['is_registered'] = $this->data['is_bot'] = false; - - // Set as a precaution to allow login_box() handling this case correctly as well as this function not being executed again. - define('IN_CHECK_BAN', 1); - - login_box("index.$phpEx"); - - // The false here is needed, else the user is able to circumvent the ban. - $this->session_kill(false); - } - - // Ok, we catch the case of an empty session id for the anonymous user... - // This can happen if the user is logging in, banned by username and the login_box() being called "again". - if (empty($this->session_id) && defined('IN_CHECK_BAN')) - { - $this->session_create(ANONYMOUS); - } - - - // Determine which message to output - $till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : ''; - $message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM'; - - $message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>'); - $message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : ''; - $message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>'; - - // To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again - $this->session_kill(false); - - // A very special case... we are within the cron script which is not supposed to print out the ban message... show blank page - if (defined('IN_CRON')) - { - garbage_collection(); - exit_handler(); - exit; - } - - trigger_error($message); - } - - return ($banned && $ban_row['ban_give_reason']) ? $ban_row['ban_give_reason'] : $banned; - } - - /** - * Check if ip is blacklisted - * This should be called only where absolutly necessary - * - * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups) - * - * @author satmd (from the php manual) - * @param string $mode register/post - spamcop for example is ommitted for posting - * @return false if ip is not blacklisted, else an array([checked server], [lookup]) - */ - function check_dnsbl($mode, $ip = false) - { - if ($ip === false) - { - $ip = $this->ip; - } - - // Neither Spamhaus nor Spamcop supports IPv6 addresses. - if (strpos($ip, ':') !== false) - { - return false; - } - - $dnsbl_check = array( - 'sbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=', - ); - - if ($mode == 'register') - { - $dnsbl_check['bl.spamcop.net'] = 'http://spamcop.net/bl.shtml?'; - } - - if ($ip) - { - $quads = explode('.', $ip); - $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0]; - - // Need to be listed on all servers... - $listed = true; - $info = array(); - - foreach ($dnsbl_check as $dnsbl => $lookup) - { - if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true) - { - $info = array($dnsbl, $lookup . $ip); - } - else - { - $listed = false; - } - } - - if ($listed) - { - return $info; - } - } - - return false; - } - - /** - * Check if URI is blacklisted - * This should be called only where absolutly necessary, for example on the submitted website field - * This function is not in use at the moment and is only included for testing purposes, it may not work at all! - * This means it is untested at the moment and therefore commented out - * - * @param string $uri URI to check - * @return true if uri is on blacklist, else false. Only blacklist is checked (~zero FP), no grey lists - function check_uribl($uri) - { - // Normally parse_url() is not intended to parse uris - // We need to get the top-level domain name anyway... change. - $uri = parse_url($uri); - - if ($uri === false || empty($uri['host'])) - { - return false; - } - - $uri = trim($uri['host']); - - if ($uri) - { - // One problem here... the return parameter for the "windows" method is different from what - // we expect... this may render this check useless... - if (phpbb_checkdnsrr($uri . '.multi.uribl.com.', 'A') === true) - { - return true; - } - } - - return false; - } - */ - - /** - * Set/Update a persistent login key - * - * This method creates or updates a persistent session key. When a user makes - * use of persistent (formerly auto-) logins a key is generated and stored in the - * DB. When they revisit with the same key it's automatically updated in both the - * DB and cookie. Multiple keys may exist for each user representing different - * browsers or locations. As with _any_ non-secure-socket no passphrase login this - * remains vulnerable to exploit. - */ - function set_login_key($user_id = false, $key = false, $user_ip = false) - { - global $config, $db; - - $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id; - $user_ip = ($user_ip === false) ? $this->ip : $user_ip; - $key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key; - - $key_id = unique_id(hexdec(substr($this->session_id, 0, 8))); - - $sql_ary = array( - 'key_id' => (string) md5($key_id), - 'last_ip' => (string) $this->ip, - 'last_login' => (int) time() - ); - - if (!$key) - { - $sql_ary += array( - 'user_id' => (int) $user_id - ); - } - - if ($key) - { - $sql = 'UPDATE ' . SESSIONS_KEYS_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE user_id = ' . (int) $user_id . " - AND key_id = '" . $db->sql_escape(md5($key)) . "'"; - } - else - { - $sql = 'INSERT INTO ' . SESSIONS_KEYS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); - } - $db->sql_query($sql); - - $this->cookie_data['k'] = $key_id; - - return false; - } - - /** - * Reset all login keys for the specified user - * - * This method removes all current login keys for a specified (or the current) - * user. It will be called on password change to render old keys unusable - */ - function reset_login_keys($user_id = false) - { - global $config, $db; - - $user_id = ($user_id === false) ? (int) $this->data['user_id'] : (int) $user_id; - - $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' - WHERE user_id = ' . (int) $user_id; - $db->sql_query($sql); - - // If the user is logged in, update last visit info first before deleting sessions - $sql = 'SELECT session_time, session_page - FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . (int) $user_id . ' - ORDER BY session_time DESC'; - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $row['session_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' - WHERE user_id = " . (int) $user_id; - $db->sql_query($sql); - } - - // Let's also clear any current sessions for the specified user_id - // If it's the current user then we'll leave this session intact - $sql_where = 'session_user_id = ' . (int) $user_id; - $sql_where .= ($user_id === (int) $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : ''; - - $sql = 'DELETE FROM ' . SESSIONS_TABLE . " - WHERE $sql_where"; - $db->sql_query($sql); - - // We're changing the password of the current user and they have a key - // Lets regenerate it to be safe - if ($user_id === (int) $this->data['user_id'] && $this->cookie_data['k']) - { - $this->set_login_key($user_id); - } - } - - - /** - * Check if the request originated from the same page. - * @param bool $check_script_path If true, the path will be checked as well - */ - function validate_referer($check_script_path = false) - { - global $config; - - // no referer - nothing to validate, user's fault for turning it off (we only check on POST; so meta can't be the reason) - if (empty($this->referer) || empty($this->host)) - { - return true; - } - - $host = htmlspecialchars($this->host); - $ref = substr($this->referer, strpos($this->referer, '://') + 3); - - if (!(stripos($ref, $host) === 0) && (!$config['force_server_vars'] || !(stripos($ref, $config['server_name']) === 0))) - { - return false; - } - else if ($check_script_path && rtrim($this->page['root_script_path'], '/') !== '') - { - $ref = substr($ref, strlen($host)); - $server_port = (!empty($_SERVER['SERVER_PORT'])) ? (int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT'); - - if ($server_port !== 80 && $server_port !== 443 && stripos($ref, ":$server_port") === 0) - { - $ref = substr($ref, strlen(":$server_port")); - } - - if (!(stripos(rtrim($ref, '/'), rtrim($this->page['root_script_path'], '/')) === 0)) - { - return false; - } - } - - return true; - } - - - function unset_admin() - { - global $db; - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET session_admin = 0 - WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\''; - $db->sql_query($sql); - } -} - - -/** -* Base user class -* -* This is the overarching class which contains (through session extend) -* all methods utilised for user functionality during a session. -* -* @package phpBB3 -*/ -class user extends session -{ - var $lang = array(); - var $help = array(); - var $theme = array(); - var $date_format; - var $timezone; - var $dst; - - var $lang_name = false; - var $lang_id = false; - var $lang_path; - var $img_lang; - var $img_array = array(); - - // Able to add new options (up to id 31) - var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'popuppm' => 10, 'sig_bbcode' => 15, 'sig_smilies' => 16, 'sig_links' => 17); - - /** - * Constructor to set the lang path - */ - function user() - { - global $phpbb_root_path; - - $this->lang_path = $phpbb_root_path . 'language/'; - } - - /** - * Function to set custom language path (able to use directory outside of phpBB) - * - * @param string $lang_path New language path used. - * @access public - */ - function set_custom_lang_path($lang_path) - { - $this->lang_path = $lang_path; - - if (substr($this->lang_path, -1) != '/') - { - $this->lang_path .= '/'; - } - } - - /** - * Setup basic user-specific items (style, language, ...) - */ - function setup($lang_set = false, $style = false) - { - global $db, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache; - - if ($this->data['user_id'] != ANONYMOUS) - { - $this->lang_name = (file_exists($this->lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']); - - $this->date_format = $this->data['user_dateformat']; - $this->timezone = $this->data['user_timezone'] * 3600; - $this->dst = $this->data['user_dst'] * 3600; - } - else - { - $this->lang_name = basename($config['default_lang']); - $this->date_format = $config['default_dateformat']; - $this->timezone = $config['board_timezone'] * 3600; - $this->dst = $config['board_dst'] * 3600; - - /** - * If a guest user is surfing, we try to guess his/her language first by obtaining the browser language - * If re-enabled we need to make sure only those languages installed are checked - * Commented out so we do not loose the code. - - if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) - { - $accept_lang_ary = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); - - foreach ($accept_lang_ary as $accept_lang) - { - // Set correct format ... guess full xx_YY form - $accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2)); - $accept_lang = basename($accept_lang); - - if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx")) - { - $this->lang_name = $config['default_lang'] = $accept_lang; - break; - } - else - { - // No match on xx_YY so try xx - $accept_lang = substr($accept_lang, 0, 2); - $accept_lang = basename($accept_lang); - - if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx")) - { - $this->lang_name = $config['default_lang'] = $accept_lang; - break; - } - } - } - } - */ - } - - // We include common language file here to not load it every time a custom language file is included - $lang = &$this->lang; - - // Do not suppress error if in DEBUG_EXTRA mode - $include_result = (defined('DEBUG_EXTRA')) ? (include $this->lang_path . $this->lang_name . "/common.$phpEx") : (@include $this->lang_path . $this->lang_name . "/common.$phpEx"); - - if ($include_result === false) - { - die('Language file ' . $this->lang_path . $this->lang_name . "/common.$phpEx" . " couldn't be opened."); - } - - $this->add_lang($lang_set); - unset($lang_set); - - if (!empty($_GET['style']) && $auth->acl_get('a_styles') && !defined('ADMIN_START')) - { - global $SID, $_EXTRA_URL; - - $style = request_var('style', 0); - $SID .= '&style=' . $style; - $_EXTRA_URL = array('style=' . $style); - } - else - { - // Set up style - $style = ($style) ? $style : ((!$config['override_user_style']) ? $this->data['user_style'] : $config['default_style']); - } - - $sql = 'SELECT s.style_id, t.template_storedb, t.template_path, t.template_id, t.bbcode_bitfield, t.template_inherits_id, t.template_inherit_path, c.theme_path, c.theme_name, c.theme_storedb, c.theme_id, i.imageset_path, i.imageset_id, i.imageset_name - FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i - WHERE s.style_id = $style - AND t.template_id = s.template_id - AND c.theme_id = s.theme_id - AND i.imageset_id = s.imageset_id"; - $result = $db->sql_query($sql, 3600); - $this->theme = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // User has wrong style - if (!$this->theme && $style == $this->data['user_style']) - { - $style = $this->data['user_style'] = $config['default_style']; - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_style = $style - WHERE user_id = {$this->data['user_id']}"; - $db->sql_query($sql); - - $sql = 'SELECT s.style_id, t.template_storedb, t.template_path, t.template_id, t.bbcode_bitfield, c.theme_path, c.theme_name, c.theme_storedb, c.theme_id, i.imageset_path, i.imageset_id, i.imageset_name - FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i - WHERE s.style_id = $style - AND t.template_id = s.template_id - AND c.theme_id = s.theme_id - AND i.imageset_id = s.imageset_id"; - $result = $db->sql_query($sql, 3600); - $this->theme = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - } - - if (!$this->theme) - { - trigger_error('NO_STYLE_DATA', E_USER_ERROR); - } - - // Now parse the cfg file and cache it - $parsed_items = $cache->obtain_cfg_items($this->theme); - - // We are only interested in the theme configuration for now - $parsed_items = $parsed_items['theme']; - - $check_for = array( - 'parse_css_file' => (int) 0, - 'pagination_sep' => (string) ', ' - ); - - foreach ($check_for as $key => $default_value) - { - $this->theme[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value; - settype($this->theme[$key], gettype($default_value)); - - if (is_string($default_value)) - { - $this->theme[$key] = htmlspecialchars($this->theme[$key]); - } - } - - // If the style author specified the theme needs to be cached - // (because of the used paths and variables) than make sure it is the case. - // For example, if the theme uses language-specific images it needs to be stored in db. - if (!$this->theme['theme_storedb'] && $this->theme['parse_css_file']) - { - $this->theme['theme_storedb'] = 1; - - $stylesheet = file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/stylesheet.css"); - // Match CSS imports - $matches = array(); - preg_match_all('/@import url\(["\'](.*)["\']\);/i', $stylesheet, $matches); - - if (sizeof($matches)) - { - $content = ''; - foreach ($matches[0] as $idx => $match) - { - if ($content = @file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/" . $matches[1][$idx])) - { - $content = trim($content); - } - else - { - $content = ''; - } - $stylesheet = str_replace($match, $content, $stylesheet); - } - unset($content); - } - - $stylesheet = str_replace('./', 'styles/' . $this->theme['theme_path'] . '/theme/', $stylesheet); - - $sql_ary = array( - 'theme_data' => $stylesheet, - 'theme_mtime' => time(), - 'theme_storedb' => 1 - ); - - $sql = 'UPDATE ' . STYLES_THEME_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE theme_id = ' . $this->theme['theme_id']; - $db->sql_query($sql); - - unset($sql_ary); - } - - $template->set_template(); - - $this->img_lang = (file_exists($phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . $this->lang_name)) ? $this->lang_name : $config['default_lang']; - - // Same query in style.php - $sql = 'SELECT * - FROM ' . STYLES_IMAGESET_DATA_TABLE . ' - WHERE imageset_id = ' . $this->theme['imageset_id'] . " - AND image_filename <> '' - AND image_lang IN ('" . $db->sql_escape($this->img_lang) . "', '')"; - $result = $db->sql_query($sql, 3600); - - $localised_images = false; - while ($row = $db->sql_fetchrow($result)) - { - if ($row['image_lang']) - { - $localised_images = true; - } - - $row['image_filename'] = rawurlencode($row['image_filename']); - $this->img_array[$row['image_name']] = $row; - } - $db->sql_freeresult($result); - - // there were no localised images, try to refresh the localised imageset for the user's language - if (!$localised_images) - { - // Attention: this code ignores the image definition list from acp_styles and just takes everything - // that the config file contains - $sql_ary = array(); - - $db->sql_transaction('begin'); - - $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . ' - WHERE imageset_id = ' . $this->theme['imageset_id'] . ' - AND image_lang = \'' . $db->sql_escape($this->img_lang) . '\''; - $result = $db->sql_query($sql); - - if (@file_exists("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg")) - { - $cfg_data_imageset_data = parse_cfg_file("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg"); - foreach ($cfg_data_imageset_data as $image_name => $value) - { - if (strpos($value, '*') !== false) - { - if (substr($value, -1, 1) === '*') - { - list($image_filename, $image_height) = explode('*', $value); - $image_width = 0; - } - else - { - list($image_filename, $image_height, $image_width) = explode('*', $value); - } - } - else - { - $image_filename = $value; - $image_height = $image_width = 0; - } - - if (strpos($image_name, 'img_') === 0 && $image_filename) - { - $image_name = substr($image_name, 4); - $sql_ary[] = array( - 'image_name' => (string) $image_name, - 'image_filename' => (string) $image_filename, - 'image_height' => (int) $image_height, - 'image_width' => (int) $image_width, - 'imageset_id' => (int) $this->theme['imageset_id'], - 'image_lang' => (string) $this->img_lang, - ); - } - } - } - - if (sizeof($sql_ary)) - { - $db->sql_multi_insert(STYLES_IMAGESET_DATA_TABLE, $sql_ary); - $db->sql_transaction('commit'); - $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); - - add_log('admin', 'LOG_IMAGESET_LANG_REFRESHED', $this->theme['imageset_name'], $this->img_lang); - } - else - { - $db->sql_transaction('commit'); - add_log('admin', 'LOG_IMAGESET_LANG_MISSING', $this->theme['imageset_name'], $this->img_lang); - } - } - - // Call phpbb_user_session_handler() in case external application want to "bend" some variables or replace classes... - // After calling it we continue script execution... - phpbb_user_session_handler(); - - // If this function got called from the error handler we are finished here. - if (defined('IN_ERROR_HANDLER')) - { - return; - } - - // Disable board if the install/ directory is still present - // For the brave development army we do not care about this, else we need to comment out this everytime we develop locally - if (!defined('DEBUG_EXTRA') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install')) - { - // Adjust the message slightly according to the permissions - if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) - { - $message = 'REMOVE_INSTALL'; - } - else - { - $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; - } - trigger_error($message); - } - - // Is board disabled and user not an admin or moderator? - if ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) - { - if ($this->data['is_bot']) - { - send_status_line(503, 'Service Unavailable'); - } - - $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; - trigger_error($message); - } - - // Is load exceeded? - if ($config['limit_load'] && $this->load !== false) - { - if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN') && !defined('IN_ADMIN')) - { - // Set board disabled to true to let the admins/mods get the proper notification - $config['board_disable'] = '1'; - - if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) - { - if ($this->data['is_bot']) - { - send_status_line(503, 'Service Unavailable'); - } - trigger_error('BOARD_UNAVAILABLE'); - } - } - } - - if (isset($this->data['session_viewonline'])) - { - // Make sure the user is able to hide his session - if (!$this->data['session_viewonline']) - { - // Reset online status if not allowed to hide the session... - if (!$auth->acl_get('u_hideonline')) - { - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET session_viewonline = 1 - WHERE session_user_id = ' . $this->data['user_id']; - $db->sql_query($sql); - $this->data['session_viewonline'] = 1; - } - } - else if (!$this->data['user_allow_viewonline']) - { - // the user wants to hide and is allowed to -> cloaking device on. - if ($auth->acl_get('u_hideonline')) - { - $sql = 'UPDATE ' . SESSIONS_TABLE . ' - SET session_viewonline = 0 - WHERE session_user_id = ' . $this->data['user_id']; - $db->sql_query($sql); - $this->data['session_viewonline'] = 0; - } - } - } - - - // Does the user need to change their password? If so, redirect to the - // ucp profile reg_details page ... of course do not redirect if we're already in the ucp - if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && !empty($this->data['is_registered']) && $auth->acl_get('u_chgpasswd') && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) - { - if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx") - { - redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&mode=reg_details')); - } - } - - return; - } - - /** - * More advanced language substitution - * Function to mimic sprintf() with the possibility of using phpBB's language system to substitute nullar/singular/plural forms. - * Params are the language key and the parameters to be substituted. - * This function/functionality is inspired by SHS` and Ashe. - * - * Example call: <samp>$user->lang('NUM_POSTS_IN_QUEUE', 1);</samp> - */ - function lang() - { - $args = func_get_args(); - $key = $args[0]; - - if (is_array($key)) - { - $lang = &$this->lang[array_shift($key)]; - - foreach ($key as $_key) - { - $lang = &$lang[$_key]; - } - } - else - { - $lang = &$this->lang[$key]; - } - - // Return if language string does not exist - if (!isset($lang) || (!is_string($lang) && !is_array($lang))) - { - return $key; - } - - // If the language entry is a string, we simply mimic sprintf() behaviour - if (is_string($lang)) - { - if (sizeof($args) == 1) - { - return $lang; - } - - // Replace key with language entry and simply pass along... - $args[0] = $lang; - return call_user_func_array('sprintf', $args); - } - - // It is an array... now handle different nullar/singular/plural forms - $key_found = false; - - // We now get the first number passed and will select the key based upon this number - for ($i = 1, $num_args = sizeof($args); $i < $num_args; $i++) - { - if (is_int($args[$i])) - { - $numbers = array_keys($lang); - - foreach ($numbers as $num) - { - if ($num > $args[$i]) - { - break; - } - - $key_found = $num; - } - break; - } - } - - // Ok, let's check if the key was found, else use the last entry (because it is mostly the plural form) - if ($key_found === false) - { - $numbers = array_keys($lang); - $key_found = end($numbers); - } - - // Use the language string we determined and pass it to sprintf() - $args[0] = $lang[$key_found]; - return call_user_func_array('sprintf', $args); - } - - /** - * Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion) - * - * @param mixed $lang_set specifies the language entries to include - * @param bool $use_db internal variable for recursion, do not use - * @param bool $use_help internal variable for recursion, do not use - * - * Examples: - * <code> - * $lang_set = array('posting', 'help' => 'faq'); - * $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq')) - * $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq')) - * $lang_set = 'posting' - * $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting')) - * </code> - */ - function add_lang($lang_set, $use_db = false, $use_help = false) - { - global $phpEx; - - if (is_array($lang_set)) - { - foreach ($lang_set as $key => $lang_file) - { - // Please do not delete this line. - // We have to force the type here, else [array] language inclusion will not work - $key = (string) $key; - - if ($key == 'db') - { - $this->add_lang($lang_file, true, $use_help); - } - else if ($key == 'help') - { - $this->add_lang($lang_file, $use_db, true); - } - else if (!is_array($lang_file)) - { - $this->set_lang($this->lang, $this->help, $lang_file, $use_db, $use_help); - } - else - { - $this->add_lang($lang_file, $use_db, $use_help); - } - } - unset($lang_set); - } - else if ($lang_set) - { - $this->set_lang($this->lang, $this->help, $lang_set, $use_db, $use_help); - } - } - - /** - * Set language entry (called by add_lang) - * @access private - */ - function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false) - { - global $phpEx; - - // Make sure the language name is set (if the user setup did not happen it is not set) - if (!$this->lang_name) - { - global $config; - $this->lang_name = basename($config['default_lang']); - } - - // $lang == $this->lang - // $help == $this->help - // - add appropriate variables here, name them as they are used within the language file... - if (!$use_db) - { - if ($use_help && strpos($lang_file, '/') !== false) - { - $language_filename = $this->lang_path . $this->lang_name . '/' . substr($lang_file, 0, stripos($lang_file, '/') + 1) . 'help_' . substr($lang_file, stripos($lang_file, '/') + 1) . '.' . $phpEx; - } - else - { - $language_filename = $this->lang_path . $this->lang_name . '/' . (($use_help) ? 'help_' : '') . $lang_file . '.' . $phpEx; - } - - if (!file_exists($language_filename)) - { - global $config; - - if ($this->lang_name == 'en') - { - // The user's selected language is missing the file, the board default's language is missing the file, and the file doesn't exist in /en. - $language_filename = str_replace($this->lang_path . 'en', $this->lang_path . $this->data['user_lang'], $language_filename); - trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR); - } - else if ($this->lang_name == basename($config['default_lang'])) - { - // Fall back to the English Language - $this->lang_name = 'en'; - $this->set_lang($lang, $help, $lang_file, $use_db, $use_help); - } - else if ($this->lang_name == $this->data['user_lang']) - { - // Fall back to the board default language - $this->lang_name = basename($config['default_lang']); - $this->set_lang($lang, $help, $lang_file, $use_db, $use_help); - } - - // Reset the lang name - $this->lang_name = (file_exists($this->lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']); - return; - } - - // Do not suppress error if in DEBUG_EXTRA mode - $include_result = (defined('DEBUG_EXTRA')) ? (include $language_filename) : (@include $language_filename); - - if ($include_result === false) - { - trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR); - } - } - else if ($use_db) - { - // Get Database Language Strings - // Put them into $lang if nothing is prefixed, put them into $help if help: is prefixed - // For example: help:faq, posting - } - } - - /** - * Format user date - * - * @param int $gmepoch unix timestamp - * @param string $format date format in date() notation. | used to indicate relative dates, for example |d m Y|, h:i is translated to Today, h:i. - * @param bool $forcedate force non-relative date format. - * - * @return mixed translated date - */ - function format_date($gmepoch, $format = false, $forcedate = false) - { - static $midnight; - static $date_cache; - - $format = (!$format) ? $this->date_format : $format; - $now = time(); - $delta = $now - $gmepoch; - - if (!isset($date_cache[$format])) - { - // Is the user requesting a friendly date format (i.e. 'Today 12:42')? - $date_cache[$format] = array( - 'is_short' => strpos($format, '|'), - 'format_short' => substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1), - 'format_long' => str_replace('|', '', $format), - // Filter out values that are not strings (e.g. arrays) for strtr(). - 'lang' => array_filter($this->lang['datetime'], 'is_string'), - ); - - // Short representation of month in format? Some languages use different terms for the long and short format of May - if ((strpos($format, '\M') === false && strpos($format, 'M') !== false) || (strpos($format, '\r') === false && strpos($format, 'r') !== false)) - { - $date_cache[$format]['lang']['May'] = $this->lang['datetime']['May_short']; - } - } - - // Zone offset - $zone_offset = $this->timezone + $this->dst; - - // Show date <= 1 hour ago as 'xx min ago' but not greater than 60 seconds in the future - // A small tolerence is given for times in the future but in the same minute are displayed as '< than a minute ago' - if ($delta <= 3600 && $delta > -60 && ($delta >= -5 || (($now / 60) % 60) == (($gmepoch / 60) % 60)) && $date_cache[$format]['is_short'] !== false && !$forcedate && isset($this->lang['datetime']['AGO'])) - { - return $this->lang(array('datetime', 'AGO'), max(0, (int) floor($delta / 60))); - } - - if (!$midnight) - { - list($d, $m, $y) = explode(' ', gmdate('j n Y', time() + $zone_offset)); - $midnight = gmmktime(0, 0, 0, $m, $d, $y) - $zone_offset; - } - - if ($date_cache[$format]['is_short'] !== false && !$forcedate && !($gmepoch < $midnight - 86400 || $gmepoch > $midnight + 172800)) - { - $day = false; - - if ($gmepoch > $midnight + 86400) - { - $day = 'TOMORROW'; - } - else if ($gmepoch > $midnight) - { - $day = 'TODAY'; - } - else if ($gmepoch > $midnight - 86400) - { - $day = 'YESTERDAY'; - } - - if ($day !== false) - { - return str_replace('||', $this->lang['datetime'][$day], strtr(@gmdate($date_cache[$format]['format_short'], $gmepoch + $zone_offset), $date_cache[$format]['lang'])); - } - } - - return strtr(@gmdate($date_cache[$format]['format_long'], $gmepoch + $zone_offset), $date_cache[$format]['lang']); - } - - /** - * Get language id currently used by the user - */ - function get_iso_lang_id() - { - global $config, $db; - - if (!empty($this->lang_id)) - { - return $this->lang_id; - } - - if (!$this->lang_name) - { - $this->lang_name = $config['default_lang']; - } - - $sql = 'SELECT lang_id - FROM ' . LANG_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'"; - $result = $db->sql_query($sql); - $this->lang_id = (int) $db->sql_fetchfield('lang_id'); - $db->sql_freeresult($result); - - return $this->lang_id; - } - - /** - * Get users profile fields - */ - function get_profile_fields($user_id) - { - global $db; - - if (isset($this->profile_fields)) - { - return; - } - - $sql = 'SELECT * - FROM ' . PROFILE_FIELDS_DATA_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query_limit($sql, 1); - $this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row; - $db->sql_freeresult($result); - } - - /** - * Specify/Get image - * $suffix is no longer used - we know it. ;) It is there for backward compatibility. - */ - function img($img, $alt = '', $width = false, $suffix = '', $type = 'full_tag') - { - static $imgs; - global $phpbb_root_path; - - $img_data = &$imgs[$img]; - - if (empty($img_data)) - { - if (!isset($this->img_array[$img])) - { - // Do not fill the image to let designers decide what to do if the image is empty - $img_data = ''; - return $img_data; - } - - // Use URL if told so - $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; - - $path = 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename']; - - $img_data['src'] = $root_path . $path; - $img_data['width'] = $this->img_array[$img]['image_width']; - $img_data['height'] = $this->img_array[$img]['image_height']; - - // We overwrite the width and height to the phpbb logo's width - // and height here if the contents of the site_logo file are - // really equal to the phpbb_logo - // This allows us to change the dimensions of the phpbb_logo without - // modifying the imageset.cfg and causing a conflict for everyone - // who modified it for their custom logo on updating - if ($img == 'site_logo' && file_exists($phpbb_root_path . $path)) - { - global $cache; - - $img_file_hashes = $cache->get('imageset_site_logo_md5'); - - if ($img_file_hashes === false) - { - $img_file_hashes = array(); - } - - $key = $this->theme['imageset_path'] . '::' . $this->img_array[$img]['image_lang']; - if (!isset($img_file_hashes[$key])) - { - $img_file_hashes[$key] = md5(file_get_contents($phpbb_root_path . $path)); - $cache->put('imageset_site_logo_md5', $img_file_hashes); - } - - $phpbb_logo_hash = '0c461a32cd3621643105f0d02a772c10'; - - if ($phpbb_logo_hash == $img_file_hashes[$key]) - { - $img_data['width'] = '149'; - $img_data['height'] = '52'; - } - } - } - - $alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt; - - switch ($type) - { - case 'src': - return $img_data['src']; - break; - - case 'width': - return ($width === false) ? $img_data['width'] : $width; - break; - - case 'height': - return $img_data['height']; - break; - - default: - $use_width = ($width === false) ? $img_data['width'] : $width; - - return '<img src="' . $img_data['src'] . '"' . (($use_width) ? ' width="' . $use_width . '"' : '') . (($img_data['height']) ? ' height="' . $img_data['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />'; - break; - } - } - - /** - * Get option bit field from user options. - * - * @param int $key option key, as defined in $keyoptions property. - * @param int $data bit field value to use, or false to use $this->data['user_options'] - * @return bool true if the option is set in the bit field, false otherwise - */ - function optionget($key, $data = false) - { - $var = ($data !== false) ? $data : $this->data['user_options']; - return phpbb_optionget($this->keyoptions[$key], $var); - } - - /** - * Set option bit field for user options. - * - * @param int $key Option key, as defined in $keyoptions property. - * @param bool $value True to set the option, false to clear the option. - * @param int $data Current bit field value, or false to use $this->data['user_options'] - * @return int|bool If $data is false, the bit field is modified and - * written back to $this->data['user_options'], and - * return value is true if the bit field changed and - * false otherwise. If $data is not false, the new - * bitfield value is returned. - */ - function optionset($key, $value, $data = false) - { - $var = ($data !== false) ? $data : $this->data['user_options']; - - $new_var = phpbb_optionset($this->keyoptions[$key], $value, $var); - - if ($data === false) - { - if ($new_var != $var) - { - $this->data['user_options'] = $new_var; - return true; - } - else - { - return false; - } - } - else - { - return $new_var; - } - } - - /** - * Funtion to make the user leave the NEWLY_REGISTERED system group. - * @access public - */ - function leave_newly_registered() - { - global $db; - - if (empty($this->data['user_new'])) - { - return false; - } - - if (!function_exists('remove_newly_registered')) - { - global $phpbb_root_path, $phpEx; - - include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - } - if ($group = remove_newly_registered($this->data['user_id'], $this->data)) - { - $this->data['group_id'] = $group; - - } - $this->data['user_permissions'] = ''; - $this->data['user_new'] = 0; - - return true; - } - - /** - * Returns all password protected forum ids the user is currently NOT authenticated for. - * - * @return array Array of forum ids - * @access public - */ - function get_passworded_forums() - { - global $db; - - $sql = 'SELECT f.forum_id, fa.user_id - FROM ' . FORUMS_TABLE . ' f - LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa - ON (fa.forum_id = f.forum_id - AND fa.session_id = '" . $db->sql_escape($this->session_id) . "') - WHERE f.forum_password <> ''"; - $result = $db->sql_query($sql); - - $forum_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_id = (int) $row['forum_id']; - - if ($row['user_id'] != $this->data['user_id']) - { - $forum_ids[$forum_id] = $forum_id; - } - } - $db->sql_freeresult($result); - - return $forum_ids; - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/sphinxapi.php b/phpBB/includes/sphinxapi.php new file mode 100644 index 0000000000..6c3b66710c --- /dev/null +++ b/phpBB/includes/sphinxapi.php @@ -0,0 +1,1712 @@ +<?php + +// +// $Id: sphinxapi.php 3087 2012-01-30 23:07:35Z shodan $ +// + +// +// Copyright (c) 2001-2012, Andrew Aksyonoff +// Copyright (c) 2008-2012, Sphinx Technologies Inc +// All rights reserved +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License. You should have +// received a copy of the GPL license along with this program; if you +// did not, you can find it at http://www.gnu.org/ +// + +///////////////////////////////////////////////////////////////////////////// +// PHP version of Sphinx searchd client (PHP API) +///////////////////////////////////////////////////////////////////////////// + +/// known searchd commands +define ( "SEARCHD_COMMAND_SEARCH", 0 ); +define ( "SEARCHD_COMMAND_EXCERPT", 1 ); +define ( "SEARCHD_COMMAND_UPDATE", 2 ); +define ( "SEARCHD_COMMAND_KEYWORDS", 3 ); +define ( "SEARCHD_COMMAND_PERSIST", 4 ); +define ( "SEARCHD_COMMAND_STATUS", 5 ); +define ( "SEARCHD_COMMAND_FLUSHATTRS", 7 ); + +/// current client-side command implementation versions +define ( "VER_COMMAND_SEARCH", 0x119 ); +define ( "VER_COMMAND_EXCERPT", 0x104 ); +define ( "VER_COMMAND_UPDATE", 0x102 ); +define ( "VER_COMMAND_KEYWORDS", 0x100 ); +define ( "VER_COMMAND_STATUS", 0x100 ); +define ( "VER_COMMAND_QUERY", 0x100 ); +define ( "VER_COMMAND_FLUSHATTRS", 0x100 ); + +/// known searchd status codes +define ( "SEARCHD_OK", 0 ); +define ( "SEARCHD_ERROR", 1 ); +define ( "SEARCHD_RETRY", 2 ); +define ( "SEARCHD_WARNING", 3 ); + +/// known match modes +define ( "SPH_MATCH_ALL", 0 ); +define ( "SPH_MATCH_ANY", 1 ); +define ( "SPH_MATCH_PHRASE", 2 ); +define ( "SPH_MATCH_BOOLEAN", 3 ); +define ( "SPH_MATCH_EXTENDED", 4 ); +define ( "SPH_MATCH_FULLSCAN", 5 ); +define ( "SPH_MATCH_EXTENDED2", 6 ); // extended engine V2 (TEMPORARY, WILL BE REMOVED) + +/// known ranking modes (ext2 only) +define ( "SPH_RANK_PROXIMITY_BM25", 0 ); ///< default mode, phrase proximity major factor and BM25 minor one +define ( "SPH_RANK_BM25", 1 ); ///< statistical mode, BM25 ranking only (faster but worse quality) +define ( "SPH_RANK_NONE", 2 ); ///< no ranking, all matches get a weight of 1 +define ( "SPH_RANK_WORDCOUNT", 3 ); ///< simple word-count weighting, rank is a weighted sum of per-field keyword occurence counts +define ( "SPH_RANK_PROXIMITY", 4 ); +define ( "SPH_RANK_MATCHANY", 5 ); +define ( "SPH_RANK_FIELDMASK", 6 ); +define ( "SPH_RANK_SPH04", 7 ); +define ( "SPH_RANK_EXPR", 8 ); +define ( "SPH_RANK_TOTAL", 9 ); + +/// known sort modes +define ( "SPH_SORT_RELEVANCE", 0 ); +define ( "SPH_SORT_ATTR_DESC", 1 ); +define ( "SPH_SORT_ATTR_ASC", 2 ); +define ( "SPH_SORT_TIME_SEGMENTS", 3 ); +define ( "SPH_SORT_EXTENDED", 4 ); +define ( "SPH_SORT_EXPR", 5 ); + +/// known filter types +define ( "SPH_FILTER_VALUES", 0 ); +define ( "SPH_FILTER_RANGE", 1 ); +define ( "SPH_FILTER_FLOATRANGE", 2 ); + +/// known attribute types +define ( "SPH_ATTR_INTEGER", 1 ); +define ( "SPH_ATTR_TIMESTAMP", 2 ); +define ( "SPH_ATTR_ORDINAL", 3 ); +define ( "SPH_ATTR_BOOL", 4 ); +define ( "SPH_ATTR_FLOAT", 5 ); +define ( "SPH_ATTR_BIGINT", 6 ); +define ( "SPH_ATTR_STRING", 7 ); +define ( "SPH_ATTR_MULTI", 0x40000001 ); +define ( "SPH_ATTR_MULTI64", 0x40000002 ); + +/// known grouping functions +define ( "SPH_GROUPBY_DAY", 0 ); +define ( "SPH_GROUPBY_WEEK", 1 ); +define ( "SPH_GROUPBY_MONTH", 2 ); +define ( "SPH_GROUPBY_YEAR", 3 ); +define ( "SPH_GROUPBY_ATTR", 4 ); +define ( "SPH_GROUPBY_ATTRPAIR", 5 ); + +// important properties of PHP's integers: +// - always signed (one bit short of PHP_INT_SIZE) +// - conversion from string to int is saturated +// - float is double +// - div converts arguments to floats +// - mod converts arguments to ints + +// the packing code below works as follows: +// - when we got an int, just pack it +// if performance is a problem, this is the branch users should aim for +// +// - otherwise, we got a number in string form +// this might be due to different reasons, but we assume that this is +// because it didn't fit into PHP int +// +// - factor the string into high and low ints for packing +// - if we have bcmath, then it is used +// - if we don't, we have to do it manually (this is the fun part) +// +// - x64 branch does factoring using ints +// - x32 (ab)uses floats, since we can't fit unsigned 32-bit number into an int +// +// unpacking routines are pretty much the same. +// - return ints if we can +// - otherwise format number into a string + +/// pack 64-bit signed +function sphPackI64 ( $v ) +{ + assert ( is_numeric($v) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + $v = (int)$v; + return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); + } + + // x32, int + if ( is_int($v) ) + return pack ( "NN", $v < 0 ? -1 : 0, $v ); + + // x32, bcmath + if ( function_exists("bcmul") ) + { + if ( bccomp ( $v, 0 ) == -1 ) + $v = bcadd ( "18446744073709551616", $v ); + $h = bcdiv ( $v, "4294967296", 0 ); + $l = bcmod ( $v, "4294967296" ); + return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit + } + + // x32, no-bcmath + $p = max(0, strlen($v) - 13); + $lo = abs((float)substr($v, $p)); + $hi = abs((float)substr($v, 0, $p)); + + $m = $lo + $hi*1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912 + $q = floor($m/4294967296.0); + $l = $m - ($q*4294967296.0); + $h = $hi*2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328 + + if ( $v<0 ) + { + if ( $l==0 ) + $h = 4294967296.0 - $h; + else + { + $h = 4294967295.0 - $h; + $l = 4294967296.0 - $l; + } + } + return pack ( "NN", $h, $l ); +} + +/// pack 64-bit unsigned +function sphPackU64 ( $v ) +{ + assert ( is_numeric($v) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + assert ( $v>=0 ); + + // x64, int + if ( is_int($v) ) + return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); + + // x64, bcmath + if ( function_exists("bcmul") ) + { + $h = bcdiv ( $v, 4294967296, 0 ); + $l = bcmod ( $v, 4294967296 ); + return pack ( "NN", $h, $l ); + } + + // x64, no-bcmath + $p = max ( 0, strlen($v) - 13 ); + $lo = (int)substr ( $v, $p ); + $hi = (int)substr ( $v, 0, $p ); + + $m = $lo + $hi*1316134912; + $l = $m % 4294967296; + $h = $hi*2328 + (int)($m/4294967296); + + return pack ( "NN", $h, $l ); + } + + // x32, int + if ( is_int($v) ) + return pack ( "NN", 0, $v ); + + // x32, bcmath + if ( function_exists("bcmul") ) + { + $h = bcdiv ( $v, "4294967296", 0 ); + $l = bcmod ( $v, "4294967296" ); + return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit + } + + // x32, no-bcmath + $p = max(0, strlen($v) - 13); + $lo = (float)substr($v, $p); + $hi = (float)substr($v, 0, $p); + + $m = $lo + $hi*1316134912.0; + $q = floor($m / 4294967296.0); + $l = $m - ($q * 4294967296.0); + $h = $hi*2328.0 + $q; + + return pack ( "NN", $h, $l ); +} + +// unpack 64-bit unsigned +function sphUnpackU64 ( $v ) +{ + list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); + + if ( PHP_INT_SIZE>=8 ) + { + if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again + if ( $lo<0 ) $lo += (1<<32); + + // x64, int + if ( $hi<=2147483647 ) + return ($hi<<32) + $lo; + + // x64, bcmath + if ( function_exists("bcmul") ) + return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); + + // x64, no-bcmath + $C = 100000; + $h = ((int)($hi / $C) << 32) + (int)($lo / $C); + $l = (($hi % $C) << 32) + ($lo % $C); + if ( $l>$C ) + { + $h += (int)($l / $C); + $l = $l % $C; + } + + if ( $h==0 ) + return $l; + return sprintf ( "%d%05d", $h, $l ); + } + + // x32, int + if ( $hi==0 ) + { + if ( $lo>0 ) + return $lo; + return sprintf ( "%u", $lo ); + } + + $hi = sprintf ( "%u", $hi ); + $lo = sprintf ( "%u", $lo ); + + // x32, bcmath + if ( function_exists("bcmul") ) + return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); + + // x32, no-bcmath + $hi = (float)$hi; + $lo = (float)$lo; + + $q = floor($hi/10000000.0); + $r = $hi - $q*10000000.0; + $m = $lo + $r*4967296.0; + $mq = floor($m/10000000.0); + $l = $m - $mq*10000000.0; + $h = $q*4294967296.0 + $r*429.0 + $mq; + + $h = sprintf ( "%.0f", $h ); + $l = sprintf ( "%07.0f", $l ); + if ( $h=="0" ) + return sprintf( "%.0f", (float)$l ); + return $h . $l; +} + +// unpack 64-bit signed +function sphUnpackI64 ( $v ) +{ + list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again + if ( $lo<0 ) $lo += (1<<32); + + return ($hi<<32) + $lo; + } + + // x32, int + if ( $hi==0 ) + { + if ( $lo>0 ) + return $lo; + return sprintf ( "%u", $lo ); + } + // x32, int + elseif ( $hi==-1 ) + { + if ( $lo<0 ) + return $lo; + return sprintf ( "%.0f", $lo - 4294967296.0 ); + } + + $neg = ""; + $c = 0; + if ( $hi<0 ) + { + $hi = ~$hi; + $lo = ~$lo; + $c = 1; + $neg = "-"; + } + + $hi = sprintf ( "%u", $hi ); + $lo = sprintf ( "%u", $lo ); + + // x32, bcmath + if ( function_exists("bcmul") ) + return $neg . bcadd ( bcadd ( $lo, bcmul ( $hi, "4294967296" ) ), $c ); + + // x32, no-bcmath + $hi = (float)$hi; + $lo = (float)$lo; + + $q = floor($hi/10000000.0); + $r = $hi - $q*10000000.0; + $m = $lo + $r*4967296.0; + $mq = floor($m/10000000.0); + $l = $m - $mq*10000000.0 + $c; + $h = $q*4294967296.0 + $r*429.0 + $mq; + if ( $l==10000000 ) + { + $l = 0; + $h += 1; + } + + $h = sprintf ( "%.0f", $h ); + $l = sprintf ( "%07.0f", $l ); + if ( $h=="0" ) + return $neg . sprintf( "%.0f", (float)$l ); + return $neg . $h . $l; +} + + +function sphFixUint ( $value ) +{ + if ( PHP_INT_SIZE>=8 ) + { + // x64 route, workaround broken unpack() in 5.2.2+ + if ( $value<0 ) $value += (1<<32); + return $value; + } + else + { + // x32 route, workaround php signed/unsigned braindamage + return sprintf ( "%u", $value ); + } +} + + +/// sphinx searchd client class +class SphinxClient +{ + var $_host; ///< searchd host (default is "localhost") + var $_port; ///< searchd port (default is 9312) + var $_offset; ///< how many records to seek from result-set start (default is 0) + var $_limit; ///< how many records to return from result-set starting at offset (default is 20) + var $_mode; ///< query matching mode (default is SPH_MATCH_ALL) + var $_weights; ///< per-field weights (default is 1 for all fields) + var $_sort; ///< match sorting mode (default is SPH_SORT_RELEVANCE) + var $_sortby; ///< attribute to sort by (defualt is "") + var $_min_id; ///< min ID to match (default is 0, which means no limit) + var $_max_id; ///< max ID to match (default is 0, which means no limit) + var $_filters; ///< search filters + var $_groupby; ///< group-by attribute name + var $_groupfunc; ///< group-by function (to pre-process group-by attribute value with) + var $_groupsort; ///< group-by sorting clause (to sort groups in result set with) + var $_groupdistinct;///< group-by count-distinct attribute + var $_maxmatches; ///< max matches to retrieve + var $_cutoff; ///< cutoff to stop searching at (default is 0) + var $_retrycount; ///< distributed retries count + var $_retrydelay; ///< distributed retries delay + var $_anchor; ///< geographical anchor point + var $_indexweights; ///< per-index weights + var $_ranker; ///< ranking mode (default is SPH_RANK_PROXIMITY_BM25) + var $_rankexpr; ///< ranking mode expression (for SPH_RANK_EXPR) + var $_maxquerytime; ///< max query time, milliseconds (default is 0, do not limit) + var $_fieldweights; ///< per-field-name weights + var $_overrides; ///< per-query attribute values overrides + var $_select; ///< select-list (attributes or expressions, with optional aliases) + + var $_error; ///< last error message + var $_warning; ///< last warning message + var $_connerror; ///< connection error vs remote error flag + + var $_reqs; ///< requests array for multi-query + var $_mbenc; ///< stored mbstring encoding + var $_arrayresult; ///< whether $result["matches"] should be a hash or an array + var $_timeout; ///< connect timeout + + ///////////////////////////////////////////////////////////////////////////// + // common stuff + ///////////////////////////////////////////////////////////////////////////// + + /// create a new client object and fill defaults + function SphinxClient () + { + // per-client-object settings + $this->_host = "localhost"; + $this->_port = 9312; + $this->_path = false; + $this->_socket = false; + + // per-query settings + $this->_offset = 0; + $this->_limit = 20; + $this->_mode = SPH_MATCH_ALL; + $this->_weights = array (); + $this->_sort = SPH_SORT_RELEVANCE; + $this->_sortby = ""; + $this->_min_id = 0; + $this->_max_id = 0; + $this->_filters = array (); + $this->_groupby = ""; + $this->_groupfunc = SPH_GROUPBY_DAY; + $this->_groupsort = "@group desc"; + $this->_groupdistinct= ""; + $this->_maxmatches = 1000; + $this->_cutoff = 0; + $this->_retrycount = 0; + $this->_retrydelay = 0; + $this->_anchor = array (); + $this->_indexweights= array (); + $this->_ranker = SPH_RANK_PROXIMITY_BM25; + $this->_rankexpr = ""; + $this->_maxquerytime= 0; + $this->_fieldweights= array(); + $this->_overrides = array(); + $this->_select = "*"; + + $this->_error = ""; // per-reply fields (for single-query case) + $this->_warning = ""; + $this->_connerror = false; + + $this->_reqs = array (); // requests storage (for multi-query case) + $this->_mbenc = ""; + $this->_arrayresult = false; + $this->_timeout = 0; + } + + function __destruct() + { + if ( $this->_socket !== false ) + fclose ( $this->_socket ); + } + + /// get last error message (string) + function GetLastError () + { + return $this->_error; + } + + /// get last warning message (string) + function GetLastWarning () + { + return $this->_warning; + } + + /// get last error flag (to tell network connection errors from searchd errors or broken responses) + function IsConnectError() + { + return $this->_connerror; + } + + /// set searchd host name (string) and port (integer) + function SetServer ( $host, $port = 0 ) + { + assert ( is_string($host) ); + if ( $host[0] == '/') + { + $this->_path = 'unix://' . $host; + return; + } + if ( substr ( $host, 0, 7 )=="unix://" ) + { + $this->_path = $host; + return; + } + + assert ( is_int($port) ); + $this->_host = $host; + $this->_port = $port; + $this->_path = ''; + + } + + /// set server connection timeout (0 to remove) + function SetConnectTimeout ( $timeout ) + { + assert ( is_numeric($timeout) ); + $this->_timeout = $timeout; + } + + + function _Send ( $handle, $data, $length ) + { + if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length ) + { + $this->_error = 'connection unexpectedly closed (timed out?)'; + $this->_connerror = true; + return false; + } + return true; + } + + ///////////////////////////////////////////////////////////////////////////// + + /// enter mbstring workaround mode + function _MBPush () + { + $this->_mbenc = ""; + if ( ini_get ( "mbstring.func_overload" ) & 2 ) + { + $this->_mbenc = mb_internal_encoding(); + mb_internal_encoding ( "latin1" ); + } + } + + /// leave mbstring workaround mode + function _MBPop () + { + if ( $this->_mbenc ) + mb_internal_encoding ( $this->_mbenc ); + } + + /// connect to searchd server + function _Connect () + { + if ( $this->_socket!==false ) + { + // we are in persistent connection mode, so we have a socket + // however, need to check whether it's still alive + if ( !@feof ( $this->_socket ) ) + return $this->_socket; + + // force reopen + $this->_socket = false; + } + + $errno = 0; + $errstr = ""; + $this->_connerror = false; + + if ( $this->_path ) + { + $host = $this->_path; + $port = 0; + } + else + { + $host = $this->_host; + $port = $this->_port; + } + + if ( $this->_timeout<=0 ) + $fp = @fsockopen ( $host, $port, $errno, $errstr ); + else + $fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout ); + + if ( !$fp ) + { + if ( $this->_path ) + $location = $this->_path; + else + $location = "{$this->_host}:{$this->_port}"; + + $errstr = trim ( $errstr ); + $this->_error = "connection to $location failed (errno=$errno, msg=$errstr)"; + $this->_connerror = true; + return false; + } + + // send my version + // this is a subtle part. we must do it before (!) reading back from searchd. + // because otherwise under some conditions (reported on FreeBSD for instance) + // TCP stack could throttle write-write-read pattern because of Nagle. + if ( !$this->_Send ( $fp, pack ( "N", 1 ), 4 ) ) + { + fclose ( $fp ); + $this->_error = "failed to send client protocol version"; + return false; + } + + // check version + list(,$v) = unpack ( "N*", fread ( $fp, 4 ) ); + $v = (int)$v; + if ( $v<1 ) + { + fclose ( $fp ); + $this->_error = "expected searchd protocol version 1+, got version '$v'"; + return false; + } + + return $fp; + } + + /// get and check response packet from searchd server + function _GetResponse ( $fp, $client_ver ) + { + $response = ""; + $len = 0; + + $header = fread ( $fp, 8 ); + if ( strlen($header)==8 ) + { + list ( $status, $ver, $len ) = array_values ( unpack ( "n2a/Nb", $header ) ); + $left = $len; + while ( $left>0 && !feof($fp) ) + { + $chunk = fread ( $fp, min ( 8192, $left ) ); + if ( $chunk ) + { + $response .= $chunk; + $left -= strlen($chunk); + } + } + } + if ( $this->_socket === false ) + fclose ( $fp ); + + // check response + $read = strlen ( $response ); + if ( !$response || $read!=$len ) + { + $this->_error = $len + ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)" + : "received zero-sized searchd response"; + return false; + } + + // check status + if ( $status==SEARCHD_WARNING ) + { + list(,$wlen) = unpack ( "N*", substr ( $response, 0, 4 ) ); + $this->_warning = substr ( $response, 4, $wlen ); + return substr ( $response, 4+$wlen ); + } + if ( $status==SEARCHD_ERROR ) + { + $this->_error = "searchd error: " . substr ( $response, 4 ); + return false; + } + if ( $status==SEARCHD_RETRY ) + { + $this->_error = "temporary searchd error: " . substr ( $response, 4 ); + return false; + } + if ( $status!=SEARCHD_OK ) + { + $this->_error = "unknown status code '$status'"; + return false; + } + + // check version + if ( $ver<$client_ver ) + { + $this->_warning = sprintf ( "searchd command v.%d.%d older than client's v.%d.%d, some options might not work", + $ver>>8, $ver&0xff, $client_ver>>8, $client_ver&0xff ); + } + + return $response; + } + + ///////////////////////////////////////////////////////////////////////////// + // searching + ///////////////////////////////////////////////////////////////////////////// + + /// set offset and count into result set, + /// and optionally set max-matches and cutoff limits + function SetLimits ( $offset, $limit, $max=0, $cutoff=0 ) + { + assert ( is_int($offset) ); + assert ( is_int($limit) ); + assert ( $offset>=0 ); + assert ( $limit>0 ); + assert ( $max>=0 ); + $this->_offset = $offset; + $this->_limit = $limit; + if ( $max>0 ) + $this->_maxmatches = $max; + if ( $cutoff>0 ) + $this->_cutoff = $cutoff; + } + + /// set maximum query time, in milliseconds, per-index + /// integer, 0 means "do not limit" + function SetMaxQueryTime ( $max ) + { + assert ( is_int($max) ); + assert ( $max>=0 ); + $this->_maxquerytime = $max; + } + + /// set matching mode + function SetMatchMode ( $mode ) + { + assert ( $mode==SPH_MATCH_ALL + || $mode==SPH_MATCH_ANY + || $mode==SPH_MATCH_PHRASE + || $mode==SPH_MATCH_BOOLEAN + || $mode==SPH_MATCH_EXTENDED + || $mode==SPH_MATCH_FULLSCAN + || $mode==SPH_MATCH_EXTENDED2 ); + $this->_mode = $mode; + } + + /// set ranking mode + function SetRankingMode ( $ranker, $rankexpr="" ) + { + assert ( $ranker>=0 && $ranker<SPH_RANK_TOTAL ); + assert ( is_string($rankexpr) ); + $this->_ranker = $ranker; + $this->_rankexpr = $rankexpr; + } + + /// set matches sorting mode + function SetSortMode ( $mode, $sortby="" ) + { + assert ( + $mode==SPH_SORT_RELEVANCE || + $mode==SPH_SORT_ATTR_DESC || + $mode==SPH_SORT_ATTR_ASC || + $mode==SPH_SORT_TIME_SEGMENTS || + $mode==SPH_SORT_EXTENDED || + $mode==SPH_SORT_EXPR ); + assert ( is_string($sortby) ); + assert ( $mode==SPH_SORT_RELEVANCE || strlen($sortby)>0 ); + + $this->_sort = $mode; + $this->_sortby = $sortby; + } + + /// bind per-field weights by order + /// DEPRECATED; use SetFieldWeights() instead + function SetWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $weight ) + assert ( is_int($weight) ); + + $this->_weights = $weights; + } + + /// bind per-field weights by name + function SetFieldWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $name=>$weight ) + { + assert ( is_string($name) ); + assert ( is_int($weight) ); + } + $this->_fieldweights = $weights; + } + + /// bind per-index weights by name + function SetIndexWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $index=>$weight ) + { + assert ( is_string($index) ); + assert ( is_int($weight) ); + } + $this->_indexweights = $weights; + } + + /// set IDs range to match + /// only match records if document ID is beetwen $min and $max (inclusive) + function SetIDRange ( $min, $max ) + { + assert ( is_numeric($min) ); + assert ( is_numeric($max) ); + assert ( $min<=$max ); + $this->_min_id = $min; + $this->_max_id = $max; + } + + /// set values set filter + /// only match records where $attribute value is in given set + function SetFilter ( $attribute, $values, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_array($values) ); + assert ( count($values) ); + + if ( is_array($values) && count($values) ) + { + foreach ( $values as $value ) + assert ( is_numeric($value) ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_VALUES, "attr"=>$attribute, "exclude"=>$exclude, "values"=>$values ); + } + } + + /// set range filter + /// only match records if $attribute value is beetwen $min and $max (inclusive) + function SetFilterRange ( $attribute, $min, $max, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_numeric($min) ); + assert ( is_numeric($max) ); + assert ( $min<=$max ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_RANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); + } + + /// set float range filter + /// only match records if $attribute value is beetwen $min and $max (inclusive) + function SetFilterFloatRange ( $attribute, $min, $max, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_float($min) ); + assert ( is_float($max) ); + assert ( $min<=$max ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_FLOATRANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); + } + + /// setup anchor point for geosphere distance calculations + /// required to use @geodist in filters and sorting + /// latitude and longitude must be in radians + function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long ) + { + assert ( is_string($attrlat) ); + assert ( is_string($attrlong) ); + assert ( is_float($lat) ); + assert ( is_float($long) ); + + $this->_anchor = array ( "attrlat"=>$attrlat, "attrlong"=>$attrlong, "lat"=>$lat, "long"=>$long ); + } + + /// set grouping attribute and function + function SetGroupBy ( $attribute, $func, $groupsort="@group desc" ) + { + assert ( is_string($attribute) ); + assert ( is_string($groupsort) ); + assert ( $func==SPH_GROUPBY_DAY + || $func==SPH_GROUPBY_WEEK + || $func==SPH_GROUPBY_MONTH + || $func==SPH_GROUPBY_YEAR + || $func==SPH_GROUPBY_ATTR + || $func==SPH_GROUPBY_ATTRPAIR ); + + $this->_groupby = $attribute; + $this->_groupfunc = $func; + $this->_groupsort = $groupsort; + } + + /// set count-distinct attribute for group-by queries + function SetGroupDistinct ( $attribute ) + { + assert ( is_string($attribute) ); + $this->_groupdistinct = $attribute; + } + + /// set distributed retries count and delay + function SetRetries ( $count, $delay=0 ) + { + assert ( is_int($count) && $count>=0 ); + assert ( is_int($delay) && $delay>=0 ); + $this->_retrycount = $count; + $this->_retrydelay = $delay; + } + + /// set result set format (hash or array; hash by default) + /// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs + function SetArrayResult ( $arrayresult ) + { + assert ( is_bool($arrayresult) ); + $this->_arrayresult = $arrayresult; + } + + /// set attribute values override + /// there can be only one override per attribute + /// $values must be a hash that maps document IDs to attribute values + function SetOverride ( $attrname, $attrtype, $values ) + { + assert ( is_string ( $attrname ) ); + assert ( in_array ( $attrtype, array ( SPH_ATTR_INTEGER, SPH_ATTR_TIMESTAMP, SPH_ATTR_BOOL, SPH_ATTR_FLOAT, SPH_ATTR_BIGINT ) ) ); + assert ( is_array ( $values ) ); + + $this->_overrides[$attrname] = array ( "attr"=>$attrname, "type"=>$attrtype, "values"=>$values ); + } + + /// set select-list (attributes or expressions), SQL-like syntax + function SetSelect ( $select ) + { + assert ( is_string ( $select ) ); + $this->_select = $select; + } + + ////////////////////////////////////////////////////////////////////////////// + + /// clear all filters (for multi-queries) + function ResetFilters () + { + $this->_filters = array(); + $this->_anchor = array(); + } + + /// clear groupby settings (for multi-queries) + function ResetGroupBy () + { + $this->_groupby = ""; + $this->_groupfunc = SPH_GROUPBY_DAY; + $this->_groupsort = "@group desc"; + $this->_groupdistinct= ""; + } + + /// clear all attribute value overrides (for multi-queries) + function ResetOverrides () + { + $this->_overrides = array (); + } + + ////////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, run given search query through given indexes, + /// and return the search results + function Query ( $query, $index="*", $comment="" ) + { + assert ( empty($this->_reqs) ); + + $this->AddQuery ( $query, $index, $comment ); + $results = $this->RunQueries (); + $this->_reqs = array (); // just in case it failed too early + + if ( !is_array($results) ) + return false; // probably network error; error message should be already filled + + $this->_error = $results[0]["error"]; + $this->_warning = $results[0]["warning"]; + if ( $results[0]["status"]==SEARCHD_ERROR ) + return false; + else + return $results[0]; + } + + /// helper to pack floats in network byte order + function _PackFloat ( $f ) + { + $t1 = pack ( "f", $f ); // machine order + list(,$t2) = unpack ( "L*", $t1 ); // int in machine order + return pack ( "N", $t2 ); + } + + /// add query to multi-query batch + /// returns index into results array from RunQueries() call + function AddQuery ( $query, $index="*", $comment="" ) + { + // mbstring workaround + $this->_MBPush (); + + // build request + $req = pack ( "NNNN", $this->_offset, $this->_limit, $this->_mode, $this->_ranker ); + if ( $this->_ranker==SPH_RANK_EXPR ) + $req .= pack ( "N", strlen($this->_rankexpr) ) . $this->_rankexpr; + $req .= pack ( "N", $this->_sort ); // (deprecated) sort mode + $req .= pack ( "N", strlen($this->_sortby) ) . $this->_sortby; + $req .= pack ( "N", strlen($query) ) . $query; // query itself + $req .= pack ( "N", count($this->_weights) ); // weights + foreach ( $this->_weights as $weight ) + $req .= pack ( "N", (int)$weight ); + $req .= pack ( "N", strlen($index) ) . $index; // indexes + $req .= pack ( "N", 1 ); // id64 range marker + $req .= sphPackU64 ( $this->_min_id ) . sphPackU64 ( $this->_max_id ); // id64 range + + // filters + $req .= pack ( "N", count($this->_filters) ); + foreach ( $this->_filters as $filter ) + { + $req .= pack ( "N", strlen($filter["attr"]) ) . $filter["attr"]; + $req .= pack ( "N", $filter["type"] ); + switch ( $filter["type"] ) + { + case SPH_FILTER_VALUES: + $req .= pack ( "N", count($filter["values"]) ); + foreach ( $filter["values"] as $value ) + $req .= sphPackI64 ( $value ); + break; + + case SPH_FILTER_RANGE: + $req .= sphPackI64 ( $filter["min"] ) . sphPackI64 ( $filter["max"] ); + break; + + case SPH_FILTER_FLOATRANGE: + $req .= $this->_PackFloat ( $filter["min"] ) . $this->_PackFloat ( $filter["max"] ); + break; + + default: + assert ( 0 && "internal error: unhandled filter type" ); + } + $req .= pack ( "N", $filter["exclude"] ); + } + + // group-by clause, max-matches count, group-sort clause, cutoff count + $req .= pack ( "NN", $this->_groupfunc, strlen($this->_groupby) ) . $this->_groupby; + $req .= pack ( "N", $this->_maxmatches ); + $req .= pack ( "N", strlen($this->_groupsort) ) . $this->_groupsort; + $req .= pack ( "NNN", $this->_cutoff, $this->_retrycount, $this->_retrydelay ); + $req .= pack ( "N", strlen($this->_groupdistinct) ) . $this->_groupdistinct; + + // anchor point + if ( empty($this->_anchor) ) + { + $req .= pack ( "N", 0 ); + } else + { + $a =& $this->_anchor; + $req .= pack ( "N", 1 ); + $req .= pack ( "N", strlen($a["attrlat"]) ) . $a["attrlat"]; + $req .= pack ( "N", strlen($a["attrlong"]) ) . $a["attrlong"]; + $req .= $this->_PackFloat ( $a["lat"] ) . $this->_PackFloat ( $a["long"] ); + } + + // per-index weights + $req .= pack ( "N", count($this->_indexweights) ); + foreach ( $this->_indexweights as $idx=>$weight ) + $req .= pack ( "N", strlen($idx) ) . $idx . pack ( "N", $weight ); + + // max query time + $req .= pack ( "N", $this->_maxquerytime ); + + // per-field weights + $req .= pack ( "N", count($this->_fieldweights) ); + foreach ( $this->_fieldweights as $field=>$weight ) + $req .= pack ( "N", strlen($field) ) . $field . pack ( "N", $weight ); + + // comment + $req .= pack ( "N", strlen($comment) ) . $comment; + + // attribute overrides + $req .= pack ( "N", count($this->_overrides) ); + foreach ( $this->_overrides as $key => $entry ) + { + $req .= pack ( "N", strlen($entry["attr"]) ) . $entry["attr"]; + $req .= pack ( "NN", $entry["type"], count($entry["values"]) ); + foreach ( $entry["values"] as $id=>$val ) + { + assert ( is_numeric($id) ); + assert ( is_numeric($val) ); + + $req .= sphPackU64 ( $id ); + switch ( $entry["type"] ) + { + case SPH_ATTR_FLOAT: $req .= $this->_PackFloat ( $val ); break; + case SPH_ATTR_BIGINT: $req .= sphPackI64 ( $val ); break; + default: $req .= pack ( "N", $val ); break; + } + } + } + + // select-list + $req .= pack ( "N", strlen($this->_select) ) . $this->_select; + + // mbstring workaround + $this->_MBPop (); + + // store request to requests array + $this->_reqs[] = $req; + return count($this->_reqs)-1; + } + + /// connect to searchd, run queries batch, and return an array of result sets + function RunQueries () + { + if ( empty($this->_reqs) ) + { + $this->_error = "no queries defined, issue AddQuery() first"; + return false; + } + + // mbstring workaround + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop (); + return false; + } + + // send query, get response + $nreqs = count($this->_reqs); + $req = join ( "", $this->_reqs ); + $len = 8+strlen($req); + $req = pack ( "nnNNN", SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs ) . $req; // add header + + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_SEARCH ) ) ) + { + $this->_MBPop (); + return false; + } + + // query sent ok; we can reset reqs now + $this->_reqs = array (); + + // parse and return response + return $this->_ParseSearchResponse ( $response, $nreqs ); + } + + /// parse and return search query (or queries) response + function _ParseSearchResponse ( $response, $nreqs ) + { + $p = 0; // current position + $max = strlen($response); // max position for checks, to protect against broken responses + + $results = array (); + for ( $ires=0; $ires<$nreqs && $p<$max; $ires++ ) + { + $results[] = array(); + $result =& $results[$ires]; + + $result["error"] = ""; + $result["warning"] = ""; + + // extract status + list(,$status) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $result["status"] = $status; + if ( $status!=SEARCHD_OK ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $message = substr ( $response, $p, $len ); $p += $len; + + if ( $status==SEARCHD_WARNING ) + { + $result["warning"] = $message; + } else + { + $result["error"] = $message; + continue; + } + } + + // read schema + $fields = array (); + $attrs = array (); + + list(,$nfields) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + while ( $nfields-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $fields[] = substr ( $response, $p, $len ); $p += $len; + } + $result["fields"] = $fields; + + list(,$nattrs) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + while ( $nattrs-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attr = substr ( $response, $p, $len ); $p += $len; + list(,$type) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attrs[$attr] = $type; + } + $result["attrs"] = $attrs; + + // read match count + list(,$count) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + list(,$id64) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + + // read matches + $idx = -1; + while ( $count-->0 && $p<$max ) + { + // index into result array + $idx++; + + // parse document id and weight + if ( $id64 ) + { + $doc = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8; + list(,$weight) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + } + else + { + list ( $doc, $weight ) = array_values ( unpack ( "N*N*", + substr ( $response, $p, 8 ) ) ); + $p += 8; + $doc = sphFixUint($doc); + } + $weight = sprintf ( "%u", $weight ); + + // create match entry + if ( $this->_arrayresult ) + $result["matches"][$idx] = array ( "id"=>$doc, "weight"=>$weight ); + else + $result["matches"][$doc]["weight"] = $weight; + + // parse and create attributes + $attrvals = array (); + foreach ( $attrs as $attr=>$type ) + { + // handle 64bit ints + if ( $type==SPH_ATTR_BIGINT ) + { + $attrvals[$attr] = sphUnpackI64 ( substr ( $response, $p, 8 ) ); $p += 8; + continue; + } + + // handle floats + if ( $type==SPH_ATTR_FLOAT ) + { + list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + list(,$fval) = unpack ( "f*", pack ( "L", $uval ) ); + $attrvals[$attr] = $fval; + continue; + } + + // handle everything else as unsigned ints + list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + if ( $type==SPH_ATTR_MULTI ) + { + $attrvals[$attr] = array (); + $nvalues = $val; + while ( $nvalues-->0 && $p<$max ) + { + list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attrvals[$attr][] = sphFixUint($val); + } + } else if ( $type==SPH_ATTR_MULTI64 ) + { + $attrvals[$attr] = array (); + $nvalues = $val; + while ( $nvalues>0 && $p<$max ) + { + $attrvals[$attr][] = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8; + $nvalues -= 2; + } + } else if ( $type==SPH_ATTR_STRING ) + { + $attrvals[$attr] = substr ( $response, $p, $val ); + $p += $val; + } else + { + $attrvals[$attr] = sphFixUint($val); + } + } + + if ( $this->_arrayresult ) + $result["matches"][$idx]["attrs"] = $attrvals; + else + $result["matches"][$doc]["attrs"] = $attrvals; + } + + list ( $total, $total_found, $msecs, $words ) = + array_values ( unpack ( "N*N*N*N*", substr ( $response, $p, 16 ) ) ); + $result["total"] = sprintf ( "%u", $total ); + $result["total_found"] = sprintf ( "%u", $total_found ); + $result["time"] = sprintf ( "%.3f", $msecs/1000 ); + $p += 16; + + while ( $words-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $word = substr ( $response, $p, $len ); $p += $len; + list ( $docs, $hits ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; + $result["words"][$word] = array ( + "docs"=>sprintf ( "%u", $docs ), + "hits"=>sprintf ( "%u", $hits ) ); + } + } + + $this->_MBPop (); + return $results; + } + + ///////////////////////////////////////////////////////////////////////////// + // excerpts generation + ///////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, and generate exceprts (snippets) + /// of given documents for given query. returns false on failure, + /// an array of snippets on success + function BuildExcerpts ( $docs, $index, $words, $opts=array() ) + { + assert ( is_array($docs) ); + assert ( is_string($index) ); + assert ( is_string($words) ); + assert ( is_array($opts) ); + + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + ///////////////// + // fixup options + ///////////////// + + if ( !isset($opts["before_match"]) ) $opts["before_match"] = "<b>"; + if ( !isset($opts["after_match"]) ) $opts["after_match"] = "</b>"; + if ( !isset($opts["chunk_separator"]) ) $opts["chunk_separator"] = " ... "; + if ( !isset($opts["limit"]) ) $opts["limit"] = 256; + if ( !isset($opts["limit_passages"]) ) $opts["limit_passages"] = 0; + if ( !isset($opts["limit_words"]) ) $opts["limit_words"] = 0; + if ( !isset($opts["around"]) ) $opts["around"] = 5; + if ( !isset($opts["exact_phrase"]) ) $opts["exact_phrase"] = false; + if ( !isset($opts["single_passage"]) ) $opts["single_passage"] = false; + if ( !isset($opts["use_boundaries"]) ) $opts["use_boundaries"] = false; + if ( !isset($opts["weight_order"]) ) $opts["weight_order"] = false; + if ( !isset($opts["query_mode"]) ) $opts["query_mode"] = false; + if ( !isset($opts["force_all_words"]) ) $opts["force_all_words"] = false; + if ( !isset($opts["start_passage_id"]) ) $opts["start_passage_id"] = 1; + if ( !isset($opts["load_files"]) ) $opts["load_files"] = false; + if ( !isset($opts["html_strip_mode"]) ) $opts["html_strip_mode"] = "index"; + if ( !isset($opts["allow_empty"]) ) $opts["allow_empty"] = false; + if ( !isset($opts["passage_boundary"]) ) $opts["passage_boundary"] = "none"; + if ( !isset($opts["emit_zones"]) ) $opts["emit_zones"] = false; + if ( !isset($opts["load_files_scattered"]) ) $opts["load_files_scattered"] = false; + + + ///////////////// + // build request + ///////////////// + + // v.1.2 req + $flags = 1; // remove spaces + if ( $opts["exact_phrase"] ) $flags |= 2; + if ( $opts["single_passage"] ) $flags |= 4; + if ( $opts["use_boundaries"] ) $flags |= 8; + if ( $opts["weight_order"] ) $flags |= 16; + if ( $opts["query_mode"] ) $flags |= 32; + if ( $opts["force_all_words"] ) $flags |= 64; + if ( $opts["load_files"] ) $flags |= 128; + if ( $opts["allow_empty"] ) $flags |= 256; + if ( $opts["emit_zones"] ) $flags |= 512; + if ( $opts["load_files_scattered"] ) $flags |= 1024; + $req = pack ( "NN", 0, $flags ); // mode=0, flags=$flags + $req .= pack ( "N", strlen($index) ) . $index; // req index + $req .= pack ( "N", strlen($words) ) . $words; // req words + + // options + $req .= pack ( "N", strlen($opts["before_match"]) ) . $opts["before_match"]; + $req .= pack ( "N", strlen($opts["after_match"]) ) . $opts["after_match"]; + $req .= pack ( "N", strlen($opts["chunk_separator"]) ) . $opts["chunk_separator"]; + $req .= pack ( "NN", (int)$opts["limit"], (int)$opts["around"] ); + $req .= pack ( "NNN", (int)$opts["limit_passages"], (int)$opts["limit_words"], (int)$opts["start_passage_id"] ); // v.1.2 + $req .= pack ( "N", strlen($opts["html_strip_mode"]) ) . $opts["html_strip_mode"]; + $req .= pack ( "N", strlen($opts["passage_boundary"]) ) . $opts["passage_boundary"]; + + // documents + $req .= pack ( "N", count($docs) ); + foreach ( $docs as $doc ) + { + assert ( is_string($doc) ); + $req .= pack ( "N", strlen($doc) ) . $doc; + } + + //////////////////////////// + // send query, get response + //////////////////////////// + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len ) . $req; // add header + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_EXCERPT ) ) ) + { + $this->_MBPop (); + return false; + } + + ////////////////// + // parse response + ////////////////// + + $pos = 0; + $res = array (); + $rlen = strlen($response); + for ( $i=0; $i<count($docs); $i++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); + $pos += 4; + + if ( $pos+$len > $rlen ) + { + $this->_error = "incomplete reply"; + $this->_MBPop (); + return false; + } + $res[] = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + } + + $this->_MBPop (); + return $res; + } + + + ///////////////////////////////////////////////////////////////////////////// + // keyword generation + ///////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, and generate keyword list for a given query + /// returns false on failure, + /// an array of words on success + function BuildKeywords ( $query, $index, $hits ) + { + assert ( is_string($query) ); + assert ( is_string($index) ); + assert ( is_bool($hits) ); + + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + ///////////////// + // build request + ///////////////// + + // v.1.0 req + $req = pack ( "N", strlen($query) ) . $query; // req query + $req .= pack ( "N", strlen($index) ) . $index; // req index + $req .= pack ( "N", (int)$hits ); + + //////////////////////////// + // send query, get response + //////////////////////////// + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len ) . $req; // add header + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_KEYWORDS ) ) ) + { + $this->_MBPop (); + return false; + } + + ////////////////// + // parse response + ////////////////// + + $pos = 0; + $res = array (); + $rlen = strlen($response); + list(,$nwords) = unpack ( "N*", substr ( $response, $pos, 4 ) ); + $pos += 4; + for ( $i=0; $i<$nwords; $i++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; + $tokenized = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; + $normalized = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + + $res[] = array ( "tokenized"=>$tokenized, "normalized"=>$normalized ); + + if ( $hits ) + { + list($ndocs,$nhits) = array_values ( unpack ( "N*N*", substr ( $response, $pos, 8 ) ) ); + $pos += 8; + $res [$i]["docs"] = $ndocs; + $res [$i]["hits"] = $nhits; + } + + if ( $pos > $rlen ) + { + $this->_error = "incomplete reply"; + $this->_MBPop (); + return false; + } + } + + $this->_MBPop (); + return $res; + } + + function EscapeString ( $string ) + { + $from = array ( '\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=' ); + $to = array ( '\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=' ); + + return str_replace ( $from, $to, $string ); + } + + ///////////////////////////////////////////////////////////////////////////// + // attribute updates + ///////////////////////////////////////////////////////////////////////////// + + /// batch update given attributes in given rows in given indexes + /// returns amount of updated documents (0 or more) on success, or -1 on failure + function UpdateAttributes ( $index, $attrs, $values, $mva=false ) + { + // verify everything + assert ( is_string($index) ); + assert ( is_bool($mva) ); + + assert ( is_array($attrs) ); + foreach ( $attrs as $attr ) + assert ( is_string($attr) ); + + assert ( is_array($values) ); + foreach ( $values as $id=>$entry ) + { + assert ( is_numeric($id) ); + assert ( is_array($entry) ); + assert ( count($entry)==count($attrs) ); + foreach ( $entry as $v ) + { + if ( $mva ) + { + assert ( is_array($v) ); + foreach ( $v as $vv ) + assert ( is_int($vv) ); + } else + assert ( is_int($v) ); + } + } + + // build request + $this->_MBPush (); + $req = pack ( "N", strlen($index) ) . $index; + + $req .= pack ( "N", count($attrs) ); + foreach ( $attrs as $attr ) + { + $req .= pack ( "N", strlen($attr) ) . $attr; + $req .= pack ( "N", $mva ? 1 : 0 ); + } + + $req .= pack ( "N", count($values) ); + foreach ( $values as $id=>$entry ) + { + $req .= sphPackU64 ( $id ); + foreach ( $entry as $v ) + { + $req .= pack ( "N", $mva ? count($v) : $v ); + if ( $mva ) + foreach ( $v as $vv ) + $req .= pack ( "N", $vv ); + } + } + + // connect, send query, get response + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop (); + return -1; + } + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len ) . $req; // add header + if ( !$this->_Send ( $fp, $req, $len+8 ) ) + { + $this->_MBPop (); + return -1; + } + + if (!( $response = $this->_GetResponse ( $fp, VER_COMMAND_UPDATE ) )) + { + $this->_MBPop (); + return -1; + } + + // parse response + list(,$updated) = unpack ( "N*", substr ( $response, 0, 4 ) ); + $this->_MBPop (); + return $updated; + } + + ///////////////////////////////////////////////////////////////////////////// + // persistent connections + ///////////////////////////////////////////////////////////////////////////// + + function Open() + { + if ( $this->_socket !== false ) + { + $this->_error = 'already connected'; + return false; + } + if ( !$fp = $this->_Connect() ) + return false; + + // command, command version = 0, body length = 4, body = 1 + $req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 ); + if ( !$this->_Send ( $fp, $req, 12 ) ) + return false; + + $this->_socket = $fp; + return true; + } + + function Close() + { + if ( $this->_socket === false ) + { + $this->_error = 'not connected'; + return false; + } + + fclose ( $this->_socket ); + $this->_socket = false; + + return true; + } + + ////////////////////////////////////////////////////////////////////////// + // status + ////////////////////////////////////////////////////////////////////////// + + function Status () + { + $this->_MBPush (); + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + $req = pack ( "nnNN", SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, 1 ); // len=4, body=1 + if ( !( $this->_Send ( $fp, $req, 12 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_STATUS ) ) ) + { + $this->_MBPop (); + return false; + } + + $res = substr ( $response, 4 ); // just ignore length, error handling, etc + $p = 0; + list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; + + $res = array(); + for ( $i=0; $i<$rows; $i++ ) + for ( $j=0; $j<$cols; $j++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $res[$i][] = substr ( $response, $p, $len ); $p += $len; + } + + $this->_MBPop (); + return $res; + } + + ////////////////////////////////////////////////////////////////////////// + // flush + ////////////////////////////////////////////////////////////////////////// + + function FlushAttributes () + { + $this->_MBPush (); + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return -1; + } + + $req = pack ( "nnN", SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0 ); // len=0 + if ( !( $this->_Send ( $fp, $req, 8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_FLUSHATTRS ) ) ) + { + $this->_MBPop (); + return -1; + } + + $tag = -1; + if ( strlen($response)==4 ) + list(,$tag) = unpack ( "N*", $response ); + else + $this->_error = "unexpected response length"; + + $this->_MBPop (); + return $tag; + } +} + +// +// $Id: sphinxapi.php 3087 2012-01-30 23:07:35Z shodan $ +// diff --git a/phpBB/includes/startup.php b/phpBB/includes/startup.php index 9bbbf4fd4c..2885c80541 100644 --- a/phpBB/includes/startup.php +++ b/phpBB/includes/startup.php @@ -1,9 +1,13 @@ <?php /** * -* @package phpBB3 -* @copyright (c) 2011 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -20,21 +24,6 @@ if (!defined('E_DEPRECATED')) define('E_DEPRECATED', 8192); } $level = E_ALL & ~E_NOTICE & ~E_DEPRECATED; -if (version_compare(PHP_VERSION, '5.4.0-dev', '>=')) -{ - // PHP 5.4 adds E_STRICT to E_ALL. - // Our utf8 normalizer triggers E_STRICT output on PHP 5.4. - // Unfortunately it cannot be made E_STRICT-clean while - // continuing to work on PHP 4. - // Therefore, in phpBB 3.0.x we disable E_STRICT on PHP 5.4+, - // while phpBB 3.1 will fix utf8 normalizer. - // E_STRICT is defined starting with PHP 5 - if (!defined('E_STRICT')) - { - define('E_STRICT', 2048); - } - $level &= ~E_STRICT; -} error_reporting($level); /* @@ -95,54 +84,6 @@ function deregister_globals() unset($input); } -/** - * Check if requested page uses a trailing path - * - * @param string $phpEx PHP extension - * - * @return bool True if trailing path is used, false if not - */ -function phpbb_has_trailing_path($phpEx) -{ - // Check if path_info is being used - if (!empty($_SERVER['PATH_INFO']) || (!empty($_SERVER['ORIG_PATH_INFO']) && $_SERVER['SCRIPT_NAME'] != $_SERVER['ORIG_PATH_INFO'])) - { - return true; - } - - // Match any trailing path appended to a php script in the REQUEST_URI. - // It is assumed that only actual PHP scripts use names like foo.php. Due - // to this, any phpBB board inside a directory that has the php extension - // appended to its name will stop working, i.e. if the board is at - // example.com/phpBB/test.php/ or example.com/test.php/ - if (preg_match('#^[^?]+\.' . preg_quote($phpEx, '#') . '/#', $_SERVER['REQUEST_URI'])) - { - return true; - } - - return false; -} - -// Check if trailing path is used -if (phpbb_has_trailing_path($phpEx)) -{ - if (substr(strtolower(@php_sapi_name()), 0, 3) === 'cgi') - { - $prefix = 'Status:'; - } - else if (!empty($_SERVER['SERVER_PROTOCOL'])) - { - $prefix = $_SERVER['SERVER_PROTOCOL']; - } - else - { - $prefix = 'HTTP/1.0'; - } - header("$prefix 404 Not Found", true, 404); - echo 'Trailing paths and PATH_INFO is not supported by phpBB 3.0'; - exit; -} - // Register globals and magic quotes have been dropped in PHP 5.4 if (version_compare(PHP_VERSION, '5.4.0-dev', '>=')) { @@ -192,5 +133,40 @@ if (function_exists('date_default_timezone_set') && function_exists('date_defaul date_default_timezone_set(@date_default_timezone_get()); } +// Autoloading of dependencies. +// Three options are supported: +// 1. If dependencies are installed with Composer, Composer will create a +// vendor/autoload.php. If this file exists it will be +// automatically used by phpBB. This is the default mode that phpBB +// will use when shipped. +// 2. To disable composer autoloading, PHPBB_NO_COMPOSER_AUTOLOAD can be specified. +// Additionally specify PHPBB_AUTOLOAD=/path/to/autoload.php in the +// environment. This is useful for running CLI scripts and tests. +// /path/to/autoload.php should define and register class loaders +// for all of phpBB's dependencies. +// 3. You can also set PHPBB_NO_COMPOSER_AUTOLOAD without setting PHPBB_AUTOLOAD. +// In this case autoloading needs to be defined before running any phpBB +// script. This might be useful in cases when phpBB is integrated into a +// larger program. +if (getenv('PHPBB_NO_COMPOSER_AUTOLOAD')) +{ + if (getenv('PHPBB_AUTOLOAD')) + { + require(getenv('PHPBB_AUTOLOAD')); + } +} +else +{ + if (!file_exists($phpbb_root_path . 'vendor/autoload.php')) + { + trigger_error( + 'Composer dependencies have not been set up yet, run ' . + "'php ../composer.phar install' from the phpBB directory to do so.", + E_USER_ERROR + ); + } + require($phpbb_root_path . 'vendor/autoload.php'); +} + $starttime = explode(' ', microtime()); $starttime = $starttime[1] + $starttime[0]; diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php deleted file mode 100644 index 9ac395344f..0000000000 --- a/phpBB/includes/template.php +++ /dev/null @@ -1,692 +0,0 @@ -<?php -/** -* -* @package phpBB3 -* @version $Id$ -* @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* Base Template class. -* @package phpBB3 -*/ -class template -{ - /** variable that holds all the data we'll be substituting into - * the compiled templates. Takes form: - * --> $this->_tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value - * if it's a root-level variable, it'll be like this: - * --> $this->_tpldata[.][0][varname] == value - */ - var $_tpldata = array('.' => array(0 => array())); - var $_rootref; - - // Root dir and hash of filenames for each template handle. - var $root = ''; - var $cachepath = ''; - var $files = array(); - var $filename = array(); - var $files_inherit = array(); - var $files_template = array(); - var $inherit_root = ''; - var $orig_tpl_storedb; - var $orig_tpl_inherits_id; - - // this will hash handle names to the compiled/uncompiled code for that handle. - var $compiled_code = array(); - - /** - * Set template location - * @access public - */ - function set_template() - { - global $phpbb_root_path, $user; - - if (file_exists($phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template')) - { - $this->root = $phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template'; - $this->cachepath = $phpbb_root_path . 'cache/tpl_' . str_replace('_', '-', $user->theme['template_path']) . '_'; - - if ($this->orig_tpl_storedb === null) - { - $this->orig_tpl_storedb = $user->theme['template_storedb']; - } - - if ($this->orig_tpl_inherits_id === null) - { - $this->orig_tpl_inherits_id = $user->theme['template_inherits_id']; - } - - $user->theme['template_storedb'] = $this->orig_tpl_storedb; - $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; - - if ($user->theme['template_inherits_id']) - { - $this->inherit_root = $phpbb_root_path . 'styles/' . $user->theme['template_inherit_path'] . '/template'; - } - } - else - { - trigger_error('Template path could not be found: styles/' . $user->theme['template_path'] . '/template', E_USER_ERROR); - } - - $this->_rootref = &$this->_tpldata['.'][0]; - - return true; - } - - /** - * Set custom template location (able to use directory outside of phpBB) - * @access public - */ - function set_custom_template($template_path, $template_name, $fallback_template_path = false) - { - global $phpbb_root_path, $user; - - // Make sure $template_path has no ending slash - if (substr($template_path, -1) == '/') - { - $template_path = substr($template_path, 0, -1); - } - - $this->root = $template_path; - $this->cachepath = $phpbb_root_path . 'cache/ctpl_' . str_replace('_', '-', $template_name) . '_'; - - if ($fallback_template_path !== false) - { - if (substr($fallback_template_path, -1) == '/') - { - $fallback_template_path = substr($fallback_template_path, 0, -1); - } - - $this->inherit_root = $fallback_template_path; - $this->orig_tpl_inherits_id = true; - } - else - { - $this->orig_tpl_inherits_id = false; - } - - // the database does not store the path or name of a custom template - // so there is no way we can properly store custom templates there - $this->orig_tpl_storedb = false; - - $this->_rootref = &$this->_tpldata['.'][0]; - - return true; - } - - /** - * Sets the template filenames for handles. $filename_array - * should be a hash of handle => filename pairs. - * @access public - */ - function set_filenames($filename_array) - { - if (!is_array($filename_array)) - { - return false; - } - foreach ($filename_array as $handle => $filename) - { - if (empty($filename)) - { - trigger_error("template->set_filenames: Empty filename specified for $handle", E_USER_ERROR); - } - - $this->filename[$handle] = $filename; - $this->files[$handle] = $this->root . '/' . $filename; - - if ($this->inherit_root) - { - $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename; - } - } - - return true; - } - - /** - * Destroy template data set - * @access public - */ - function destroy() - { - $this->_tpldata = array('.' => array(0 => array())); - $this->_rootref = &$this->_tpldata['.'][0]; - } - - /** - * Reset/empty complete block - * @access public - */ - function destroy_block_vars($blockname) - { - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - $str = &$this->_tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - $str = &$str[$blocks[$i]]; - $str = &$str[sizeof($str) - 1]; - } - - unset($str[$blocks[$blockcount]]); - } - else - { - // Top-level block. - unset($this->_tpldata[$blockname]); - } - - return true; - } - - /** - * Display handle - * @access public - */ - function display($handle, $include_once = true) - { - global $user, $phpbb_hook; - - if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, __FUNCTION__), $handle, $include_once, $this)) - { - if ($phpbb_hook->hook_return(array(__CLASS__, __FUNCTION__))) - { - return $phpbb_hook->hook_return_result(array(__CLASS__, __FUNCTION__)); - } - } - - if (defined('IN_ERROR_HANDLER')) - { - if ((E_NOTICE & error_reporting()) == E_NOTICE) - { - error_reporting(error_reporting() ^ E_NOTICE); - } - } - - if ($filename = $this->_tpl_load($handle)) - { - ($include_once) ? include_once($filename) : include($filename); - } - else - { - eval(' ?>' . $this->compiled_code[$handle] . '<?php '); - } - - return true; - } - - /** - * Display the handle and assign the output to a template variable or return the compiled result. - * @access public - */ - function assign_display($handle, $template_var = '', $return_content = true, $include_once = false) - { - ob_start(); - $this->display($handle, $include_once); - $contents = ob_get_clean(); - - if ($return_content) - { - return $contents; - } - - $this->assign_var($template_var, $contents); - - return true; - } - - /** - * Load a compiled template if possible, if not, recompile it - * @access private - */ - function _tpl_load(&$handle) - { - global $user, $phpEx, $config; - - if (!isset($this->filename[$handle])) - { - trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR); - } - - // reload these settings to have the values they had when this object was initialised - // using set_template or set_custom_template, they might otherwise have been overwritten - // by other template class instances in between. - $user->theme['template_storedb'] = $this->orig_tpl_storedb; - $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; - - $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; - $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0; - - $recompile = false; - if (!file_exists($filename) || @filesize($filename) === 0 || defined('DEBUG_EXTRA')) - { - $recompile = true; - } - else if ($config['load_tplcompile']) - { - // No way around it: we need to check inheritance here - if ($user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) - { - $this->files[$handle] = $this->files_inherit[$handle]; - $this->files_template[$handle] = $user->theme['template_inherits_id']; - } - $recompile = (@filemtime($filename) < filemtime($this->files[$handle])) ? true : false; - } - - // Recompile page if the original template is newer, otherwise load the compiled version - if (!$recompile) - { - return $filename; - } - - global $db, $phpbb_root_path; - - if (!class_exists('template_compile')) - { - include($phpbb_root_path . 'includes/functions_template.' . $phpEx); - } - - // Inheritance - we point to another template file for this one. Equality is also used for store_db - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) - { - $this->files[$handle] = $this->files_inherit[$handle]; - $this->files_template[$handle] = $user->theme['template_inherits_id']; - } - - $compile = new template_compile($this); - - // If we don't have a file assigned to this handle, die. - if (!isset($this->files[$handle])) - { - trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR); - } - - // Just compile if no user object is present (happens within the installer) - if (!$user) - { - $compile->_tpl_load_file($handle); - return false; - } - - if (isset($user->theme['template_storedb']) && $user->theme['template_storedb']) - { - $rows = array(); - $ids = array(); - // Inheritance - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id']) - { - $ids[] = $user->theme['template_inherits_id']; - } - $ids[] = $user->theme['template_id']; - - foreach ($ids as $id) - { - $sql = 'SELECT * - FROM ' . STYLES_TEMPLATE_DATA_TABLE . ' - WHERE template_id = ' . $id . " - AND (template_filename = '" . $db->sql_escape($this->filename[$handle]) . "' - OR template_included " . $db->sql_like_expression($db->any_char . $this->filename[$handle] . ':' . $db->any_char) . ')'; - - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - $rows[$row['template_filename']] = $row; - } - $db->sql_freeresult($result); - } - - if (sizeof($rows)) - { - foreach ($rows as $row) - { - $file = $this->root . '/' . $row['template_filename']; - $force_reload = false; - if ($row['template_id'] != $user->theme['template_id']) - { - // make sure that we are not overlooking a file not in the db yet - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($file)) - { - $file = $this->inherit_root . '/' . $row['template_filename']; - $this->files[$row['template_filename']] = $file; - $this->files_inherit[$row['template_filename']] = $file; - $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id']; - } - else if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id']) - { - // Ok, we have a situation. There is a file in the subtemplate, but nothing in the DB. We have to fix that. - $force_reload = true; - $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id']; - } - } - else - { - $this->files_template[$row['template_filename']] = $user->theme['template_id']; - } - - if ($force_reload || $row['template_mtime'] < filemtime($file)) - { - if ($row['template_filename'] == $this->filename[$handle]) - { - $compile->_tpl_load_file($handle, true); - } - else - { - $this->files[$row['template_filename']] = $file; - $this->filename[$row['template_filename']] = $row['template_filename']; - $compile->_tpl_load_file($row['template_filename'], true); - unset($this->compiled_code[$row['template_filename']]); - unset($this->files[$row['template_filename']]); - unset($this->filename[$row['template_filename']]); - } - } - - if ($row['template_filename'] == $this->filename[$handle]) - { - $this->compiled_code[$handle] = $compile->compile(trim($row['template_data'])); - $compile->compile_write($handle, $this->compiled_code[$handle]); - } - else - { - // Only bother compiling if it doesn't already exist - if (!file_exists($this->cachepath . str_replace('/', '.', $row['template_filename']) . '.' . $phpEx)) - { - $this->filename[$row['template_filename']] = $row['template_filename']; - $compile->compile_write($row['template_filename'], $compile->compile(trim($row['template_data']))); - unset($this->filename[$row['template_filename']]); - } - } - } - } - else - { - $file = $this->root . '/' . $row['template_filename']; - - if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($file)) - { - $file = $this->inherit_root . '/' . $row['template_filename']; - $this->files[$row['template_filename']] = $file; - $this->files_inherit[$row['template_filename']] = $file; - $this->files_template[$row['template_filename']] = $user->theme['template_inherits_id']; - } - // Try to load from filesystem and instruct to insert into the styles table... - $compile->_tpl_load_file($handle, true); - return false; - } - - return false; - } - - $compile->_tpl_load_file($handle); - return false; - } - - /** - * Assign key variable pairs from an array - * @access public - */ - function assign_vars($vararray) - { - foreach ($vararray as $key => $val) - { - $this->_rootref[$key] = $val; - } - - return true; - } - - /** - * Assign a single variable to a single key - * @access public - */ - function assign_var($varname, $varval) - { - $this->_rootref[$varname] = $varval; - - return true; - } - - /** - * Assign key variable pairs from an array to a specified block - * @access public - */ - function assign_block_vars($blockname, $vararray) - { - if (strpos($blockname, '.') !== false) - { - // Nested block. - $blocks = explode('.', $blockname); - $blockcount = sizeof($blocks) - 1; - - $str = &$this->_tpldata; - for ($i = 0; $i < $blockcount; $i++) - { - $str = &$str[$blocks[$i]]; - $str = &$str[sizeof($str) - 1]; - } - - $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0; - $vararray['S_ROW_COUNT'] = $s_row_count; - - // Assign S_FIRST_ROW - if (!$s_row_count) - { - $vararray['S_FIRST_ROW'] = true; - } - - // Now the tricky part, we always assign S_LAST_ROW and remove the entry before - // This is much more clever than going through the complete template data on display (phew) - $vararray['S_LAST_ROW'] = true; - if ($s_row_count > 0) - { - unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']); - } - - // Now we add the block that we're actually assigning to. - // We're adding a new iteration to this block with the given - // variable assignments. - $str[$blocks[$blockcount]][] = $vararray; - } - else - { - // Top-level block. - $s_row_count = (isset($this->_tpldata[$blockname])) ? sizeof($this->_tpldata[$blockname]) : 0; - $vararray['S_ROW_COUNT'] = $s_row_count; - - // Assign S_FIRST_ROW - if (!$s_row_count) - { - $vararray['S_FIRST_ROW'] = true; - } - - // We always assign S_LAST_ROW and remove the entry before - $vararray['S_LAST_ROW'] = true; - if ($s_row_count > 0) - { - unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']); - } - - // Add a new iteration to this block with the variable assignments we were given. - $this->_tpldata[$blockname][] = $vararray; - } - - return true; - } - - /** - * Change already assigned key variable pair (one-dimensional - single loop entry) - * - * An example of how to use this function: - * {@example alter_block_array.php} - * - * @param string $blockname the blockname, for example 'loop' - * @param array $vararray the var array to insert/add or merge - * @param mixed $key Key to search for - * - * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] - * - * int: Position [the position to change or insert at directly given] - * - * If key is false the position is set to 0 - * If key is true the position is set to the last entry - * - * @param string $mode Mode to execute (valid modes are 'insert' and 'change') - * - * If insert, the vararray is inserted at the given position (position counting from zero). - * If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new value). - * - * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array) - * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars) - * - * @return bool false on error, true on success - * @access public - */ - function alter_block_array($blockname, $vararray, $key = false, $mode = 'insert') - { - if (strpos($blockname, '.') !== false) - { - // Nested blocks are not supported - return false; - } - - // Change key to zero (change first position) if false and to last position if true - if ($key === false || $key === true) - { - $key = ($key === false) ? 0 : sizeof($this->_tpldata[$blockname]); - } - - // Get correct position if array given - if (is_array($key)) - { - // Search array to get correct position - list($search_key, $search_value) = @each($key); - - $key = NULL; - foreach ($this->_tpldata[$blockname] as $i => $val_ary) - { - if ($val_ary[$search_key] === $search_value) - { - $key = $i; - break; - } - } - - // key/value pair not found - if ($key === NULL) - { - return false; - } - } - - // Insert Block - if ($mode == 'insert') - { - // Make sure we are not exceeding the last iteration - if ($key >= sizeof($this->_tpldata[$blockname])) - { - $key = sizeof($this->_tpldata[$blockname]); - unset($this->_tpldata[$blockname][($key - 1)]['S_LAST_ROW']); - $vararray['S_LAST_ROW'] = true; - } - else if ($key === 0) - { - unset($this->_tpldata[$blockname][0]['S_FIRST_ROW']); - $vararray['S_FIRST_ROW'] = true; - } - - // Re-position template blocks - for ($i = sizeof($this->_tpldata[$blockname]); $i > $key; $i--) - { - $this->_tpldata[$blockname][$i] = $this->_tpldata[$blockname][$i-1]; - $this->_tpldata[$blockname][$i]['S_ROW_COUNT'] = $i; - } - - // Insert vararray at given position - $vararray['S_ROW_COUNT'] = $key; - $this->_tpldata[$blockname][$key] = $vararray; - - return true; - } - - // Which block to change? - if ($mode == 'change') - { - if ($key == sizeof($this->_tpldata[$blockname])) - { - $key--; - } - - $this->_tpldata[$blockname][$key] = array_merge($this->_tpldata[$blockname][$key], $vararray); - return true; - } - - return false; - } - - /** - * Include a separate template - * @access private - */ - function _tpl_include($filename, $include = true) - { - $handle = $filename; - $this->filename[$handle] = $filename; - $this->files[$handle] = $this->root . '/' . $filename; - if ($this->inherit_root) - { - $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename; - } - - $filename = $this->_tpl_load($handle); - - if ($include) - { - global $user; - - if ($filename) - { - include($filename); - return; - } - eval(' ?>' . $this->compiled_code[$handle] . '<?php '); - } - } - - /** - * Include a php-file - * @access private - */ - function _php_include($filename) - { - global $phpbb_root_path; - - $file = $phpbb_root_path . $filename; - - if (!file_exists($file)) - { - // trigger_error cannot be used here, as the output already started - echo 'template->_php_include(): File ' . htmlspecialchars($file) . ' does not exist or is empty'; - return; - } - include($file); - } -} - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/info/ucp_attachments.php b/phpBB/includes/ucp/info/ucp_attachments.php index 84edce446c..2e20106f5c 100644 --- a/phpBB/includes/ucp/info/ucp_attachments.php +++ b/phpBB/includes/ucp/info/ucp_attachments.php @@ -1,16 +1,16 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class ucp_attachments_info { function module() @@ -33,5 +33,3 @@ class ucp_attachments_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/info/ucp_auth_link.php b/phpBB/includes/ucp/info/ucp_auth_link.php new file mode 100644 index 0000000000..9ec4cb7b3a --- /dev/null +++ b/phpBB/includes/ucp/info/ucp_auth_link.php @@ -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. +* +*/ + +class ucp_auth_link_info +{ + function module() + { + return array( + 'filename' => 'ucp_auth_link', + 'title' => 'UCP_AUTH_LINK', + 'version' => '1.0.0', + 'modes' => array( + 'auth_link' => array('title' => 'UCP_AUTH_LINK_MANAGE', 'auth' => 'authmethod_oauth', 'cat' => array('UCP_PROFILE')), + ), + ); + } + + function install() + { + } + + function uninstall() + { + } +} diff --git a/phpBB/includes/ucp/info/ucp_groups.php b/phpBB/includes/ucp/info/ucp_groups.php index 2002123c50..6da2a4fe38 100644 --- a/phpBB/includes/ucp/info/ucp_groups.php +++ b/phpBB/includes/ucp/info/ucp_groups.php @@ -1,16 +1,16 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class ucp_groups_info { function module() @@ -34,5 +34,3 @@ class ucp_groups_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/info/ucp_main.php b/phpBB/includes/ucp/info/ucp_main.php index 722b7865e6..de8e7d5602 100644 --- a/phpBB/includes/ucp/info/ucp_main.php +++ b/phpBB/includes/ucp/info/ucp_main.php @@ -1,16 +1,16 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class ucp_main_info { function module() @@ -36,5 +36,3 @@ class ucp_main_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/info/ucp_notifications.php b/phpBB/includes/ucp/info/ucp_notifications.php new file mode 100644 index 0000000000..0cc011d96e --- /dev/null +++ b/phpBB/includes/ucp/info/ucp_notifications.php @@ -0,0 +1,36 @@ +<?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. +* +*/ + +class ucp_notifications_info +{ + function module() + { + return array( + 'filename' => 'ucp_notifications', + 'title' => 'UCP_NOTIFICATION_OPTIONS', + 'version' => '1.0.0', + 'modes' => array( + 'notification_options' => array('title' => 'UCP_NOTIFICATION_OPTIONS', 'auth' => '', 'cat' => array('UCP_PREFS')), + 'notification_list' => array('title' => 'UCP_NOTIFICATION_LIST', 'auth' => '', 'cat' => array('UCP_MAIN')), + ), + ); + } + + function install() + { + } + + function uninstall() + { + } +} diff --git a/phpBB/includes/ucp/info/ucp_pm.php b/phpBB/includes/ucp/info/ucp_pm.php index ade12005c0..6aa1669cb6 100644 --- a/phpBB/includes/ucp/info/ucp_pm.php +++ b/phpBB/includes/ucp/info/ucp_pm.php @@ -1,15 +1,16 @@ <?php /** -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +* 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. * */ -/** -* @package module_install -*/ class ucp_pm_info { function module() @@ -23,7 +24,6 @@ class ucp_pm_info 'compose' => array('title' => 'UCP_PM_COMPOSE', 'auth' => 'cfg_allow_privmsg', 'cat' => array('UCP_PM')), 'drafts' => array('title' => 'UCP_PM_DRAFTS', 'auth' => 'cfg_allow_privmsg', 'cat' => array('UCP_PM')), 'options' => array('title' => 'UCP_PM_OPTIONS', 'auth' => 'cfg_allow_privmsg', 'cat' => array('UCP_PM')), - 'popup' => array('title' => 'UCP_PM_POPUP_TITLE', 'auth' => 'cfg_allow_privmsg', 'display' => false, 'cat' => array('UCP_PM')), ), ); } @@ -36,5 +36,3 @@ class ucp_pm_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/info/ucp_prefs.php b/phpBB/includes/ucp/info/ucp_prefs.php index 58359e8a19..5c2d29ac73 100644 --- a/phpBB/includes/ucp/info/ucp_prefs.php +++ b/phpBB/includes/ucp/info/ucp_prefs.php @@ -1,16 +1,16 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class ucp_prefs_info { function module() @@ -35,5 +35,3 @@ class ucp_prefs_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php index 4591776768..919de99a96 100644 --- a/phpBB/includes/ucp/info/ucp_profile.php +++ b/phpBB/includes/ucp/info/ucp_profile.php @@ -1,16 +1,16 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class ucp_profile_info { function module() @@ -20,10 +20,11 @@ class ucp_profile_info 'title' => 'UCP_PROFILE', 'version' => '1.0.0', 'modes' => array( - 'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => '', 'cat' => array('UCP_PROFILE')), + 'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => 'acl_u_chgprofileinfo', 'cat' => array('UCP_PROFILE')), 'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => 'acl_u_sig', 'cat' => array('UCP_PROFILE')), - 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)', 'cat' => array('UCP_PROFILE')), + 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar', 'cat' => array('UCP_PROFILE')), 'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')), + 'autologin_keys'=> array('title' => 'UCP_PROFILE_AUTOLOGIN_KEYS', 'auth' => '', 'cat' => array('UCP_PROFILE')), ), ); } @@ -36,5 +37,3 @@ class ucp_profile_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/info/ucp_zebra.php b/phpBB/includes/ucp/info/ucp_zebra.php index 5fc1f8bee7..99d4a4f4c0 100644 --- a/phpBB/includes/ucp/info/ucp_zebra.php +++ b/phpBB/includes/ucp/info/ucp_zebra.php @@ -1,16 +1,16 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ -/** -* @package module_install -*/ class ucp_zebra_info { function module() @@ -34,5 +34,3 @@ class ucp_zebra_info { } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php index b262dc5c1c..6e357b260a 100644 --- a/phpBB/includes/ucp/ucp_activate.php +++ b/phpBB/includes/ucp/ucp_activate.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * ucp_activate * User activation -* @package ucp */ class ucp_activate { @@ -28,7 +30,7 @@ class ucp_activate function main($id, $mode) { global $config, $phpbb_root_path, $phpEx; - global $db, $user, $auth, $template; + global $db, $user, $auth, $template, $phpbb_container; $user_id = request_var('u', 0); $key = request_var('k', ''); @@ -76,7 +78,6 @@ class ucp_activate 'user_actkey' => '', 'user_password' => $user_row['user_newpasswd'], 'user_newpasswd' => '', - 'user_pass_convert' => 0, 'user_login_attempts' => 0, ); @@ -109,13 +110,16 @@ class ucp_activate if ($config['require_activation'] == USER_ACTIVATION_ADMIN && !$update_password) { + $phpbb_notifications = $phpbb_container->get('notification_manager'); + $phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_row['user_id']); + include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); $messenger = new messenger(false); $messenger->template('admin_welcome_activated', $user_row['user_lang']); - $messenger->to($user_row['user_email'], $user_row['username']); + $messenger->set_addresses($user_row); $messenger->anti_abuse_headers($config, $user); @@ -143,5 +147,3 @@ class ucp_activate trigger_error($user->lang[$message]); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_attachments.php b/phpBB/includes/ucp/ucp_attachments.php index b011b4f75d..42724209aa 100644 --- a/phpBB/includes/ucp/ucp_attachments.php +++ b/phpBB/includes/ucp/ucp_attachments.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * ucp_attachments * User attachments -* @package ucp */ class ucp_attachments { @@ -27,7 +29,7 @@ class ucp_attachments function main($id, $mode) { - global $template, $user, $db, $config, $phpEx, $phpbb_root_path; + global $template, $user, $db, $config, $phpEx, $phpbb_root_path, $phpbb_container; $start = request_var('start', 0); $sort_key = request_var('sk', 'a'); @@ -120,6 +122,10 @@ class ucp_attachments $num_attachments = $db->sql_fetchfield('num_attachments'); $db->sql_freeresult($result); + // Ensure start is a valid value + $pagination = $phpbb_container->get('pagination'); + $start = $pagination->validate_start($start, $config['topics_per_page'], $num_attachments); + $sql = 'SELECT a.*, t.topic_title, p.message_subject as message_title FROM ' . ATTACHMENTS_TABLE . ' a LEFT JOIN ' . TOPICS_TABLE . ' t ON (a.topic_id = t.topic_id AND a.in_message = 0) @@ -171,10 +177,12 @@ class ucp_attachments } $db->sql_freeresult($result); + $base_url = $this->u_action . "&sk=$sort_key&sd=$sort_dir"; + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $num_attachments, $config['topics_per_page'], $start); + $template->assign_vars(array( - 'PAGE_NUMBER' => on_page($num_attachments, $config['topics_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&sk=$sort_key&sd=$sort_dir", $num_attachments, $config['topics_per_page'], $start), 'TOTAL_ATTACHMENTS' => $num_attachments, + 'NUM_ATTACHMENTS' => $user->lang('NUM_ATTACHMENTS', $num_attachments), 'L_TITLE' => $user->lang['UCP_ATTACHMENTS'], @@ -197,5 +205,3 @@ class ucp_attachments $this->page_title = 'UCP_ATTACHMENTS'; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_auth_link.php b/phpBB/includes/ucp/ucp_auth_link.php new file mode 100644 index 0000000000..748f0fdec2 --- /dev/null +++ b/phpBB/includes/ucp/ucp_auth_link.php @@ -0,0 +1,147 @@ +<?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. +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +class ucp_auth_link +{ + /** + * @var string + */ + public $u_action; + + /** + * Generates the ucp_auth_link page and handles the auth link process + * + * @param int $id + * @param string $mode + */ + public function main($id, $mode) + { + global $request, $template, $phpbb_container, $user; + + $error = array(); + + $provider_collection = $phpbb_container->get('auth.provider_collection'); + $auth_provider = $provider_collection->get_provider(); + + // confirm that the auth provider supports this page + $provider_data = $auth_provider->get_auth_link_data(); + if ($provider_data === null) + { + $error[] = 'UCP_AUTH_LINK_NOT_SUPPORTED'; + } + + $s_hidden_fields = array(); + add_form_key('ucp_auth_link'); + + $submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST); + + // This path is only for primary actions + if (!sizeof($error) && $submit) + { + if (!check_form_key('ucp_auth_link')) + { + $error[] = 'FORM_INVALID'; + } + + if (!sizeof($error)) + { + // Any post data could be necessary for auth (un)linking + $link_data = $request->get_super_global(\phpbb\request\request_interface::POST); + + // The current user_id is also necessary + $link_data['user_id'] = $user->data['user_id']; + + // Tell the provider that the method is auth_link not login_link + $link_data['link_method'] = 'auth_link'; + + if ($request->variable('link', 0, false, \phpbb\request\request_interface::POST)) + { + $error[] = $auth_provider->link_account($link_data); + } + else + { + $error[] = $auth_provider->unlink_account($link_data); + } + + // Template data may have changed, get new data + $provider_data = $auth_provider->get_auth_link_data(); + } + } + + // In some cases, a request to an external server may be required. In + // these cases, the GET parameter 'link' should exist and should be true + if ($request->variable('link', false)) + { + // In this case the link data should only be populated with the + // link_method as the provider dictates how data is returned to it. + $link_data = array('link_method' => 'auth_link'); + + $error[] = $auth_provider->link_account($link_data); + + // Template data may have changed, get new data + $provider_data = $auth_provider->get_auth_link_data(); + } + + if (isset($provider_data['VARS'])) + { + // Handle hidden fields separately + if (isset($provider_data['VARS']['HIDDEN_FIELDS'])) + { + $s_hidden_fields = array_merge($s_hidden_fields, $provider_data['VARS']['HIDDEN_FIELDS']); + unset($provider_data['VARS']['HIDDEN_FIELDS']); + } + + $template->assign_vars($provider_data['VARS']); + } + + if (isset($provider_data['BLOCK_VAR_NAME'])) + { + foreach ($provider_data['BLOCK_VARS'] as $block_vars) + { + // See if there are additional hidden fields. This should be an associative array + if (isset($block_vars['HIDDEN_FIELDS'])) + { + $block_vars['HIDDEN_FIELDS'] = build_hidden_fields($block_vars['HIDDEN_FIELDS']); + } + + $template->assign_block_vars($provider_data['BLOCK_VAR_NAME'], $block_vars); + } + } + + $s_hidden_fields = build_hidden_fields($s_hidden_fields); + + // Replace "error" strings with their real, localised form + $error = array_map(array($user, 'lang'), $error); + $error = implode('<br />', $error); + + $template->assign_vars(array( + 'ERROR' => $error, + + 'PROVIDER_TEMPLATE_FILE' => $provider_data['TEMPLATE_FILE'], + + 'S_HIDDEN_FIELDS' => $s_hidden_fields, + 'S_UCP_ACTION' => $this->u_action, + )); + + $this->tpl_name = 'ucp_auth_link'; + $this->page_title = 'UCP_AUTH_LINK'; + } +} diff --git a/phpBB/includes/ucp/ucp_confirm.php b/phpBB/includes/ucp/ucp_confirm.php index 445f7c7d2a..7392f8dea8 100644 --- a/phpBB/includes/ucp/ucp_confirm.php +++ b/phpBB/includes/ucp/ucp_confirm.php @@ -1,10 +1,13 @@ <?php /** * -* @package VC -* @version $Id$ -* @copyright (c) 2005 2008 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -26,8 +29,6 @@ if (!defined('IN_PHPBB')) * to that licence. Do not incorporate this within software * released or distributed in any way under a licence other * than the GPL. We will be watching ... ;) -* -* @package VC */ class ucp_confirm { @@ -35,10 +36,9 @@ class ucp_confirm function main($id, $mode) { - global $db, $user, $phpbb_root_path, $config, $phpEx; + global $db, $user, $phpbb_root_path, $config, $phpEx, $phpbb_container; - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); $captcha->init(request_var('type', 0)); $captcha->execute(); @@ -46,5 +46,3 @@ class ucp_confirm exit_handler(); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php index 663b5bc931..b9606945b4 100644 --- a/phpBB/includes/ucp/ucp_groups.php +++ b/phpBB/includes/ucp/ucp_groups.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -18,7 +21,6 @@ if (!defined('IN_PHPBB')) /** * ucp_groups -* @package ucp */ class ucp_groups { @@ -26,16 +28,17 @@ class ucp_groups function main($id, $mode) { - global $config, $phpbb_root_path, $phpEx; + global $config, $phpbb_root_path, $phpEx, $phpbb_admin_path; global $db, $user, $auth, $cache, $template; + global $request, $phpbb_container; $user->add_lang('groups'); $return_page = '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $this->u_action . '">', '</a>'); $mark_ary = request_var('mark', array(0)); - $submit = (!empty($_POST['submit'])) ? true : false; - $delete = (!empty($_POST['delete'])) ? true : false; + $submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST); + $delete = $request->variable('delete', false, false, \phpbb\request\request_interface::POST); $error = $data = array(); switch ($mode) @@ -197,38 +200,6 @@ class ucp_groups else { group_user_add($group_id, $user->data['user_id'], false, false, false, 0, 1); - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $messenger = new messenger(); - - $sql = 'SELECT u.username, u.username_clean, u.user_email, u.user_notify_type, u.user_jabber, u.user_lang - FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . " u - WHERE ug.user_id = u.user_id - AND ug.group_leader = 1 - AND ug.group_id = $group_id"; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $messenger->template('group_request', $row['user_lang']); - - $messenger->to($row['user_email'], $row['username']); - $messenger->im($row['user_jabber'], $row['username']); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($row['username']), - 'GROUP_NAME' => htmlspecialchars_decode($group_row[$group_id]['group_name']), - 'REQUEST_USERNAME' => $user->data['username'], - - 'U_PENDING' => generate_board_url() . "/ucp.$phpEx?i=groups&mode=manage&action=list&g=$group_id", - 'U_GROUP' => generate_board_url() . "/memberlist.$phpEx?mode=group&g=$group_id") - ); - - $messenger->send($row['user_notify_type']); - } - $db->sql_freeresult($result); - - $messenger->save_queue(); } add_log('user', $user->data['user_id'], 'LOG_USER_GROUP_JOIN' . (($group_row[$group_id]['group_type'] == GROUP_FREE) ? '' : '_PENDING'), $group_row[$group_id]['group_name']); @@ -417,9 +388,11 @@ class ucp_groups if ($group_id) { - $sql = 'SELECT * - FROM ' . GROUPS_TABLE . " - WHERE group_id = $group_id"; + $sql = 'SELECT g.*, t.teampage_position AS group_teampage + FROM ' . GROUPS_TABLE . ' g + LEFT JOIN ' . TEAMPAGE_TABLE . ' t + ON (t.group_id = g.group_id) + WHERE g.group_id = ' . $group_id; $result = $db->sql_query($sql); $group_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -438,7 +411,7 @@ class ucp_groups $group_name = $group_row['group_name']; $group_type = $group_row['group_type']; - $avatar_img = (!empty($group_row['group_avatar'])) ? get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR') : '<img src="' . $phpbb_root_path . 'adm/images/no_avatar.gif" alt="" />'; + $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true); $template->assign_vars(array( 'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name, @@ -447,8 +420,8 @@ class ucp_groups 'GROUP_DESC_DISP' => generate_text_for_display($group_row['group_desc'], $group_row['group_desc_uid'], $group_row['group_desc_bitfield'], $group_row['group_desc_options']), 'GROUP_TYPE' => $group_row['group_type'], - 'AVATAR' => $avatar_img, - 'AVATAR_IMAGE' => $avatar_img, + 'AVATAR' => (empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar), + 'AVATAR_IMAGE' => (empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar), 'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '', 'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '', )); @@ -483,10 +456,43 @@ class ucp_groups $error = array(); - $avatar_select = basename(request_var('avatar_select', '')); - $category = basename(request_var('category', '')); + // Setup avatar data for later + $avatars_enabled = false; + $avatar_drivers = null; + $avatar_data = null; + $avatar_error = array(); + + if ($config['allow_avatar']) + { + $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); + $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers(); + + // This is normalised data, without the group_ prefix + $avatar_data = \phpbb\avatar\manager::clean_row($group_row, 'group'); + } + + // Handle deletion of avatars + if ($request->is_set_post('avatar_delete')) + { + if (confirm_box(true)) + { + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, GROUPS_TABLE, 'group_'); + $cache->destroy('sql', GROUPS_TABLE); - $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false; + $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; + trigger_error($user->lang[$message] . $return_page); + } + else + { + confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( + 'avatar_delete' => true, + 'i' => $id, + 'mode' => $mode, + 'g' => $group_id, + 'action' => $action)) + ); + } + } // Did we submit? if ($update) @@ -505,89 +511,31 @@ class ucp_groups 'receive_pm' => isset($_REQUEST['group_receive_pm']) ? 1 : 0, 'message_limit' => request_var('group_message_limit', 0), 'max_recipients'=> request_var('group_max_recipients', 0), + 'legend' => $group_row['group_legend'], + 'teampage' => $group_row['group_teampage'], ); - $data['uploadurl'] = request_var('uploadurl', ''); - $data['remotelink'] = request_var('remotelink', ''); - $data['width'] = request_var('width', ''); - $data['height'] = request_var('height', ''); - $delete = request_var('delete', ''); - - if (!empty($_FILES['uploadfile']['tmp_name']) || $data['uploadurl'] || $data['remotelink']) + if ($config['allow_avatar']) { - // Avatar stuff - $var_ary = array( - 'uploadurl' => array('string', true, 5, 255), - 'remotelink' => array('string', true, 5, 255), - 'width' => array('string', true, 1, 3), - 'height' => array('string', true, 1, 3), - ); - - if (!($error = validate_data($data, $var_ary))) - { - $data['user_id'] = "g$group_id"; + // Handle avatar + $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', '')); + $config_name = preg_replace('#^avatar\.driver.#', '', $driver_name); - if ((!empty($_FILES['uploadfile']['tmp_name']) || $data['uploadurl']) && $can_upload) - { - list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_upload($data, $error); - } - else if ($data['remotelink']) - { - list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_remote($data, $error); - } - } - } - else if ($avatar_select && $config['allow_avatar_local']) - { - // check avatar gallery - if (is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category)) + if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) { - $submit_ary['avatar_type'] = AVATAR_GALLERY; + $driver = $phpbb_avatar_manager->get_driver($driver_name); + $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error); - list($submit_ary['avatar_width'], $submit_ary['avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $avatar_select); - $submit_ary['avatar'] = $category . '/' . $avatar_select; - } - } - else if ($delete) - { - $submit_ary['avatar'] = ''; - $submit_ary['avatar_type'] = $submit_ary['avatar_width'] = $submit_ary['avatar_height'] = 0; - } - else if ($data['width'] && $data['height']) - { - // Only update the dimensions? - if ($config['avatar_max_width'] || $config['avatar_max_height']) - { - if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height']) + if ($result && empty($avatar_error)) { - $error[] = sprintf($user->lang['AVATAR_WRONG_SIZE'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], $data['width'], $data['height']); - } - } + $result['avatar_type'] = $driver_name; - if (!sizeof($error)) - { - if ($config['avatar_min_width'] || $config['avatar_min_height']) - { - if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height']) - { - $error[] = sprintf($user->lang['AVATAR_WRONG_SIZE'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], $data['width'], $data['height']); - } + $submit_ary = array_merge($submit_ary, $result); } } - if (!sizeof($error)) - { - $submit_ary['avatar_width'] = $data['width']; - $submit_ary['avatar_height'] = $data['height']; - } - } - - if ((isset($submit_ary['avatar']) && $submit_ary['avatar'] && (!isset($group_row['group_avatar']))) || $delete) - { - if (isset($group_row['group_avatar']) && $group_row['group_avatar']) - { - avatar_delete('group', $group_row, true); - } + // Merge any avatars errors into the primary error array + $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error)); } if (!check_form_key('ucp_groups')) @@ -607,24 +555,28 @@ class ucp_groups // Only set the rank, colour, etc. if it's changed or if we're adding a new // group. This prevents existing group members being updated if no changes // were made. + // However there are some attributes that need to be set everytime, + // otherwise the group gets removed from the feature. + $set_attributes = array('legend', 'teampage'); $group_attributes = array(); $test_variables = array( 'rank' => 'int', 'colour' => 'string', 'avatar' => 'string', - 'avatar_type' => 'int', + 'avatar_type' => 'string', 'avatar_width' => 'int', 'avatar_height' => 'int', 'receive_pm' => 'int', 'legend' => 'int', + 'teampage' => 'int', 'message_limit' => 'int', 'max_recipients'=> 'int', ); foreach ($test_variables as $test => $type) { - if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test])) + if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test] || isset($group_attributes['group_avatar']) && strpos($test, 'avatar') === 0 || in_array($test, $set_attributes))) { settype($submit_ary[$test], $type); $group_attributes['group_' . $test] = $group_row['group_' . $test] = $submit_ary[$test]; @@ -634,6 +586,7 @@ class ucp_groups if (!($error = group_create($group_id, $group_type, $group_name, $group_desc, $group_attributes, $allow_desc_bbcode, $allow_desc_urls, $allow_desc_smilies))) { $cache->destroy('sql', GROUPS_TABLE); + $cache->destroy('sql', TEAMPAGE_TABLE); $message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED'; trigger_error($user->lang[$message] . $return_page); @@ -690,28 +643,51 @@ class ucp_groups $type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : ''; $type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : ''; - $display_gallery = (isset($_POST['display_gallery'])) ? true : false; - - if ($config['allow_avatar'] && $config['allow_avatar_local'] && $display_gallery) + // Load up stuff for avatars + if ($config['allow_avatar']) { - avatar_gallery($category, $avatar_select, 4); + $avatars_enabled = false; + $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type'])); + + foreach ($avatar_drivers as $current_driver) + { + $driver = $phpbb_avatar_manager->get_driver($current_driver); + + $avatars_enabled = true; + $template->set_filenames(array( + 'avatar' => $driver->get_template_name(), + )); + + if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error)) + { + $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); + $driver_upper = strtoupper($driver_name); + $template->assign_block_vars('avatar_drivers', array( + 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), + 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), + + 'DRIVER' => $driver_name, + 'SELECTED' => $current_driver == $selected_driver, + 'OUTPUT' => $template->assign_display('avatar'), + )); + } + } } - $avatars_enabled = ($config['allow_avatar'] && (($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) || ($config['allow_avatar_local'] || $config['allow_avatar_remote']))) ? true : false; + if (isset($phpbb_avatar_manager) && !$update) + { + // Merge any avatars errors into the primary error array + $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error)); + } $template->assign_vars(array( 'S_EDIT' => true, 'S_INCLUDE_SWATCH' => true, - 'S_FORM_ENCTYPE' => ($config['allow_avatar'] && $can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '', + 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"', 'S_ERROR' => (sizeof($error)) ? true : false, 'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false, - 'S_AVATARS_ENABLED' => $avatars_enabled, - 'S_DISPLAY_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && !$display_gallery) ? true : false, - 'S_IN_GALLERY' => ($config['allow_avatar_local'] && $display_gallery) ? true : false, - - 'S_UPLOAD_AVATAR_FILE' => ($config['allow_avatar'] && $config['allow_avatar_upload'] && $can_upload) ? true : false, - 'S_UPLOAD_AVATAR_URL' => ($config['allow_avatar'] && $config['allow_avatar_remote_upload'] && $can_upload) ? true : false, - 'S_LINK_AVATAR' => ($config['allow_avatar'] && $config['allow_avatar_remote']) ? true : false, + 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled), + 'S_GROUP_MANAGE' => true, 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '', 'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '', @@ -724,7 +700,6 @@ class ucp_groups 'S_DESC_SMILIES_CHECKED'=> $group_desc_data['allow_smilies'], 'S_RANK_OPTIONS' => $rank_options, - 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'], 'GROUP_TYPE_FREE' => GROUP_FREE, 'GROUP_TYPE_OPEN' => GROUP_OPEN, @@ -737,9 +712,8 @@ class ucp_groups 'GROUP_CLOSED' => $type_closed, 'GROUP_HIDDEN' => $type_hidden, - 'U_SWATCH' => append_sid("{$phpbb_root_path}adm/swatch.$phpEx", 'form=ucp&name=group_colour'), 'S_UCP_ACTION' => $this->u_action . "&action=$action&g=$group_id", - 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], $config['avatar_filesize'] / 1024), + 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(), )); break; @@ -852,11 +826,14 @@ class ucp_groups $s_action_options .= '<option value="' . $option . '">' . $user->lang['GROUP_' . $lang] . '</option>'; } + $pagination = $phpbb_container->get('pagination'); + $base_url = $this->u_action . "&action=$action&g=$group_id"; + $start = $pagination->validate_start($start, $config['topics_per_page'], $total_members); + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_members, $config['topics_per_page'], $start); + $template->assign_vars(array( 'S_LIST' => true, 'S_ACTION_OPTIONS' => $s_action_options, - 'S_ON_PAGE' => on_page($total_members, $config['topics_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&action=$action&g=$group_id", $total_members, $config['topics_per_page'], $start), 'U_ACTION' => $this->u_action . "&g=$group_id", 'S_UCP_ACTION' => $this->u_action . "&g=$group_id", @@ -1075,7 +1052,8 @@ class ucp_groups 'mode' => $mode, 'action' => $action ); - confirm_box(false, sprintf($user->lang['GROUP_CONFIRM_ADD_USER' . ((sizeof($name_ary) == 1) ? '' : 'S')], implode(', ', $name_ary)), build_hidden_fields($s_hidden_fields)); + + confirm_box(false, $user->lang('GROUP_CONFIRM_ADD_USERS', sizeof($name_ary), implode($user->lang['COMMA_SEPARATOR'], $name_ary)), build_hidden_fields($s_hidden_fields)); } trigger_error($user->lang['NO_USERS_ADDED'] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $this->u_action . '&action=list&g=' . $group_id . '">', '</a>')); @@ -1117,5 +1095,3 @@ class ucp_groups $this->tpl_name = 'ucp_groups_' . $mode; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_login_link.php b/phpBB/includes/ucp/ucp_login_link.php new file mode 100644 index 0000000000..bfe4804286 --- /dev/null +++ b/phpBB/includes/ucp/ucp_login_link.php @@ -0,0 +1,246 @@ +<?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. +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* ucp_login_link +* Allows users of external accounts link those accounts to their phpBB accounts +* during an attempted login. +*/ +class ucp_login_link +{ + /** + * @var string + */ + public $u_action; + + /** + * Generates the ucp_login_link page and handles login link process + * + * @param int $id + * @param string $mode + */ + function main($id, $mode) + { + global $phpbb_container, $request, $template, $user; + global $phpbb_root_path, $phpEx; + + // Initialize necessary variables + $login_error = null; + $login_link_error = null; + $login_username = null; + + // Build the data array + $data = $this->get_login_link_data_array(); + + // Ensure the person was sent here with login_link data + if (empty($data)) + { + $login_link_error = $user->lang['LOGIN_LINK_NO_DATA_PROVIDED']; + } + + // Use the auth_provider requested even if different from configured + $provider_collection = $phpbb_container->get('auth.provider_collection'); + $auth_provider = $provider_collection->get_provider($request->variable('auth_provider', '')); + + // Set the link_method to login_link + $data['link_method'] = 'login_link'; + + // Have the authentication provider check that all necessary data is available + $result = $auth_provider->login_link_has_necessary_data($data); + if ($result !== null) + { + $login_link_error = $user->lang[$result]; + } + + // Perform link action if there is no error + if (!$login_link_error) + { + if ($request->is_set_post('login')) + { + $login_username = $request->variable('login_username', '', true, \phpbb\request\request_interface::POST); + $login_password = $request->untrimmed_variable('login_password', '', true, \phpbb\request\request_interface::POST); + + $login_result = $auth_provider->login($login_username, $login_password); + + // We only care if there is or is not an error + $login_error = $this->process_login_result($login_result); + + if (!$login_error) + { + // Give the user_id to the data + $data['user_id'] = $login_result['user_row']['user_id']; + + // The user is now logged in, attempt to link the user to the external account + $result = $auth_provider->link_account($data); + + if ($result) + { + $login_link_error = $user->lang[$result]; + } + else + { + // Finish login + $result = $user->session_create($login_result['user_row']['user_id'], false, false, true); + + // Perform a redirect as the account has been linked + $this->perform_redirect(); + } + } + } + } + + $template->assign_vars(array( + // Common template elements + 'LOGIN_LINK_ERROR' => $login_link_error, + 'PASSWORD_CREDENTIAL' => 'login_password', + 'USERNAME_CREDENTIAL' => 'login_username', + 'S_HIDDEN_FIELDS' => $this->get_hidden_fields($data), + + // Registration elements + 'REGISTER_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), + + // Login elements + 'LOGIN_ERROR' => $login_error, + 'LOGIN_USERNAME' => $login_username, + )); + + $this->tpl_name = 'ucp_login_link'; + $this->page_title = 'UCP_LOGIN_LINK'; + } + + /** + * Builds the hidden fields string from the data array. + * + * @param array $data This function only includes data in the array + * that has a key that begins with 'login_link_' + * @return string A string of hidden fields that can be included in the + * template + */ + protected function get_hidden_fields($data) + { + $fields = array(); + + foreach ($data as $key => $value) + { + $fields['login_link_' . $key] = $value; + } + + return build_hidden_fields($fields); + } + + /** + * Builds the login_link data array + * + * @return array All login_link data. This is all GET data whose names + * begin with 'login_link_' + */ + protected function get_login_link_data_array() + { + global $request; + + $var_names = $request->variable_names(\phpbb\request\request_interface::GET); + $login_link_data = array(); + $string_start_length = strlen('login_link_'); + + foreach ($var_names as $var_name) + { + if (strpos($var_name, 'login_link_') === 0) + { + $key_name = substr($var_name, $string_start_length); + $login_link_data[$key_name] = $request->variable($var_name, '', false, \phpbb\request\request_interface::GET); + } + } + + return $login_link_data; + } + + /** + * Processes the result array from the login process + * @param array $result The login result array + * @return string|null If there was an error in the process, a string is + * returned. If the login was successful, then null is + * returned. + */ + protected function process_login_result($result) + { + global $config, $request, $template, $user, $phpbb_container; + + $login_error = null; + + if ($result['status'] != LOGIN_SUCCESS) + { + // Handle all errors first + if ($result['status'] == LOGIN_BREAK) + { + trigger_error($result['error_msg']); + } + + switch ($result['status']) + { + case LOGIN_ERROR_ATTEMPTS: + + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); + $captcha->init(CONFIRM_LOGIN); + + $template->assign_vars(array( + 'CAPTCHA_TEMPLATE' => $captcha->get_template(), + )); + + $login_error = $user->lang[$result['error_msg']]; + break; + + case LOGIN_ERROR_PASSWORD_CONVERT: + $login_error = sprintf( + $user->lang[$result['error_msg']], + ($config['email_enable']) ? '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') . '">' : '', + ($config['email_enable']) ? '</a>' : '', + ($config['board_contact']) ? '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">' : '', + ($config['board_contact']) ? '</a>' : '' + ); + break; + + // Username, password, etc... + default: + $login_error = $user->lang[$result['error_msg']]; + + // Assign admin contact to some error messages + if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' || $result['error_msg'] == 'LOGIN_ERROR_PASSWORD') + { + $login_error = (!$config['board_contact']) ? sprintf($user->lang[$result['error_msg']], '', '') : sprintf($user->lang[$result['error_msg']], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'); + } + + break; + } + } + + return $login_error; + } + + /** + * Performs a post login redirect + */ + protected function perform_redirect() + { + global $phpbb_root_path, $phpEx; + $url = append_sid($phpbb_root_path . 'index.' . $phpEx); + redirect($url); + } +} diff --git a/phpBB/includes/ucp/ucp_main.php b/phpBB/includes/ucp/ucp_main.php index a6f71669ce..a1624e78ec 100644 --- a/phpBB/includes/ucp/ucp_main.php +++ b/phpBB/includes/ucp/ucp_main.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * ucp_main * UCP Front Panel -* @package ucp */ class ucp_main { @@ -34,6 +36,7 @@ class ucp_main function main($id, $mode) { global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx; + global $request; switch ($mode) { @@ -56,39 +59,29 @@ class ucp_main $sql_from .= ' LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (tt.topic_id = t.topic_id AND tt.user_id = ' . $user->data['user_id'] . ')'; $sql_select .= ', tt.mark_time'; + + $sql_from .= ' LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.forum_id = t.forum_id + AND ft.user_id = ' . $user->data['user_id'] . ')'; + $sql_select .= ', ft.mark_time AS forum_mark_time'; } $topic_type = $user->lang['VIEW_TOPIC_GLOBAL']; $folder = 'global_read'; $folder_new = 'global_unread'; - // Get cleaned up list... return only those forums not having the f_read permission - $forum_ary = $auth->acl_getf('!f_read', true); + // Get cleaned up list... return only those forums having the f_read permission + $forum_ary = $auth->acl_getf('f_read', true); $forum_ary = array_unique(array_keys($forum_ary)); - - // Determine first forum the user is able to read into - for global announcement link - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE forum_type = ' . FORUM_POST; - - if (sizeof($forum_ary)) - { - $sql .= ' AND ' . $db->sql_in_set('forum_id', $forum_ary, true); - } - $result = $db->sql_query_limit($sql, 1); - $g_forum_id = (int) $db->sql_fetchfield('forum_id'); - $db->sql_freeresult($result); - - $sql = "SELECT t.* $sql_select - FROM $sql_from - WHERE t.forum_id = 0 - AND t.topic_type = " . POST_GLOBAL . ' - ORDER BY t.topic_last_post_time DESC'; - $topic_list = $rowset = array(); + // If the user can't see any forums, he can't read any posts because fid of 0 is invalid - if ($g_forum_id) + if (!empty($forum_ary)) { + $sql = "SELECT t.* $sql_select + FROM $sql_from + WHERE t.topic_type = " . POST_GLOBAL . ' + AND ' . $db->sql_in_set('t.forum_id', $forum_ary) . ' + ORDER BY t.topic_last_post_time DESC, t.topic_last_post_id DESC'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -99,15 +92,34 @@ class ucp_main $db->sql_freeresult($result); } - $topic_tracking_info = array(); + $topic_forum_list = array(); + foreach ($rowset as $t_id => $row) + { + if (isset($forum_tracking_info[$row['forum_id']])) + { + $row['forum_mark_time'] = $forum_tracking_info[$row['forum_id']]; + } + + $topic_forum_list[$row['forum_id']]['forum_mark_time'] = ($config['load_db_lastread'] && $user->data['is_registered'] && isset($row['forum_mark_time'])) ? $row['forum_mark_time'] : 0; + $topic_forum_list[$row['forum_id']]['topics'][] = (int) $t_id; + } + + $topic_tracking_info = $tracking_topics = array(); if ($config['load_db_lastread']) { - $topic_tracking_info = get_topic_tracking(0, $topic_list, $rowset, false, $topic_list); + foreach ($topic_forum_list as $f_id => $topic_row) + { + $topic_tracking_info += get_topic_tracking($f_id, $topic_row['topics'], $rowset, array($f_id => $topic_row['forum_mark_time'])); + } } else { - $topic_tracking_info = get_complete_topic_tracking(0, $topic_list, $topic_list); + foreach ($topic_forum_list as $f_id => $topic_row) + { + $topic_tracking_info += get_complete_topic_tracking($f_id, $topic_row['topics']); + } } + unset($topic_forum_list); foreach ($topic_list as $topic_id) { @@ -148,18 +160,18 @@ class ucp_main 'TOPIC_TITLE' => censor_text($row['topic_title']), 'TOPIC_TYPE' => $topic_type, + 'TOPIC_IMG_STYLE' => $folder_img, 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'TOPIC_FOLDER_IMG_SRC' => $user->img($folder_img, $folder_alt, false, '', 'src'), 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', '') : '', 'S_USER_POSTED' => (!empty($row['topic_posted']) && $row['topic_posted']) ? true : false, 'S_UNREAD' => $unread_topic, 'U_TOPIC_AUTHOR' => get_username_string('profile', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']), - 'U_LAST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$g_forum_id&t=$topic_id&p=" . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'], + 'U_LAST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&p=" . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'], 'U_LAST_POST_AUTHOR' => get_username_string('profile', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']), - 'U_NEWEST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$g_forum_id&t=$topic_id&view=unread") . '#unread', - 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$g_forum_id&t=$topic_id")) + 'U_NEWEST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=unread") . '#unread', + 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id")) ); } @@ -180,14 +192,11 @@ class ucp_main $template->assign_vars(array( 'USER_COLOR' => (!empty($user->data['user_colour'])) ? $user->data['user_colour'] : '', 'JOINED' => $user->format_date($user->data['user_regdate']), - 'VISITED' => (empty($last_visit)) ? ' - ' : $user->format_date($last_visit), + 'LAST_ACTIVE' => (empty($last_active)) ? ' - ' : $user->format_date($last_active), 'WARNINGS' => ($user->data['user_warnings']) ? $user->data['user_warnings'] : 0, 'POSTS' => ($user->data['user_posts']) ? $user->data['user_posts'] : 0, - 'POSTS_DAY' => sprintf($user->lang['POST_DAY'], $posts_per_day), - 'POSTS_PCT' => sprintf($user->lang['POST_PCT'], $percentage), - - 'OCCUPATION' => (!empty($row['user_occ'])) ? $row['user_occ'] : '', - 'INTERESTS' => (!empty($row['user_interests'])) ? $row['user_interests'] : '', + 'POSTS_DAY' => $user->lang('POST_DAY', $posts_per_day), + 'POSTS_PCT' => $user->lang('POST_PCT', $percentage), // 'S_GROUP_OPTIONS' => $group_options, @@ -287,7 +296,7 @@ class ucp_main } else { - $tracking_topics = (isset($_COOKIE[$config['cookie_name'] . '_track'])) ? ((STRIP) ? stripslashes($_COOKIE[$config['cookie_name'] . '_track']) : $_COOKIE[$config['cookie_name'] . '_track']) : ''; + $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE); $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); } @@ -334,8 +343,8 @@ class ucp_main $template->assign_block_vars('forumrow', array( 'FORUM_ID' => $forum_id, + 'FORUM_IMG_STYLE' => $folder_image, 'FORUM_FOLDER_IMG' => $user->img($folder_image, $folder_alt), - 'FORUM_FOLDER_IMG_SRC' => $user->img($folder_image, $folder_alt, false, '', 'src'), 'FORUM_IMAGE' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="' . $user->lang[$folder_alt] . '" />' : '', 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', 'FORUM_NAME' => $row['forum_name'], @@ -348,6 +357,8 @@ class ucp_main 'LAST_POST_AUTHOR_FULL' => get_username_string('full', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']), 'U_LAST_POST_AUTHOR' => get_username_string('profile', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']), + 'S_UNREAD_FORUM' => $unread_forum, + 'U_LAST_POST' => $last_post_url, 'U_VIEWFORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id'])) ); @@ -435,7 +446,7 @@ class ucp_main $edit = (isset($_REQUEST['edit'])) ? true : false; $submit = (isset($_POST['submit'])) ? true : false; - $draft_id = ($edit) ? intval($_REQUEST['edit']) : 0; + $draft_id = $request->variable('edit', 0); $delete = (isset($_POST['delete'])) ? true : false; $s_hidden_fields = ($edit) ? '<input type="hidden" name="edit" value="' . $draft_id . '" />' : ''; @@ -611,7 +622,6 @@ class ucp_main break; } - $template->assign_vars(array( 'L_TITLE' => $user->lang['UCP_MAIN_' . strtoupper($mode)], @@ -633,10 +643,11 @@ class ucp_main */ function assign_topiclist($mode = 'subscribed', $forbidden_forum_ary = array()) { - global $user, $db, $template, $config, $cache, $auth, $phpbb_root_path, $phpEx; + global $user, $db, $template, $config, $cache, $auth, $phpbb_root_path, $phpEx, $phpbb_container; $table = ($mode == 'subscribed') ? TOPICS_WATCH_TABLE : BOOKMARKS_TABLE; $start = request_var('start', 0); + $pagination = $phpbb_container->get('pagination'); // Grab icons $icons = $cache->obtain_icons(); @@ -660,11 +671,12 @@ class ucp_main if ($topics_count) { + $start = $pagination->validate_start($start, $config['topics_per_page'], $topics_count); + $pagination->generate_template_pagination($this->u_action, 'pagination', 'start', $topics_count, $config['topics_per_page'], $start); + $template->assign_vars(array( - 'PAGINATION' => generate_pagination($this->u_action, $topics_count, $config['topics_per_page'], $start), - 'PAGE_NUMBER' => on_page($topics_count, $config['topics_per_page'], $start), - 'TOTAL_TOPICS' => ($topics_count == 1) ? $user->lang['VIEW_FORUM_TOPIC'] : sprintf($user->lang['VIEW_FORUM_TOPICS'], $topics_count)) - ); + 'TOTAL_TOPICS' => $user->lang('VIEW_FORUM_TOPICS', (int) $topics_count), + )); } if ($mode == 'subscribed') @@ -681,8 +693,7 @@ class ucp_main AND t.topic_id = tw.topic_id AND ' . $db->sql_in_set('t.forum_id', $forbidden_forum_ary, true, true), - - 'ORDER_BY' => 't.topic_last_post_time DESC' + 'ORDER_BY' => 't.topic_last_post_time DESC, t.topic_last_post_id DESC' ); $sql_array['LEFT_JOIN'] = array(); @@ -699,7 +710,7 @@ class ucp_main 'WHERE' => 'b.user_id = ' . $user->data['user_id'] . ' AND ' . $db->sql_in_set('f.forum_id', $forbidden_forum_ary, true, true), - 'ORDER_BY' => 't.topic_last_post_time DESC' + 'ORDER_BY' => 't.topic_last_post_time DESC, t.topic_last_post_id DESC' ); $sql_array['LEFT_JOIN'] = array(); @@ -747,17 +758,19 @@ class ucp_main { foreach ($topic_forum_list as $f_id => $topic_row) { - $topic_tracking_info += get_topic_tracking($f_id, $topic_row['topics'], $rowset, array($f_id => $topic_row['forum_mark_time']), ($f_id == 0) ? $global_announce_list : false); + $topic_tracking_info += get_topic_tracking($f_id, $topic_row['topics'], $rowset, array($f_id => $topic_row['forum_mark_time'])); } } else { foreach ($topic_forum_list as $f_id => $topic_row) { - $topic_tracking_info += get_complete_topic_tracking($f_id, $topic_row['topics'], $global_announce_list); + $topic_tracking_info += get_complete_topic_tracking($f_id, $topic_row['topics']); } } + $phpbb_content_visibility = $phpbb_container->get('content.visibility'); + foreach ($topic_list as $topic_id) { $row = &$rowset[$topic_id]; @@ -768,7 +781,7 @@ class ucp_main $unread_topic = (isset($topic_tracking_info[$topic_id]) && $row['topic_last_post_time'] > $topic_tracking_info[$topic_id]) ? true : false; // Replies - $replies = ($auth->acl_get('m_approve', $forum_id)) ? $row['topic_replies_real'] : $row['topic_replies']; + $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1; if ($row['topic_status'] == ITEM_MOVED && !empty($row['topic_moved_id'])) { @@ -802,17 +815,15 @@ class ucp_main 'U_LAST_POST_AUTHOR' => get_username_string('profile', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']), 'S_DELETED_TOPIC' => (!$row['topic_id']) ? true : false, - 'S_GLOBAL_TOPIC' => (!$forum_id) ? true : false, - 'PAGINATION' => topic_generate_pagination($replies, append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . (($row['forum_id']) ? $row['forum_id'] : $forum_id) . "&t=$topic_id")), 'REPLIES' => $replies, 'VIEWS' => $row['topic_views'], 'TOPIC_TITLE' => censor_text($row['topic_title']), 'TOPIC_TYPE' => $topic_type, 'FORUM_NAME' => $row['forum_name'], + 'TOPIC_IMG_STYLE' => $folder_img, 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'TOPIC_FOLDER_IMG_SRC' => $user->img($folder_img, $folder_alt, false, '', 'src'), 'TOPIC_FOLDER_IMG_ALT' => $user->lang[$folder_alt], 'TOPIC_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['img'] : '', 'TOPIC_ICON_IMG_WIDTH' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '', @@ -828,8 +839,8 @@ class ucp_main 'U_VIEW_TOPIC' => $view_topic_url, 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id), )); + + $pagination->generate_template_pagination(append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id'] . "&t=$topic_id"), 'topicrow.pagination', 'start', $replies + 1, $config['posts_per_page'], 1, true, true); } } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_notifications.php b/phpBB/includes/ucp/ucp_notifications.php new file mode 100644 index 0000000000..b0aeaba227 --- /dev/null +++ b/phpBB/includes/ucp/ucp_notifications.php @@ -0,0 +1,239 @@ +<?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. +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +class ucp_notifications +{ + public $u_action; + + public function main($id, $mode) + { + global $config, $template, $user, $request, $phpbb_container; + global $phpbb_root_path, $phpEx; + + add_form_key('ucp_notification'); + + $start = $request->variable('start', 0); + $form_time = $request->variable('form_time', 0); + $form_time = ($form_time <= 0 || $form_time > time()) ? time() : $form_time; + + $phpbb_notifications = $phpbb_container->get('notification_manager'); + $pagination = $phpbb_container->get('pagination'); + + switch ($mode) + { + case 'notification_options': + $subscriptions = $phpbb_notifications->get_global_subscriptions(false); + + // Add/remove subscriptions + if ($request->is_set_post('submit')) + { + if (!check_form_key('ucp_notification')) + { + trigger_error('FORM_INVALID'); + } + + $notification_methods = $phpbb_notifications->get_subscription_methods(); + + foreach($phpbb_notifications->get_subscription_types() as $group => $subscription_types) + { + foreach($subscription_types as $type => $data) + { + foreach($notification_methods as $method => $method_data) + { + if ($request->is_set_post(str_replace('.', '_', $type . '_' . $method_data['id'])) && (!isset($subscriptions[$type]) || !in_array($method_data['id'], $subscriptions[$type]))) + { + $phpbb_notifications->add_subscription($type, 0, $method_data['id']); + } + else if (!$request->is_set_post(str_replace('.', '_', $type . '_' . $method_data['id'])) && isset($subscriptions[$type]) && in_array($method_data['id'], $subscriptions[$type])) + { + $phpbb_notifications->delete_subscription($type, 0, $method_data['id']); + } + } + + if ($request->is_set_post(str_replace('.', '_', $type) . '_notification') && !isset($subscriptions[$type])) + { + $phpbb_notifications->add_subscription($type); + } + else if (!$request->is_set_post(str_replace('.', '_', $type) . '_notification') && isset($subscriptions[$type])) + { + $phpbb_notifications->delete_subscription($type); + } + } + } + + meta_refresh(3, $this->u_action); + $message = $user->lang['PREFERENCES_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>'); + trigger_error($message); + } + + $this->output_notification_methods($phpbb_notifications, $template, $user, 'notification_methods'); + + $this->output_notification_types($subscriptions, $phpbb_notifications, $template, $user, 'notification_types'); + + $this->tpl_name = 'ucp_notifications'; + $this->page_title = 'UCP_NOTIFICATION_OPTIONS'; + break; + + case 'notification_list': + default: + // Mark all items read + if ($request->variable('mark', '') == 'all' && check_link_hash($request->variable('token', ''), 'mark_all_notifications_read')) + { + $phpbb_notifications->mark_notifications_read(false, false, $user->data['user_id'], $form_time); + + meta_refresh(3, $this->u_action); + $message = $user->lang['NOTIFICATIONS_MARK_ALL_READ_SUCCESS']; + + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response(); + $json_response->send(array( + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $message, + 'success' => true, + )); + } + $message .= '<br /><br />' . $user->lang('RETURN_UCP', '<a href="' . $this->u_action . '">', '</a>'); + + trigger_error($message); + } + + // Mark specific notifications read + if ($request->is_set_post('submit')) + { + if (!check_form_key('ucp_notification')) + { + trigger_error('FORM_INVALID'); + } + + $mark_read = $request->variable('mark', array(0)); + + if (!empty($mark_read)) + { + $phpbb_notifications->mark_notifications_read_by_id($mark_read, $form_time); + } + } + + $notifications = $phpbb_notifications->load_notifications(array( + 'start' => $start, + 'limit' => $config['topics_per_page'], + 'count_total' => true, + )); + + foreach ($notifications['notifications'] as $notification) + { + $template->assign_block_vars('notification_list', $notification->prepare_for_display()); + } + + $base_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=ucp_notifications&mode=notification_list"); + $start = $pagination->validate_start($start, $config['topics_per_page'], $notifications['total_count']); + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $notifications['total_count'], $config['topics_per_page'], $start); + + $template->assign_vars(array( + 'TOTAL_COUNT' => $notifications['total_count'], + 'U_MARK_ALL' => $base_url . '&mark=all&token=' . generate_link_hash('mark_all_notifications_read'), + )); + + $this->tpl_name = 'ucp_notifications'; + $this->page_title = 'UCP_NOTIFICATION_LIST'; + break; + } + + $template->assign_vars(array( + 'TITLE' => $user->lang($this->page_title), + 'TITLE_EXPLAIN' => $user->lang($this->page_title . '_EXPLAIN'), + + 'MODE' => $mode, + + 'FORM_TIME' => time(), + )); + } + + /** + * Output all the notification types to the template + * + * @param array $subscriptions Array containing global subscriptions + * @param \phpbb\notification\manager $phpbb_notifications + * @param \phpbb\template\template $template + * @param \phpbb\user $user + * @param string $block + */ + public function output_notification_types($subscriptions, \phpbb\notification\manager $phpbb_notifications, \phpbb\template\template $template, \phpbb\user $user, $block = 'notification_types') + { + $notification_methods = $phpbb_notifications->get_subscription_methods(); + + foreach($phpbb_notifications->get_subscription_types() as $group => $subscription_types) + { + $template->assign_block_vars($block, array( + 'GROUP_NAME' => $user->lang($group), + )); + + foreach($subscription_types as $type => $data) + { + $template->assign_block_vars($block, array( + 'TYPE' => $type, + + 'NAME' => $user->lang($data['lang']), + 'EXPLAIN' => (isset($user->lang[$data['lang'] . '_EXPLAIN'])) ? $user->lang($data['lang'] . '_EXPLAIN') : '', + + 'SUBSCRIBED' => (isset($subscriptions[$type])) ? true : false, + )); + + foreach($notification_methods as $method => $method_data) + { + $template->assign_block_vars($block . '.notification_methods', array( + 'METHOD' => $method_data['id'], + + 'NAME' => $user->lang($method_data['lang']), + + 'SUBSCRIBED' => (isset($subscriptions[$type]) && in_array($method_data['id'], $subscriptions[$type])) ? true : false, + )); + } + } + } + + $template->assign_vars(array( + strtoupper($block) . '_COLS' => sizeof($notification_methods) + 2, + )); + } + + /** + * Output all the notification methods to the template + * + * @param \phpbb\notification\manager $phpbb_notifications + * @param \phpbb\template\template $template + * @param \phpbb\user $user + * @param string $block + */ + public function output_notification_methods(\phpbb\notification\manager $phpbb_notifications, \phpbb\template\template $template, \phpbb\user $user, $block = 'notification_methods') + { + $notification_methods = $phpbb_notifications->get_subscription_methods(); + + foreach($notification_methods as $method => $method_data) + { + $template->assign_block_vars($block, array( + 'METHOD' => $method_data['id'], + + 'NAME' => $user->lang($method_data['lang']), + )); + } + } +} diff --git a/phpBB/includes/ucp/ucp_pm.php b/phpBB/includes/ucp/ucp_pm.php index 447b6ebe87..425a56cf6c 100644 --- a/phpBB/includes/ucp/ucp_pm.php +++ b/phpBB/includes/ucp/ucp_pm.php @@ -1,9 +1,13 @@ <?php /** -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +* 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. * */ @@ -34,8 +38,6 @@ if (!defined('IN_PHPBB')) * Quoting a post (action=quotepost&p=[post_id]) * Quoting a PM (action=quote&p=[msg_id]) * Forwarding a PM (action=forward&p=[msg_id]) -* -* @package ucp */ class ucp_pm { @@ -43,7 +45,7 @@ class ucp_pm function main($id, $mode) { - global $user, $template, $phpbb_root_path, $auth, $phpEx, $db, $config; + global $user, $template, $phpbb_root_path, $auth, $phpEx, $db, $config, $request; if (!$user->data['is_registered']) { @@ -84,33 +86,6 @@ class ucp_pm switch ($mode) { - // New private messages popup - case 'popup': - - $l_new_message = ''; - if ($user->data['is_registered']) - { - if ($user->data['user_new_privmsg']) - { - $l_new_message = ($user->data['user_new_privmsg'] == 1) ? $user->lang['YOU_NEW_PM'] : $user->lang['YOU_NEW_PMS']; - } - else - { - $l_new_message = $user->lang['YOU_NO_NEW_PM']; - } - } - - $template->assign_vars(array( - 'MESSAGE' => $l_new_message, - 'S_NOT_LOGGED_IN' => ($user->data['user_id'] == ANONYMOUS) ? true : false, - 'CLICK_TO_VIEW' => sprintf($user->lang['CLICK_VIEW_PRIVMSG'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox') . '" onclick="jump_to_inbox(this.href); return false;">', '</a>'), - 'U_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'), - 'UA_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox', false)) - ); - - $tpl_file = 'ucp_pm_popup'; - break; - // Compose message case 'compose': $action = request_var('action', 'post'); @@ -200,7 +175,6 @@ class ucp_pm trigger_error('NO_AUTH_READ_HOLD_MESSAGE'); } - // First Handle Mark actions and moving messages $submit_mark = (isset($_POST['submit_mark'])) ? true : false; $move_pm = (isset($_POST['move_pm'])) ? true : false; @@ -272,6 +246,27 @@ class ucp_pm $folder_id = (int) $row['folder_id']; } + if ($request->variable('mark', '') == 'all' && check_link_hash($request->variable('token', ''), 'mark_all_pms_read')) + { + mark_folder_read($user->data['user_id'], $folder_id); + + meta_refresh(3, $this->u_action); + $message = $user->lang['PM_MARK_ALL_READ_SUCCESS']; + + if ($request->is_ajax()) + { + $json_response = new \phpbb\json_response(); + $json_response->send(array( + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $message, + 'success' => true, + )); + } + $message .= '<br /><br />' . $user->lang('RETURN_UCP', '<a href="' . $this->u_action . '">', '</a>'); + + trigger_error($message); + } + $message_row = array(); if ($action == 'view_message' && $msg_id) { @@ -345,8 +340,8 @@ class ucp_pm 'NUM_NOT_MOVED' => $num_not_moved, 'NUM_REMOVED' => $num_removed, 'RELEASE_MESSAGE_INFO' => sprintf($user->lang['RELEASE_MESSAGES'], '<a href="' . $this->u_action . '&folder=' . $folder_id . '&release=1">', '</a>'), - 'NOT_MOVED_MESSAGES' => ($num_not_moved == 1) ? $user->lang['NOT_MOVED_MESSAGE'] : sprintf($user->lang['NOT_MOVED_MESSAGES'], $num_not_moved), - 'RULE_REMOVED_MESSAGES' => ($num_removed == 1) ? $user->lang['RULE_REMOVED_MESSAGE'] : sprintf($user->lang['RULE_REMOVED_MESSAGES'], $num_removed), + 'NOT_MOVED_MESSAGES' => $user->lang('NOT_MOVED_MESSAGES', (int) $num_not_moved), + 'RULE_REMOVED_MESSAGES' => $user->lang('RULE_REMOVED_MESSAGES', (int) $num_removed), 'S_FOLDER_OPTIONS' => $s_folder_options, 'S_TO_FOLDER_OPTIONS' => $s_to_folder_options, @@ -358,6 +353,7 @@ class ucp_pm 'U_SENTBOX' => $this->u_action . '&folder=sentbox', 'U_CREATE_FOLDER' => $this->u_action . '&mode=options', 'U_CURRENT_FOLDER' => $this->u_action . '&folder=' . $folder_id, + 'U_MARK_ALL' => $this->u_action . '&folder=' . $folder_id . '&mark=all&token=' . generate_link_hash('mark_all_pms_read'), 'S_IN_INBOX' => ($folder_id == PRIVMSGS_INBOX) ? true : false, 'S_IN_OUTBOX' => ($folder_id == PRIVMSGS_OUTBOX) ? true : false, @@ -380,9 +376,10 @@ class ucp_pm else if ($action == 'view_message') { $template->assign_vars(array( - 'S_VIEW_MESSAGE' => true, - 'MSG_ID' => $msg_id) - ); + 'S_VIEW_MESSAGE' => true, + 'L_RETURN_TO_FOLDER' => $user->lang('RETURN_TO', $folder_status['folder_name']), + 'MSG_ID' => $msg_id, + )); if (!$msg_id) { @@ -412,5 +409,3 @@ class ucp_pm $this->page_title = 'UCP_PM_' . strtoupper($mode); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index d7509a1072..51018e3a5d 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -22,8 +25,9 @@ if (!defined('IN_PHPBB')) */ function compose_pm($id, $mode, $action, $user_folders = array()) { - global $template, $db, $auth, $user; + global $template, $db, $auth, $user, $cache; global $phpbb_root_path, $phpEx, $config; + global $request, $phpbb_dispatcher, $phpbb_container; // Damn php and globals - i know, this is horrible // Needed for handle_message_list_actions() @@ -49,13 +53,7 @@ function compose_pm($id, $mode, $action, $user_folders = array()) // Reply to all triggered (quote/reply) $reply_to_all = request_var('reply_to_all', 0); - // Do NOT use request_var or specialchars here - $address_list = isset($_REQUEST['address_list']) ? $_REQUEST['address_list'] : array(); - - if (!is_array($address_list)) - { - $address_list = array(); - } + $address_list = $request->variable('address_list', array('' => array(0 => ''))); $submit = (isset($_POST['post'])) ? true : false; $preview = (isset($_POST['preview'])) ? true : false; @@ -92,6 +90,32 @@ function compose_pm($id, $mode, $action, $user_folders = array()) // we include the language file here $user->add_lang('viewtopic'); + /** + * Modify the default vars before composing a PM + * + * @event core.ucp_pm_compose_modify_data + * @var int msg_id post_id in the page request + * @var int to_user_id The id of whom the message is to + * @var int to_group_id The id of the group the message is to + * @var bool submit Whether the form has been submitted + * @var bool preview Whether the user is previewing the PM or not + * @var string action One of: post, reply, quote, forward, quotepost, edit, delete, smilies + * @var bool delete Whether the user is deleting the PM + * @var int reply_to_all Value of reply_to_all request variable. + * @since 3.1.4-RC1 + */ + $vars = array( + 'msg_id', + 'to_user_id', + 'to_group_id', + 'submit', + 'preview', + 'action', + 'delete', + 'reply_to_all', + ); + extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_modify_data', compact($vars))); + // Output PM_TO box if message composing if ($action != 'edit') { @@ -234,6 +258,42 @@ function compose_pm($id, $mode, $action, $user_folders = array()) if ($sql) { + /** + * Alter sql query to get message for user to write the PM + * + * @event core.ucp_pm_compose_compose_pm_basic_info_query_before + * @var string sql String with the query to be executed + * @var array forum_list List of forums that contain the posts + * @var int visibility_const Integer with one of the possible ITEM_* constant values + * @var int msg_id topic_id in the page request + * @var int to_user_id The id of whom the message is to + * @var int to_group_id The id of the group whom the message is to + * @var bool submit Whether the user is sending the PM or not + * @var bool preview Whether the user is previewing the PM or not + * @var string action One of: post, reply, quote, forward, quotepost, edit, delete, smilies + * @var bool delete Whether the user is deleting the PM + * @var int reply_to_all Value of reply_to_all request variable. + * @var string limit_time_sql String with the SQL code to limit the time interval of the post (Note: May be empty string) + * @var string sort_order_sql String with the ORDER BY SQL code used in this query + * @since 3.1.0-RC5 + */ + $vars = array( + 'sql', + 'forum_list', + 'visibility_const', + 'msg_id', + 'to_user_id', + 'to_group_id', + 'submit', + 'preview', + 'action', + 'delete', + 'reply_to_all', + 'limit_time_sql', + 'sort_order_sql', + ); + extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_compose_pm_basic_info_query_before', compact($vars))); + $result = $db->sql_query($sql); $post = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -268,6 +328,40 @@ function compose_pm($id, $mode, $action, $user_folders = array()) trigger_error('NOT_AUTHORISED'); } + /** + * Get the result of querying for the post to be quoted in the pm message + * + * @event core.ucp_pm_compose_quotepost_query_after + * @var string sql The original SQL used in the query + * @var array post Associative array with the data of the quoted post + * @var array msg_id The post_id that was searched to get the message for quoting + * @var int visibility_const Visibility of the quoted post (one of the possible ITEM_* constant values) + * @var int topic_id Topic ID of the quoted post + * @var int to_user_id Users the message is sent to + * @var int to_group_id Groups the message is sent to + * @var bool submit Whether the user is sending the PM or not + * @var bool preview Whether the user is previewing the PM or not + * @var string action One of: post, reply, quote, forward, quotepost, edit, delete, smilies + * @var bool delete If deleting message + * @var int reply_to_all Value of reply_to_all request variable. + * @since 3.1.0-RC5 + */ + $vars = array( + 'sql', + 'post', + 'msg_id', + 'visibility_const', + 'topic_id', + 'to_user_id', + 'to_group_id', + 'submit', + 'preview', + 'action', + 'delete', + 'reply_to_all', + ); + extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_quotepost_query_after', compact($vars))); + // Passworded forum? if ($post['forum_id']) { @@ -391,6 +485,8 @@ function compose_pm($id, $mode, $action, $user_folders = array()) } $message_parser = new parse_message(); + $plupload = $phpbb_container->get('plupload'); + $message_parser->set_plupload($plupload); $message_parser->message = ($action == 'reply') ? '' : $message_text; unset($message_text); @@ -495,7 +591,7 @@ function compose_pm($id, $mode, $action, $user_folders = array()) if ($message_attachment && !$submit && !$refresh && !$preview && $action == 'edit') { // Do not change to SELECT * - $sql = 'SELECT attach_id, is_orphan, attach_comment, real_filename + $sql = 'SELECT attach_id, is_orphan, attach_comment, real_filename, filesize FROM ' . ATTACHMENTS_TABLE . " WHERE post_msg_id = $msg_id AND in_message = 1 @@ -589,7 +685,6 @@ function compose_pm($id, $mode, $action, $user_folders = array()) ); $s_hidden_fields .= build_address_field($address_list); - confirm_box(false, 'SAVE_DRAFT', $s_hidden_fields); } } @@ -751,7 +846,6 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $return_box_url = ($action === 'post' || $action === 'edit') ? $outbox_folder_url : $inbox_folder_url; $return_box_lang = ($action === 'post' || $action === 'edit') ? 'PM_OUTBOX' : 'PM_INBOX'; - $save_message = ($action === 'edit') ? $user->lang['MESSAGE_EDITED'] : $user->lang['MESSAGE_STORED']; $message = $save_message . '<br /><br />' . $user->lang('VIEW_PRIVATE_MESSAGE', '<a href="' . $return_message_url . '">', '</a>'); @@ -841,11 +935,11 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $post_id = request_var('p', 0); if ($config['allow_post_links']) { - $message_link = "[url=" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id}]{$user->lang['SUBJECT']}: {$message_subject}[/url]\n\n"; + $message_link = "[url=" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id}]{$user->lang['SUBJECT']}{$user->lang['COLON']} {$message_subject}[/url]\n\n"; } else { - $message_link = $user->lang['SUBJECT'] . ': ' . $message_subject . " (" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id})\n\n"; + $message_link = $user->lang['SUBJECT'] . $user->lang['COLON'] . ' ' . $message_subject . " (" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id})\n\n"; } } else @@ -878,7 +972,7 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $forward_text[] = sprintf($user->lang['FWD_SUBJECT'], censor_text($message_subject)); $forward_text[] = sprintf($user->lang['FWD_DATE'], $user->format_date($message_time, false, true)); $forward_text[] = sprintf($user->lang['FWD_FROM'], $quote_username_text); - $forward_text[] = sprintf($user->lang['FWD_TO'], implode(', ', $fwd_to_field['to'])); + $forward_text[] = sprintf($user->lang['FWD_TO'], implode($user->lang['COMMA_SEPARATOR'], $fwd_to_field['to'])); $message_parser->message = implode("\n", $forward_text) . "\n\n[quote="{$quote_username}"]\n" . censor_text(trim($message_parser->message)) . "\n[/quote]"; $message_subject = ((!preg_match('/^Fwd:/', $message_subject)) ? 'Fwd: ' : '') . censor_text($message_subject); @@ -1009,7 +1103,6 @@ function compose_pm($id, $mode, $action, $user_folders = array()) // Build hidden address list $s_hidden_address_field = build_address_field($address_list); - $bbcode_checked = (isset($enable_bbcode)) ? !$enable_bbcode : (($config['allow_bbcode'] && $auth->acl_get('u_pm_bbcode')) ? !$user->optionget('bbcode') : 1); $smilies_checked = (isset($enable_smilies)) ? !$enable_smilies : (($config['allow_smilies'] && $auth->acl_get('u_pm_smilies')) ? !$user->optionget('smilies') : 1); $urls_checked = (isset($enable_urls)) ? !$enable_urls : 0; @@ -1048,7 +1141,7 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $s_hidden_fields = '<input type="hidden" name="lastclick" value="' . $current_time . '" />'; $s_hidden_fields .= (isset($check_value)) ? '<input type="hidden" name="status_switch" value="' . $check_value . '" />' : ''; - $s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '<input type="hidden" name="draft_loaded" value="' . ((isset($_REQUEST['draft_loaded'])) ? intval($_REQUEST['draft_loaded']) : $draft_id) . '" />' : ''; + $s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '<input type="hidden" name="draft_loaded" value="' . ((isset($_REQUEST['draft_loaded'])) ? $request->variable('draft_loaded', 0) : $draft_id) . '" />' : ''; $form_enctype = (@ini_get('file_uploads') == '0' || strtolower(@ini_get('file_uploads')) == 'off' || !$config['allow_pm_attach'] || !$auth->acl_get('u_pm_attach')) ? '' : ' enctype="multipart/form-data"'; @@ -1056,7 +1149,7 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $template->assign_vars(array( 'L_POST_A' => $page_title, 'L_ICON' => $user->lang['PM_ICON'], - 'L_MESSAGE_BODY_EXPLAIN' => (intval($config['max_post_chars'])) ? sprintf($user->lang['MESSAGE_BODY_EXPLAIN'], intval($config['max_post_chars'])) : '', + 'L_MESSAGE_BODY_EXPLAIN' => $user->lang('MESSAGE_BODY_EXPLAIN', (int) $config['max_post_chars']), 'SUBJECT' => (isset($message_subject)) ? $message_subject : '', 'MESSAGE' => $message_text, @@ -1084,6 +1177,7 @@ function compose_pm($id, $mode, $action, $user_folders = array()) 'S_SAVE_ALLOWED' => ($auth->acl_get('u_savedrafts') && $action != 'edit') ? true : false, 'S_HAS_DRAFTS' => ($auth->acl_get('u_savedrafts') && $drafts), 'S_FORM_ENCTYPE' => $form_enctype, + 'S_ATTACH_DATA' => json_encode($message_parser->attachment_data), 'S_BBCODE_IMG' => $img_status, 'S_BBCODE_FLASH' => $flash_status, @@ -1105,6 +1199,12 @@ function compose_pm($id, $mode, $action, $user_folders = array()) // Show attachment box for adding attachments if true $allowed = ($auth->acl_get('u_pm_attach') && $config['allow_pm_attach'] && $form_enctype); + if ($allowed) + { + $max_files = ($auth->acl_gets('a_', 'm_')) ? 0 : (int) $config['max_attachments_pm']; + $plupload->configure($cache, $template, $s_action, false, $max_files); + } + // Attachment entry posting_gen_attachment_entry($attachment_data, $filename_data, $allowed); @@ -1124,11 +1224,12 @@ function compose_pm($id, $mode, $action, $user_folders = array()) function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove_g, $add_to, $add_bcc) { global $auth, $db, $user; + global $request; // Delete User [TO/BCC] - if ($remove_u && !empty($_REQUEST['remove_u']) && is_array($_REQUEST['remove_u'])) + if ($remove_u && $request->variable('remove_u', array(0 => ''))) { - $remove_user_id = array_keys($_REQUEST['remove_u']); + $remove_user_id = array_keys($request->variable('remove_u', array(0 => ''))); if (isset($remove_user_id[0])) { @@ -1137,9 +1238,9 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove } // Delete Group [TO/BCC] - if ($remove_g && !empty($_REQUEST['remove_g']) && is_array($_REQUEST['remove_g'])) + if ($remove_g && $request->variable('remove_g', array(0 => ''))) { - $remove_group_id = array_keys($_REQUEST['remove_g']); + $remove_group_id = array_keys($request->variable('remove_g', array(0 => ''))); if (isset($remove_group_id[0])) { @@ -1207,7 +1308,7 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove } // Add Friends if specified - $friend_list = (isset($_REQUEST['add_' . $type]) && is_array($_REQUEST['add_' . $type])) ? array_map('intval', array_keys($_REQUEST['add_' . $type])) : array(); + $friend_list = array_keys($request->variable('add_' . $type, array(0))); $user_id_ary = array_merge($user_id_ary, $friend_list); foreach ($user_id_ary as $user_id) @@ -1224,29 +1325,80 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove // Check for disallowed recipients if (!empty($address_list['u'])) { - // We need to check their PM status (do they want to receive PM's?) - // Only check if not a moderator or admin, since they are allowed to override this user setting - if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) + $can_ignore_allow_pm = $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'); + + // Administrator deactivated users check and we need to check their + // PM status (do they want to receive PM's?) + // Only check PM status if not a moderator or admin, since they + // are allowed to override this user setting + $sql = 'SELECT user_id, user_allow_pm + FROM ' . USERS_TABLE . ' + WHERE ' . $db->sql_in_set('user_id', array_keys($address_list['u'])) . ' + AND ( + (user_type = ' . USER_INACTIVE . ' + AND user_inactive_reason = ' . INACTIVE_MANUAL . ') + ' . ($can_ignore_allow_pm ? '' : ' OR user_allow_pm = 0') . ' + )'; + + $result = $db->sql_query($sql); + + $removed_no_pm = $removed_no_permission = false; + while ($row = $db->sql_fetchrow($result)) { - $sql = 'SELECT user_id - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', array_keys($address_list['u'])) . ' - AND user_allow_pm = 0'; - $result = $db->sql_query($sql); + if (!$can_ignore_allow_pm && !$row['user_allow_pm']) + { + $removed_no_pm = true; + } + else + { + $removed_no_permission = true; + } - $removed = false; - while ($row = $db->sql_fetchrow($result)) + unset($address_list['u'][$row['user_id']]); + } + $db->sql_freeresult($result); + + // print a notice about users not being added who do not want to receive pms + if ($removed_no_pm) + { + $error[] = $user->lang['PM_USERS_REMOVED_NO_PM']; + } + + // print a notice about users not being added who do not have permission to receive PMs + if ($removed_no_permission) + { + $error[] = $user->lang['PM_USERS_REMOVED_NO_PERMISSION']; + } + + if (!sizeof(array_keys($address_list['u']))) + { + return; + } + + // Check if users have permission to read PMs + $can_read = $auth->acl_get_list(array_keys($address_list['u']), 'u_readpm'); + $can_read = (empty($can_read) || !isset($can_read[0]['u_readpm'])) ? array() : $can_read[0]['u_readpm']; + $cannot_read_list = array_diff(array_keys($address_list['u']), $can_read); + if (!empty($cannot_read_list)) + { + foreach ($cannot_read_list as $cannot_read) { - $removed = true; - unset($address_list['u'][$row['user_id']]); + unset($address_list['u'][$cannot_read]); } - $db->sql_freeresult($result); - // print a notice about users not being added who do not want to receive pms - if ($removed) + $error[] = $user->lang['PM_USERS_REMOVED_NO_PERMISSION']; + } + + // Check if users are banned + $banned_user_list = phpbb_get_banned_user_ids(array_keys($address_list['u']), false); + if (!empty($banned_user_list)) + { + foreach ($banned_user_list as $banned_user) { - $error[] = $user->lang['PM_USERS_REMOVED_NO_PM']; + unset($address_list['u'][$banned_user]); } + + $error[] = $user->lang['PM_USERS_REMOVED_NO_PERMISSION']; } } } @@ -1305,5 +1457,3 @@ function get_recipients($address_list, $num_recipients = 1) return $recipient; } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_pm_options.php b/phpBB/includes/ucp/ucp_pm_options.php index 1d5c0ecce3..d1fc9d2c62 100644 --- a/phpBB/includes/ucp/ucp_pm_options.php +++ b/phpBB/includes/ucp/ucp_pm_options.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -70,7 +73,7 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit trigger_error($message); } } - + // Add Folder if (isset($_POST['addfolder'])) { @@ -231,11 +234,11 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit // Move Messages case 1: $num_moved = move_pm($user->data['user_id'], $user->data['message_limit'], $msg_ids, $move_to, $remove_folder_id); - + // Something went wrong, only partially moved? if ($num_moved != $folder_row['pm_count']) { - trigger_error(sprintf($user->lang['MOVE_PM_ERROR'], $num_moved, $folder_row['pm_count'])); + trigger_error($user->lang('MOVE_PM_ERROR', $user->lang('MESSAGES_COUNT', (int) $folder_row['pm_count']), $num_moved)); } break; @@ -423,10 +426,10 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit $result = $db->sql_query($sql); $num_messages = (int) $db->sql_fetchfield('num_messages'); $db->sql_freeresult($result); - + $folder[PRIVMSGS_INBOX] = array( 'folder_name' => $user->lang['PM_INBOX'], - 'message_status' => sprintf($user->lang['FOLDER_MESSAGE_STATUS'], $num_messages, $user->data['message_limit']) + 'message_status' => $user->lang('FOLDER_MESSAGE_STATUS', $user->lang('MESSAGES_COUNT', (int) $user->data['message_limit']), $num_messages), ); $sql = 'SELECT folder_id, folder_name, pm_count @@ -440,7 +443,7 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit $num_user_folder++; $folder[$row['folder_id']] = array( 'folder_name' => $row['folder_name'], - 'message_status' => sprintf($user->lang['FOLDER_MESSAGE_STATUS'], $row['pm_count'], $user->data['message_limit']) + 'message_status' => $user->lang('FOLDER_MESSAGE_STATUS', $user->lang('MESSAGES_COUNT', (int) $user->data['message_limit']), (int) $row['pm_count']), ); } $db->sql_freeresult($result); @@ -696,7 +699,7 @@ function define_rule_option($hardcoded, $rule_option, $rule_lang, $check_ary) function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule_conditions) { global $db, $template, $auth, $user; - + $template->assign_vars(array( 'S_COND_DEFINED' => true, 'S_COND_SELECT' => (!$hardcoded && isset($global_rule_conditions[$rule_option])) ? true : false) @@ -720,7 +723,7 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule { case 'text': $rule_string = utf8_normalize_nfc(request_var('rule_string', '', true)); - + $template->assign_vars(array( 'S_TEXT_CONDITION' => true, 'CURRENT_STRING' => $rule_string, @@ -734,7 +737,7 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule case 'user': $rule_user_id = request_var('rule_user_id', 0); $rule_string = utf8_normalize_nfc(request_var('rule_string', '', true)); - + if ($rule_string && !$rule_user_id) { $sql = 'SELECT user_id @@ -796,10 +799,10 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule { $sql .= 'WHERE'; } - - $sql .= " (g.group_name NOT IN ('GUESTS', 'BOTS') OR g.group_type <> " . GROUP_SPECIAL . ') + + $sql .= " (g.group_name NOT IN ('GUESTS', 'BOTS') OR g.group_type <> " . GROUP_SPECIAL . ') ORDER BY g.group_type DESC, g.group_name ASC'; - + $result = $db->sql_query($sql); $s_group_options = ''; @@ -812,7 +815,7 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule $s_class = ($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : ''; $s_selected = ($row['group_id'] == $rule_group_id) ? ' selected="selected"' : ''; - + $s_group_options .= '<option value="' . $row['group_id'] . '"' . $s_class . $s_selected . '>' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>'; } $db->sql_freeresult($result); @@ -850,7 +853,7 @@ function show_defined_rules($user_id, $check_lang, $rule_lang, $action_lang, $fo WHERE user_id = ' . $user_id . ' ORDER BY rule_id ASC'; $result = $db->sql_query($sql); - + $count = 0; while ($row = $db->sql_fetchrow($result)) { @@ -866,5 +869,3 @@ function show_defined_rules($user_id, $check_lang, $rule_lang, $action_lang, $fo } $db->sql_freeresult($result); } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_pm_viewfolder.php b/phpBB/includes/ucp/ucp_pm_viewfolder.php index bd7bf89854..19acd9ecb9 100644 --- a/phpBB/includes/ucp/ucp_pm_viewfolder.php +++ b/phpBB/includes/ucp/ucp_pm_viewfolder.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -165,7 +168,7 @@ function view_folder($id, $mode, $folder_id, $folder) 'PM_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? '<img src="' . $config['icons_path'] . '/' . $icons[$row['icon_id']]['img'] . '" width="' . $icons[$row['icon_id']]['width'] . '" height="' . $icons[$row['icon_id']]['height'] . '" alt="" title="" />' : '', 'PM_ICON_URL' => (!empty($icons[$row['icon_id']])) ? $config['icons_path'] . '/' . $icons[$row['icon_id']]['img'] : '', 'FOLDER_IMG' => $user->img($folder_img, $folder_alt), - 'FOLDER_IMG_SRC' => $user->img($folder_img, $folder_alt, false, '', 'src'), + 'FOLDER_IMG_STYLE' => $folder_img, 'PM_IMG' => ($row_indicator) ? $user->img('pm_' . $row_indicator, '') : '', 'ATTACH_ICON_IMG' => ($auth->acl_get('u_pm_download') && $row['message_attachment'] && $config['allow_pm_attach']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', @@ -177,7 +180,7 @@ function view_folder($id, $mode, $folder_id, $folder) 'U_VIEW_PM' => ($row['pm_deleted']) ? '' : $view_message_url, 'U_REMOVE_PM' => ($row['pm_deleted']) ? $remove_message_url : '', 'U_MCP_REPORT' => (isset($row['report_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=pm_reports&mode=pm_report_details&r=' . $row['report_id']) : '', - 'RECIPIENTS' => ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) ? implode(', ', $address_list[$message_id]) : '') + 'RECIPIENTS' => ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) ? implode($user->lang['COMMA_SEPARATOR'], $address_list[$message_id]) : '') ); } unset($folder_info['rowset']); @@ -267,10 +270,10 @@ function view_folder($id, $mode, $folder_id, $folder) } } - // There is the chance that all recipients of the message got deleted. To avoid creating + // There is the chance that all recipients of the message got deleted. To avoid creating // exports without recipients, we add a bogus "undisclosed recipient". - if (!(isset($address[$message_id]['g']) && sizeof($address[$message_id]['g'])) && - !(isset($address[$message_id]['u']) && sizeof($address[$message_id]['u']))) + if (!(isset($address[$message_id]['g']) && sizeof($address[$message_id]['g'])) && + !(isset($address[$message_id]['u']) && sizeof($address[$message_id]['u']))) { $address[$message_id]['u'] = array(); $address[$message_id]['u']['to'] = array(); @@ -278,12 +281,12 @@ function view_folder($id, $mode, $folder_id, $folder) } decode_message($message_row['message_text'], $message_row['bbcode_uid']); - + $data[] = array( 'subject' => censor_text($row['message_subject']), 'sender' => $row['username'], // ISO 8601 date. For PHP4 we are able to hardcode the timezone because $user->format_date() does not set it. - 'date' => $user->format_date($row['message_time'], (PHP_VERSION >= 5) ? 'c' : "Y-m-d\TH:i:s+00:00", true), + 'date' => $user->format_date($row['message_time'], 'c', true), 'to' => ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) ? $address[$message_id] : '', 'message' => $message_row['message_text'] ); @@ -380,7 +383,7 @@ function view_folder($id, $mode, $folder_id, $folder) break; } - header('Pragma: no-cache'); + header('Cache-Control: private, no-cache'); header("Content-Type: $mimetype; name=\"data.$filetype\""); header("Content-disposition: attachment; filename=data.$filetype"); echo $string; @@ -394,7 +397,7 @@ function view_folder($id, $mode, $folder_id, $folder) */ function get_pm_from($folder_id, $folder, $user_id) { - global $user, $db, $template, $config, $auth, $phpbb_root_path, $phpEx; + global $user, $db, $template, $config, $auth, $phpbb_container, $phpbb_root_path, $phpEx; $start = request_var('start', 0); @@ -403,6 +406,8 @@ function get_pm_from($folder_id, $folder, $user_id) $sort_key = request_var('sk', 't'); $sort_dir = request_var('sd', 'd'); + $pagination = $phpbb_container->get('pagination'); + // PM ordering options $limit_days = array(0 => $user->lang['ALL_MESSAGES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); @@ -452,10 +457,12 @@ function get_pm_from($folder_id, $folder, $user_id) $sql_limit_time = ''; } + $base_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=view&action=view_folder&f=$folder_id&$u_sort_param"); + $start = $pagination->validate_start($start, $config['topics_per_page'], $pm_count); + $pagination->generate_template_pagination($base_url, 'pagination', 'start', $pm_count, $config['topics_per_page'], $start); + $template->assign_vars(array( - 'PAGINATION' => generate_pagination(append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=view&action=view_folder&f=$folder_id&$u_sort_param"), $pm_count, $config['topics_per_page'], $start), - 'PAGE_NUMBER' => on_page($pm_count, $config['topics_per_page'], $start), - 'TOTAL_MESSAGES' => (($pm_count == 1) ? $user->lang['VIEW_PM_MESSAGE'] : sprintf($user->lang['VIEW_PM_MESSAGES'], $pm_count)), + 'TOTAL_MESSAGES' => $user->lang('VIEW_PM_MESSAGES', (int) $pm_count), 'POST_IMG' => (!$auth->acl_get('u_sendpm')) ? $user->img('button_topic_locked', 'POST_PM_LOCKED') : $user->img('button_pm_new', 'POST_NEW_PM'), @@ -480,14 +487,10 @@ function get_pm_from($folder_id, $folder, $user_id) { $store_reverse = true; - if ($start + $config['topics_per_page'] > $pm_count) - { - $sql_limit = min($config['topics_per_page'], max(1, $pm_count - $start)); - } - // Select the sort order $direction = ($sort_dir == 'd') ? 'ASC' : 'DESC'; - $sql_start = max(0, $pm_count - $sql_limit - $start); + $sql_limit = $pagination->reverse_limit($start, $sql_limit, $pm_count); + $sql_start = $pagination->reverse_start($start, $sql_limit, $pm_count); } else { @@ -552,5 +555,3 @@ function get_pm_from($folder_id, $folder, $user_id) 'rowset' => $rowset ); } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index 82a095dd9c..d81c4ce7fe 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -21,8 +24,8 @@ if (!defined('IN_PHPBB')) */ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) { - global $user, $template, $auth, $db, $cache; - global $phpbb_root_path, $phpEx, $config; + global $user, $template, $auth, $db, $cache, $phpbb_container; + global $phpbb_root_path, $request, $phpEx, $config, $phpbb_dispatcher; $user->add_lang(array('viewtopic', 'memberlist')); @@ -50,13 +53,12 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) // Grab icons $icons = $cache->obtain_icons(); - $bbcode = false; - - // Instantiate BBCode if need be - if ($message_row['bbcode_bitfield']) + // Load the custom profile fields + if ($config['load_cpf_pm']) { - include($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode($message_row['bbcode_bitfield']); + $cp = $phpbb_container->get('profilefields.manager'); + + $profile_fields = $cp->grab_profile_fields_data($author_id); } // Assign TO/BCC Addresses to template @@ -65,17 +67,8 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) $user_info = get_user_information($author_id, $message_row); // Parse the message and subject - $message = censor_text($message_row['message_text']); - - // Second parse bbcode here - if ($message_row['bbcode_bitfield']) - { - $bbcode->bbcode_second_pass($message, $message_row['bbcode_uid'], $message_row['bbcode_bitfield']); - } - - // Always process smilies after parsing bbcodes - $message = bbcode_nl2br($message); - $message = smiley_text($message); + $parse_flags = ($message_row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; + $message = generate_text_for_display($message_row['message_text'], $message_row['bbcode_uid'], $message_row['bbcode_bitfield'], $parse_flags, true); // Replace naughty words such as farty pants $message_row['message_subject'] = censor_text($message_row['message_subject']); @@ -83,8 +76,16 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) // Editing information if ($message_row['message_edit_count'] && $config['display_last_edited']) { - $l_edit_time_total = ($message_row['message_edit_count'] == 1) ? $user->lang['EDITED_TIME_TOTAL'] : $user->lang['EDITED_TIMES_TOTAL']; - $l_edited_by = '<br /><br />' . sprintf($l_edit_time_total, (!$message_row['message_edit_user']) ? $message_row['username'] : $message_row['message_edit_user'], $user->format_date($message_row['message_edit_time'], false, true), $message_row['message_edit_count']); + if (!$message_row['message_edit_user']) + { + $display_username = get_username_string('full', $author_id, $user_info['username'], $user_info['user_colour']); + } + else + { + $edit_user_info = get_user_information($message_row['message_edit_user'], false); + $display_username = get_username_string('full', $message_row['message_edit_user'], $edit_user_info['username'], $edit_user_info['user_colour']); + } + $l_edited_by = '<br /><br />' . $user->lang('EDITED_TIMES_TOTAL', (int) $message_row['message_edit_count'], $display_username, $user->format_date($message_row['message_edit_time'], false, true)); } else { @@ -150,31 +151,49 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) // End signature parsing, only if needed if ($signature) { - $signature = censor_text($signature); + $parse_flags = ($user_info['user_sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES; + $signature = generate_text_for_display($signature, $user_info['user_sig_bbcode_uid'], $user_info['user_sig_bbcode_bitfield'], $parse_flags, true); + } + + $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm'); - if ($user_info['user_sig_bbcode_bitfield']) + // Number of "to" recipients + $num_recipients = (int) preg_match_all('/:?(u|g)_([0-9]+):?/', $message_row['to_address'], $match); + + $bbcode_status = ($config['allow_bbcode'] && $config['auth_bbcode_pm'] && $auth->acl_get('u_pm_bbcode')) ? true : false; + + // Get the profile fields template data + $cp_row = array(); + if ($config['load_cpf_pm'] && isset($profile_fields[$author_id])) + { + // Filter the fields we don't want to show + foreach ($profile_fields[$author_id] as $used_ident => $profile_field) { - if ($bbcode === false) + if (!$profile_field['data']['field_show_on_pm']) { - include($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode($user_info['user_sig_bbcode_bitfield']); + unset($profile_fields[$author_id][$used_ident]); } - - $bbcode->bbcode_second_pass($signature, $user_info['user_sig_bbcode_uid'], $user_info['user_sig_bbcode_bitfield']); } - $signature = bbcode_nl2br($signature); - $signature = smiley_text($signature); + if (isset($profile_fields[$author_id])) + { + $cp_row = $cp->generate_profile_fields_template_data($profile_fields[$author_id]); + } } - $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm'); + $u_pm = $u_jabber = ''; - // Number of "to" recipients - $num_recipients = (int) preg_match_all('/:?(u|g)_([0-9]+):?/', $message_row['to_address'], $match); + if ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($user_info['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) + { + $u_pm = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $author_id); + } - $bbcode_status = ($config['allow_bbcode'] && $config['auth_bbcode_pm'] && $auth->acl_get('u_pm_bbcode')) ? true : false; + if ($config['jab_enable'] && $user_info['user_jabber'] && $auth->acl_get('u_sendim')) + { + $u_jabber = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=jabber&u=' . $author_id); + } - $template->assign_vars(array( + $msg_data = array( 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), 'MESSAGE_AUTHOR' => get_username_string('username', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), @@ -185,7 +204,8 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'AUTHOR_AVATAR' => (isset($user_info['avatar'])) ? $user_info['avatar'] : '', 'AUTHOR_JOINED' => $user->format_date($user_info['user_regdate']), 'AUTHOR_POSTS' => (int) $user_info['user_posts'], - 'AUTHOR_FROM' => (!empty($user_info['user_from'])) ? $user_info['user_from'] : '', + 'U_AUTHOR_POSTS' => ($config['load_search'] && $auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$author_id&sr=posts") : '', + 'CONTACT_USER' => $user->lang('CONTACT_USER', get_username_string('username', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username'])), 'ONLINE_IMG' => (!$config['load_onlinetrack']) ? '' : ((isset($user_info['online']) && $user_info['online']) ? $user->img('icon_user_online', $user->lang['ONLINE']) : $user->img('icon_user_offline', $user->lang['OFFLINE'])), 'S_ONLINE' => (!$config['load_onlinetrack']) ? false : ((isset($user_info['online']) && $user_info['online']) ? true : false), @@ -206,13 +226,8 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'EDITED_MESSAGE' => $l_edited_by, 'MESSAGE_ID' => $message_row['msg_id'], - 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($user_info['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $author_id) : '', - 'U_WWW' => (!empty($user_info['user_website'])) ? $user_info['user_website'] : '', - 'U_ICQ' => ($user_info['user_icq']) ? 'http://www.icq.com/people/' . urlencode($user_info['user_icq']) . '/' : '', - 'U_AIM' => ($user_info['user_aim'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=aim&u=' . $author_id) : '', - 'U_YIM' => ($user_info['user_yim']) ? 'http://edit.yahoo.com/config/send_webmesg?.target=' . urlencode($user_info['user_yim']) . '&.src=pg' : '', - 'U_MSN' => ($user_info['user_msnm'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=msnm&u=' . $author_id) : '', - 'U_JABBER' => ($user_info['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contact&action=jabber&u=' . $author_id) : '', + 'U_PM' => $u_pm, + 'U_JABBER' => $u_jabber, 'U_DELETE' => ($auth->acl_get('u_pm_delete')) ? "$url&mode=compose&action=delete&f=$folder_id&p=" . $message_row['msg_id'] : '', 'U_EMAIL' => $user_info['email'], @@ -232,11 +247,86 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'S_SPECIAL_FOLDER' => in_array($folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)), 'S_PM_RECIPIENTS' => $num_recipients, 'S_BBCODE_ALLOWED' => ($bbcode_status) ? 1 : 0, + 'S_CUSTOM_FIELDS' => (!empty($cp_row['row'])) ? true : false, 'U_PRINT_PM' => ($config['print_pm'] && $auth->acl_get('u_pm_printpm')) ? "$url&f=$folder_id&p=" . $message_row['msg_id'] . "&view=print" : '', - 'U_FORWARD_PM' => ($config['forward_pm'] && $auth->acl_get('u_sendpm') && $auth->acl_get('u_pm_forward')) ? "$url&mode=compose&action=forward&f=$folder_id&p=" . $message_row['msg_id'] : '') + 'U_FORWARD_PM' => ($config['forward_pm'] && $auth->acl_get('u_sendpm') && $auth->acl_get('u_pm_forward')) ? "$url&mode=compose&action=forward&f=$folder_id&p=" . $message_row['msg_id'] : '', ); + /** + * Modify pm and sender data before it is assigned to the template + * + * @event core.ucp_pm_view_messsage + * @var mixed id Active module category (can be int or string) + * @var string mode Active module + * @var int folder_id ID of the folder the message is in + * @var int msg_id ID of the private message + * @var array folder Array with data of user's message folders + * @var array message_row Array with message data + * @var array cp_row Array with senders custom profile field data + * @var array msg_data Template array with message data + * @since 3.1.0-a1 + */ + $vars = array( + 'id', + 'mode', + 'folder_id', + 'msg_id', + 'folder', + 'message_row', + 'cp_row', + 'msg_data', + ); + extract($phpbb_dispatcher->trigger_event('core.ucp_pm_view_messsage', compact($vars))); + + $template->assign_vars($msg_data); + + $contact_fields = array( + array( + 'ID' => 'pm', + 'NAME' => $user->lang['SEND_PRIVATE_MESSAGE'], + 'U_CONTACT' => $u_pm, + ), + array( + 'ID' => 'email', + 'NAME' => $user->lang['SEND_EMAIL'], + 'U_CONTACT' => $user_info['email'], + ), + array( + 'ID' => 'jabber', + 'NAME' => $user->lang['JABBER'], + 'U_CONTACT' => $u_jabber, + ), + ); + + foreach ($contact_fields as $field) + { + if ($field['U_CONTACT']) + { + $template->assign_block_vars('contact', $field); + } + } + + // Display the custom profile fields + if (!empty($cp_row['row'])) + { + $template->assign_vars($cp_row['row']); + + foreach ($cp_row['blockrow'] as $cp_block_row) + { + $template->assign_block_vars('custom_fields', $cp_block_row); + + if ($cp_block_row['S_PROFILE_CONTACT']) + { + $template->assign_block_vars('contact', array( + 'ID' => $cp_block_row['PROFILE_FIELD_IDENT'], + 'NAME' => $cp_block_row['PROFILE_FIELD_NAME'], + 'U_CONTACT' => $cp_block_row['PROFILE_FIELD_CONTACT'], + )); + } + } + } + // Display not already displayed Attachments for this post, we already parsed them. ;) if (isset($attachments) && sizeof($attachments)) { @@ -248,7 +338,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) } } - if (!isset($_REQUEST['view']) || $_REQUEST['view'] != 'print') + if (!isset($_REQUEST['view']) || $request->variable('view', '') != 'print') { // Message History if (message_history($msg_id, $user->data['user_id'], $message_row, $folder)) @@ -303,14 +393,17 @@ function get_user_information($user_id, $user_row) } } - if (!function_exists('get_user_avatar')) + $user_row['avatar'] = ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($user_row) : ''; + + if (!function_exists('phpbb_get_user_rank')) { include($phpbb_root_path . 'includes/functions_display.' . $phpEx); } - $user_row['avatar'] = ($user->optionget('viewavatars')) ? get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']) : ''; - - get_user_rank($user_row['user_rank'], $user_row['user_posts'], $user_row['rank_title'], $user_row['rank_image'], $user_row['rank_image_src']); + $user_rank_data = phpbb_get_user_rank($user_row, $user_row['user_posts']); + $user_row['rank_title'] = $user_rank_data['title']; + $user_row['rank_image'] = $user_rank_data['img']; + $user_row['rank_image_src'] = $user_rank_data['img_src']; if ((!empty($user_row['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_email')) { @@ -319,5 +412,3 @@ function get_user_information($user_id, $user_row) return $user_row; } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index c6e43b831c..1d3fb19f67 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * ucp_prefs * Changing user preferences -* @package ucp */ class ucp_prefs { @@ -27,7 +29,7 @@ class ucp_prefs function main($id, $mode) { - global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx; + global $config, $db, $user, $auth, $template, $phpbb_dispatcher, $phpbb_root_path, $phpEx; $submit = (isset($_POST['submit'])) ? true : false; $error = $data = array(); @@ -41,15 +43,12 @@ class ucp_prefs 'notifymethod' => request_var('notifymethod', $user->data['user_notify_type']), 'dateformat' => request_var('dateformat', $user->data['user_dateformat'], true), 'lang' => basename(request_var('lang', $user->data['user_lang'])), - 'style' => request_var('style', (int) $user->data['user_style']), - 'tz' => request_var('tz', (float) $user->data['user_timezone']), + 'user_style' => request_var('user_style', (int) $user->data['user_style']), + 'tz' => request_var('tz', $user->data['user_timezone']), - 'dst' => request_var('dst', (bool) $user->data['user_dst']), 'viewemail' => request_var('viewemail', (bool) $user->data['user_allow_viewemail']), 'massemail' => request_var('massemail', (bool) $user->data['user_allow_massemail']), 'hideonline' => request_var('hideonline', (bool) !$user->data['user_allow_viewonline']), - 'notifypm' => request_var('notifypm', (bool) $user->data['user_notify_pm']), - 'popuppm' => request_var('popuppm', (bool) $user->optionget('popuppm')), 'allowpm' => request_var('allowpm', (bool) $user->data['user_allow_pm']), ); @@ -59,22 +58,38 @@ class ucp_prefs $data['notifymethod'] = NOTIFY_BOTH; } + /** + * Add UCP edit global settings data before they are assigned to the template or submitted + * + * To assign data to the template, use $template->assign_vars() + * + * @event core.ucp_prefs_personal_data + * @var bool submit Do we display the form only + * or did the user press submit + * @var array data Array with current ucp options data + * @var array error Array with list of errors + * @since 3.1.0-a1 + * @changed 3.1.4-rc1 Added error variable to the event + */ + $vars = array('submit', 'data', 'error'); + extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_personal_data', compact($vars))); + if ($submit) { if ($config['override_user_style']) { - $data['style'] = (int) $config['default_style']; + $data['user_style'] = (int) $config['default_style']; } - else if (!phpbb_style_is_active($data['style'])) + else if (!phpbb_style_is_active($data['user_style'])) { - $data['style'] = (int) $user->data['user_style']; + $data['user_style'] = (int) $user->data['user_style']; } - $error = validate_data($data, array( + $error = array_merge(validate_data($data, array( 'dateformat' => array('string', false, 1, 30), 'lang' => array('language_iso_name'), - 'tz' => array('num', false, -14, 14), - )); + 'tz' => array('timezone'), + )), $error); if (!check_form_key('ucp_prefs_personal')) { @@ -83,24 +98,31 @@ class ucp_prefs if (!sizeof($error)) { - $user->optionset('popuppm', $data['popuppm']); - $sql_ary = array( 'user_allow_pm' => $data['allowpm'], 'user_allow_viewemail' => $data['viewemail'], 'user_allow_massemail' => $data['massemail'], 'user_allow_viewonline' => ($auth->acl_get('u_hideonline')) ? !$data['hideonline'] : $user->data['user_allow_viewonline'], 'user_notify_type' => $data['notifymethod'], - 'user_notify_pm' => $data['notifypm'], 'user_options' => $user->data['user_options'], - 'user_dst' => $data['dst'], 'user_dateformat' => $data['dateformat'], 'user_lang' => $data['lang'], 'user_timezone' => $data['tz'], - 'user_style' => $data['style'], + 'user_style' => $data['user_style'], ); + /** + * Update UCP edit global settings data on form submit + * + * @event core.ucp_prefs_personal_update_data + * @var array data Submitted display options data + * @var array sql_ary Display options data we update + * @since 3.1.0-a1 + */ + $vars = array('data', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_personal_update_data', compact($vars))); + $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $user->data['user_id']; @@ -112,7 +134,7 @@ class ucp_prefs } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); } $dateformat_options = ''; @@ -134,6 +156,8 @@ class ucp_prefs } $dateformat_options .= '>' . $user->lang['CUSTOM_DATEFORMAT'] . '</option>'; + phpbb_timezone_select($template, $user, $data['tz'], true); + // check if there are any user-selectable languages $sql = 'SELECT COUNT(lang_id) as languages_count FROM ' . LANG_TABLE; @@ -173,9 +197,6 @@ class ucp_prefs 'S_MASS_EMAIL' => $data['massemail'], 'S_ALLOW_PM' => $data['allowpm'], 'S_HIDE_ONLINE' => $data['hideonline'], - 'S_NOTIFY_PM' => $data['notifypm'], - 'S_POPUP_PM' => $data['popuppm'], - 'S_DST' => $data['dst'], 'DATE_FORMAT' => $data['dateformat'], 'A_DATE_FORMAT' => addslashes($data['dateformat']), @@ -188,8 +209,7 @@ class ucp_prefs 'S_MORE_STYLES' => $s_more_styles, 'S_LANG_OPTIONS' => language_select($data['lang']), - 'S_STYLE_OPTIONS' => ($config['override_user_style']) ? '' : style_select($data['style']), - 'S_TZ_OPTIONS' => tz_select($data['tz'], true), + 'S_STYLE_OPTIONS' => ($config['override_user_style']) ? '' : style_select($data['user_style']), 'S_CAN_HIDE_ONLINE' => ($auth->acl_get('u_hideonline')) ? true : false, 'S_SELECT_NOTIFY' => ($config['jab_enable'] && $user->data['user_jabber'] && @extension_loaded('xml')) ? true : false) ); @@ -203,11 +223,11 @@ class ucp_prefs $data = array( 'topic_sk' => request_var('topic_sk', (!empty($user->data['user_topic_sortby_type'])) ? $user->data['user_topic_sortby_type'] : 't'), 'topic_sd' => request_var('topic_sd', (!empty($user->data['user_topic_sortby_dir'])) ? $user->data['user_topic_sortby_dir'] : 'd'), - 'topic_st' => request_var('topic_st', (!empty($user->data['user_topic_show_days'])) ? $user->data['user_topic_show_days'] : 0), + 'topic_st' => request_var('topic_st', (!empty($user->data['user_topic_show_days'])) ? (int) $user->data['user_topic_show_days'] : 0), 'post_sk' => request_var('post_sk', (!empty($user->data['user_post_sortby_type'])) ? $user->data['user_post_sortby_type'] : 't'), 'post_sd' => request_var('post_sd', (!empty($user->data['user_post_sortby_dir'])) ? $user->data['user_post_sortby_dir'] : 'a'), - 'post_st' => request_var('post_st', (!empty($user->data['user_post_show_days'])) ? $user->data['user_post_show_days'] : 0), + 'post_st' => request_var('post_st', (!empty($user->data['user_post_show_days'])) ? (int) $user->data['user_post_show_days'] : 0), 'images' => request_var('images', (bool) $user->optionget('viewimg')), 'flash' => request_var('flash', (bool) $user->optionget('viewflash')), @@ -217,13 +237,39 @@ class ucp_prefs 'wordcensor' => request_var('wordcensor', (bool) $user->optionget('viewcensors')), ); + /** + * Add UCP edit display options data before they are assigned to the template or submitted + * + * To assign data to the template, use $template->assign_vars() + * + * @event core.ucp_prefs_view_data + * @var bool submit Do we display the form only + * or did the user press submit + * @var array data Array with current ucp options data + * @since 3.1.0-a1 + */ + $vars = array('submit', 'data'); + extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_view_data', compact($vars))); + if ($submit) { $error = validate_data($data, array( - 'topic_sk' => array('string', false, 1, 1), - 'topic_sd' => array('string', false, 1, 1), - 'post_sk' => array('string', false, 1, 1), - 'post_sd' => array('string', false, 1, 1), + 'topic_sk' => array( + array('string', false, 1, 1), + array('match', false, '#(a|r|s|t|v)#'), + ), + 'topic_sd' => array( + array('string', false, 1, 1), + array('match', false, '#(a|d)#'), + ), + 'post_sk' => array( + array('string', false, 1, 1), + array('match', false, '#(a|s|t)#'), + ), + 'post_sd' => array( + array('string', false, 1, 1), + array('match', false, '#(a|d)#'), + ), )); if (!check_form_key('ucp_prefs_view')) @@ -255,6 +301,17 @@ class ucp_prefs 'user_post_show_days' => $data['post_st'], ); + /** + * Update UCP edit display options data on form submit + * + * @event core.ucp_prefs_view_update_data + * @var array data Submitted display options data + * @var array sql_ary Display options data we update + * @since 3.1.0-a1 + */ + $vars = array('data', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_view_update_data', compact($vars))); + $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $user->data['user_id']; @@ -266,7 +323,7 @@ class ucp_prefs } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); } $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); @@ -275,7 +332,7 @@ class ucp_prefs $limit_topic_days = array(0 => $user->lang['ALL_TOPICS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); $sort_by_topic_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 'r' => $user->lang['REPLIES'], 's' => $user->lang['SUBJECT'], 'v' => $user->lang['VIEWS']); - $sort_by_topic_sql = array('a' => 't.topic_first_poster_name', 't' => 't.topic_last_post_time', 'r' => 't.topic_replies', 's' => 't.topic_title', 'v' => 't.topic_views'); + $sort_by_topic_sql = array('a' => 't.topic_first_poster_name', 't' => array('t.topic_last_post_time', 't.topic_last_post_id'), 'r' => 't.topic_posts_approved', 's' => 't.topic_title', 'v' => 't.topic_views'); // Post ordering options $limit_post_days = array(0 => $user->lang['ALL_POSTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); @@ -343,6 +400,20 @@ class ucp_prefs ); add_form_key('ucp_prefs_post'); + /** + * Add UCP edit posting defaults data before they are assigned to the template or submitted + * + * To assign data to the template, use $template->assign_vars() + * + * @event core.ucp_prefs_post_data + * @var bool submit Do we display the form only + * or did the user press submit + * @var array data Array with current ucp options data + * @since 3.1.0-a1 + */ + $vars = array('submit', 'data'); + extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_post_data', compact($vars))); + if ($submit) { if (check_form_key('ucp_prefs_post')) @@ -356,6 +427,17 @@ class ucp_prefs 'user_notify' => $data['notify'], ); + /** + * Update UCP edit posting defaults data on form submit + * + * @event core.ucp_prefs_post_update_data + * @var array data Submitted display options data + * @var array sql_ary Display options data we update + * @since 3.1.0-a1 + */ + $vars = array('data', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_post_update_data', compact($vars))); + $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $user->data['user_id']; @@ -381,6 +463,24 @@ class ucp_prefs break; } + /** + * Modify UCP preferences data before the page load + * + * @event core.ucp_prefs_modify_common + * @var array data Array with current/submitted UCP options data + * @var array error Errors data + * @var string mode UCP prefs operation mode + * @var string s_hidden_fields Hidden fields data + * @since 3.1.0-RC3 + */ + $vars = array( + 'data', + 'error', + 'mode', + 's_hidden_fields', + ); + extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_modify_common', compact($vars))); + $template->assign_vars(array( 'L_TITLE' => $user->lang['UCP_PREFS_' . strtoupper($mode)], @@ -392,5 +492,3 @@ class ucp_prefs $this->page_title = 'UCP_PREFS_' . strtoupper($mode); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index 847311058b..8d8d42e742 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -21,7 +24,6 @@ if (!defined('IN_PHPBB')) * Changing profile settings * * @todo what about pertaining user_sig_options? -* @package ucp */ class ucp_profile { @@ -29,13 +31,14 @@ class ucp_profile function main($id, $mode) { - global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx; + global $cache, $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx; + global $request, $phpbb_container, $phpbb_dispatcher; $user->add_lang('posting'); - $preview = (!empty($_POST['preview'])) ? true : false; - $submit = (!empty($_POST['submit'])) ? true : false; - $delete = (!empty($_POST['delete'])) ? true : false; + $preview = $request->variable('preview', false, false, \phpbb\request\request_interface::POST); + $submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST); + $delete = $request->variable('delete', false, false, \phpbb\request\request_interface::POST); $error = $data = array(); $s_hidden_fields = ''; @@ -46,12 +49,22 @@ class ucp_profile $data = array( 'username' => utf8_normalize_nfc(request_var('username', $user->data['username'], true)), 'email' => strtolower(request_var('email', $user->data['user_email'])), - 'email_confirm' => strtolower(request_var('email_confirm', '')), - 'new_password' => request_var('new_password', '', true), - 'cur_password' => request_var('cur_password', '', true), - 'password_confirm' => request_var('password_confirm', '', true), + 'new_password' => $request->variable('new_password', '', true), + 'cur_password' => $request->variable('cur_password', '', true), + 'password_confirm' => $request->variable('password_confirm', '', true), ); + /** + * Modify user registration data on editing account settings in UCP + * + * @event core.ucp_profile_reg_details_data + * @var array data Array with current or updated user registration data + * @var bool submit Flag indicating if submit button has been pressed + * @since 3.1.4-RC1 + */ + $vars = array('data', 'submit'); + extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_data', compact($vars))); + add_form_key('ucp_reg_details'); if ($submit) @@ -64,8 +77,7 @@ class ucp_profile 'password_confirm' => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), 'email' => array( array('string', false, 6, 60), - array('email')), - 'email_confirm' => array('string', true, 6, 60), + array('user_email')), ); if ($auth->acl_get('u_chgname') && $config['allow_namechange']) @@ -78,23 +90,21 @@ class ucp_profile $error = validate_data($data, $check_ary); - if ($auth->acl_get('u_chgemail') && $data['email'] != $user->data['user_email'] && $data['email_confirm'] != $data['email']) - { - $error[] = ($data['email_confirm']) ? 'NEW_EMAIL_ERROR' : 'NEW_EMAIL_CONFIRM_EMPTY'; - } - if ($auth->acl_get('u_chgpasswd') && $data['new_password'] && $data['password_confirm'] != $data['new_password']) { $error[] = ($data['password_confirm']) ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; } + // Instantiate passwords manager + $passwords_manager = $phpbb_container->get('passwords.manager'); + // Only check the new password against the previous password if there have been no errors - if (!sizeof($error) && $auth->acl_get('u_chgpasswd') && $data['new_password'] && phpbb_check_hash($data['new_password'], $user->data['user_password'])) + if (!sizeof($error) && $auth->acl_get('u_chgpasswd') && $data['new_password'] && $passwords_manager->check($data['new_password'], $user->data['user_password'])) { $error[] = 'SAME_PASSWORD_ERROR'; } - if (!phpbb_check_hash($data['cur_password'], $user->data['user_password'])) + if (!$passwords_manager->check($data['cur_password'], $user->data['user_password'])) { $error[] = ($data['cur_password']) ? 'CUR_PASSWORD_ERROR' : 'CUR_PASSWORD_EMPTY'; } @@ -104,6 +114,18 @@ class ucp_profile $error[] = 'FORM_INVALID'; } + /** + * Validate user data on editing registration data in UCP + * + * @event core.ucp_profile_reg_details_validate + * @var array data Array with user profile data + * @var bool submit Flag indicating if submit button has been pressed + * @var array error Array of any generated errors + * @since 3.1.4-RC1 + */ + $vars = array('data', 'submit', 'error'); + extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_validate', compact($vars))); + if (!sizeof($error)) { $sql_ary = array( @@ -111,7 +133,7 @@ class ucp_profile 'username_clean' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? utf8_clean_string($data['username']) : $user->data['username_clean'], 'user_email' => ($auth->acl_get('u_chgemail')) ? $data['email'] : $user->data['user_email'], 'user_email_hash' => ($auth->acl_get('u_chgemail')) ? phpbb_email_hash($data['email']) : $user->data['user_email_hash'], - 'user_password' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? phpbb_hash($data['new_password']) : $user->data['user_password'], + 'user_password' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? $passwords_manager->hash($data['new_password']) : $user->data['user_password'], 'user_passchg' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? time() : 0, ); @@ -120,7 +142,7 @@ class ucp_profile add_log('user', $user->data['user_id'], 'LOG_USER_UPDATE_NAME', $user->data['username'], $data['username']); } - if ($auth->acl_get('u_chgpasswd') && $data['new_password'] && !phpbb_check_hash($data['new_password'], $user->data['user_password'])) + if ($auth->acl_get('u_chgpasswd') && $data['new_password'] && !$passwords_manager->check($data['new_password'], $user->data['user_password'])) { $user->reset_login_keys(); add_log('user', $user->data['user_id'], 'LOG_USER_NEW_PASSWORD', $data['username']); @@ -181,8 +203,7 @@ class ucp_profile while ($row = $db->sql_fetchrow($result)) { $messenger->template('admin_activate', $row['user_lang']); - $messenger->to($row['user_email'], $row['username']); - $messenger->im($row['user_jabber'], $row['username']); + $messenger->set_addresses($row); $messenger->assign_vars(array( 'USERNAME' => htmlspecialchars_decode($data['username']), @@ -202,6 +223,17 @@ class ucp_profile $sql_ary['user_newpasswd'] = ''; } + /** + * Modify user registration data before submitting it to the database + * + * @event core.ucp_profile_reg_details_sql_ary + * @var array data Array with current or updated user registration data + * @var array sql_ary Array with user registration data to submit to the database + * @since 3.1.4-RC1 + */ + $vars = array('data', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_sql_ary', compact($vars))); + if (sizeof($sql_ary)) { $sql = 'UPDATE ' . USERS_TABLE . ' @@ -235,7 +267,7 @@ class ucp_profile } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); } $template->assign_vars(array( @@ -247,8 +279,8 @@ class ucp_profile 'NEW_PASSWORD' => $data['new_password'], 'CUR_PASSWORD' => '', - 'L_USERNAME_EXPLAIN' => sprintf($user->lang[$config['allow_name_chars'] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), - 'L_CHANGE_PASSWORD_EXPLAIN' => sprintf($user->lang[$config['pass_complex'] . '_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), + 'L_USERNAME_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), + 'L_CHANGE_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars']), $user->lang('CHARACTERS', (int) $config['max_pass_chars'])), 'S_FORCE_PASSWORD' => ($auth->acl_get('u_chgpasswd') && $config['chg_passforce'] && $user->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) ? true : false, 'S_CHANGE_USERNAME' => ($config['allow_namechange'] && $auth->acl_get('u_chgname')) ? true : false, @@ -258,23 +290,18 @@ class ucp_profile break; case 'profile_info': + // Do not display profile information panel if not authed to do so + if (!$auth->acl_get('u_chgprofileinfo')) + { + trigger_error('NO_AUTH_PROFILEINFO'); + } - include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); - - $cp = new custom_profile(); + $cp = $phpbb_container->get('profilefields.manager'); $cp_data = $cp_error = array(); $data = array( - 'icq' => request_var('icq', $user->data['user_icq']), - 'aim' => request_var('aim', $user->data['user_aim']), - 'msn' => request_var('msn', $user->data['user_msnm']), - 'yim' => request_var('yim', $user->data['user_yim']), 'jabber' => utf8_normalize_nfc(request_var('jabber', $user->data['user_jabber'], true)), - 'website' => request_var('website', $user->data['user_website']), - 'location' => utf8_normalize_nfc(request_var('location', $user->data['user_from'], true)), - 'occupation' => utf8_normalize_nfc(request_var('occupation', $user->data['user_occ'], true)), - 'interests' => utf8_normalize_nfc(request_var('interests', $user->data['user_interests'], true)), ); if ($config['allow_birthdays']) @@ -292,26 +319,25 @@ class ucp_profile $data['user_birthday'] = sprintf('%2d-%2d-%4d', $data['bday_day'], $data['bday_month'], $data['bday_year']); } + /** + * Modify user data on editing profile in UCP + * + * @event core.ucp_profile_modify_profile_info + * @var array data Array with user profile data + * @var bool submit Flag indicating if submit button has been pressed + * @since 3.1.4-RC1 + */ + $vars = array('data', 'submit'); + extract($phpbb_dispatcher->trigger_event('core.ucp_profile_modify_profile_info', compact($vars))); + add_form_key('ucp_profile_info'); if ($submit) { $validate_array = array( - 'icq' => array( - array('string', true, 3, 15), - array('match', true, '#^[0-9]+$#i')), - 'aim' => array('string', true, 3, 255), - 'msn' => array('string', true, 5, 255), 'jabber' => array( array('string', true, 5, 255), array('jabber')), - 'yim' => array('string', true, 5, 255), - 'website' => array( - array('string', true, 12, 255), - array('match', true, '#^http[s]?://(.*?\.)*?[a-z0-9\-]+\.[a-z]{2,4}#i')), - 'location' => array('string', true, 2, 100), - 'occupation' => array('string', true, 2, 500), - 'interests' => array('string', true, 2, 500), ); if ($config['allow_birthdays']) @@ -339,6 +365,18 @@ class ucp_profile $error[] = 'FORM_INVALID'; } + /** + * Validate user data on editing profile in UCP + * + * @event core.ucp_profile_validate_profile_info + * @var array data Array with user profile data + * @var bool submit Flag indicating if submit button has been pressed + * @var array error Array of any generated errors + * @since 3.1.4-RC1 + */ + $vars = array('data', 'submit', 'error'); + extract($phpbb_dispatcher->trigger_event('core.ucp_profile_validate_profile_info', compact($vars))); + if (!sizeof($error)) { $data['notify'] = $user->data['user_notify_type']; @@ -351,15 +389,7 @@ class ucp_profile } $sql_ary = array( - 'user_icq' => $data['icq'], - 'user_aim' => $data['aim'], - 'user_msnm' => $data['msn'], - 'user_yim' => $data['yim'], 'user_jabber' => $data['jabber'], - 'user_website' => $data['website'], - 'user_from' => $data['location'], - 'user_occ' => $data['occupation'], - 'user_interests'=> $data['interests'], 'user_notify_type' => $data['notify'], ); @@ -368,6 +398,18 @@ class ucp_profile $sql_ary['user_birthday'] = $data['user_birthday']; } + /** + * Modify profile data in UCP before submitting to the database + * + * @event core.ucp_profile_info_modify_sql_ary + * @var array cp_data Array with the user custom profile fields data + * @var array data Array with user profile data + * @var array sql_ary user options data we update + * @since 3.1.4-RC1 + */ + $vars = array('cp_data', 'data', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.ucp_profile_info_modify_sql_ary', compact($vars))); + $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $user->data['user_id']; @@ -382,7 +424,7 @@ class ucp_profile } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); } if ($config['allow_birthdays']) @@ -420,17 +462,9 @@ class ucp_profile } $template->assign_vars(array( - 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', - - 'ICQ' => $data['icq'], - 'YIM' => $data['yim'], - 'AIM' => $data['aim'], - 'MSN' => $data['msn'], - 'JABBER' => $data['jabber'], - 'WEBSITE' => $data['website'], - 'LOCATION' => $data['location'], - 'OCCUPATION'=> $data['occupation'], - 'INTERESTS' => $data['interests'], + 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', + 'S_JABBER_ENABLED' => $config['jab_enable'], + 'JABBER' => $data['jabber'], )); // Get additional profile fields and assign them to the template block var 'profile_fields' @@ -507,7 +541,7 @@ class ucp_profile } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); } $signature_preview = ''; @@ -536,7 +570,7 @@ class ucp_profile 'URL_STATUS' => ($config['allow_sig_links']) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'], 'MAX_FONT_SIZE' => (int) $config['max_sig_font_size'], - 'L_SIGNATURE_EXPLAIN' => sprintf($user->lang['SIGNATURE_EXPLAIN'], $config['max_sig_chars']), + 'L_SIGNATURE_EXPLAIN' => $user->lang('SIGNATURE_EXPLAIN', (int) $config['max_sig_chars']), 'S_BBCODE_ALLOWED' => $config['allow_sig_bbcode'], 'S_SMILIES_ALLOWED' => $config['allow_sig_smilies'], @@ -555,82 +589,186 @@ class ucp_profile case 'avatar': - include($phpbb_root_path . 'includes/functions_display.' . $phpEx); + add_form_key('ucp_avatar'); - $display_gallery = request_var('display_gallery', '0'); - $avatar_select = basename(request_var('avatar_select', '')); - $category = basename(request_var('category', '')); + $avatars_enabled = false; - $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $auth->acl_get('u_chgavatar') && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false; + if ($config['allow_avatar'] && $auth->acl_get('u_chgavatar')) + { + $phpbb_avatar_manager = $phpbb_container->get('avatar.manager'); + $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers(); - add_form_key('ucp_avatar'); + // This is normalised data, without the user_ prefix + $avatar_data = \phpbb\avatar\manager::clean_row($user->data, 'user'); - if ($submit) - { - if (check_form_key('ucp_avatar')) + if ($submit) + { + if (check_form_key('ucp_avatar')) + { + $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', '')); + + if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete')) + { + $driver = $phpbb_avatar_manager->get_driver($driver_name); + $result = $driver->process_form($request, $template, $user, $avatar_data, $error); + + if ($result && empty($error)) + { + // Success! Lets save the result in the database + $result = array( + 'user_avatar_type' => $driver_name, + 'user_avatar' => $result['avatar'], + 'user_avatar_width' => $result['avatar_width'], + 'user_avatar_height' => $result['avatar_height'], + ); + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $result) . ' + WHERE user_id = ' . (int) $user->data['user_id']; + + $db->sql_query($sql); + + meta_refresh(3, $this->u_action); + $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>'); + trigger_error($message); + } + } + } + else + { + $error[] = 'FORM_INVALID'; + } + } + + // Handle deletion of avatars + if ($request->is_set_post('avatar_delete')) { - if (avatar_process_user($error, false, $can_upload)) + if (!confirm_box(true)) + { + confirm_box(false, $user->lang('CONFIRM_AVATAR_DELETE'), build_hidden_fields(array( + 'avatar_delete' => true, + 'i' => $id, + 'mode' => $mode)) + ); + } + else { + $phpbb_avatar_manager->handle_avatar_delete($db, $user, $avatar_data, USERS_TABLE, 'user_'); + meta_refresh(3, $this->u_action); $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>'); trigger_error($message); } } - else + + $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user->data['user_avatar_type'])); + + foreach ($avatar_drivers as $current_driver) { - $error[] = 'FORM_INVALID'; + $driver = $phpbb_avatar_manager->get_driver($current_driver); + + $avatars_enabled = true; + $template->set_filenames(array( + 'avatar' => $driver->get_template_name(), + )); + + if ($driver->prepare_form($request, $template, $user, $avatar_data, $error)) + { + $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver); + $driver_upper = strtoupper($driver_name); + + $template->assign_block_vars('avatar_drivers', array( + 'L_TITLE' => $user->lang($driver_upper . '_TITLE'), + 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'), + + 'DRIVER' => $driver_name, + 'SELECTED' => $current_driver == $selected_driver, + 'OUTPUT' => $template->assign_display('avatar'), + )); + } } + // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = $phpbb_avatar_manager->localize_errors($user, $error); } - if (!$config['allow_avatar'] && $user->data['user_avatar_type']) - { - $error[] = $user->lang['AVATAR_NOT_ALLOWED']; - } - else if ((($user->data['user_avatar_type'] == AVATAR_UPLOAD) && !$config['allow_avatar_upload']) || - (($user->data['user_avatar_type'] == AVATAR_REMOTE) && !$config['allow_avatar_remote']) || - (($user->data['user_avatar_type'] == AVATAR_GALLERY) && !$config['allow_avatar_local'])) - { - $error[] = $user->lang['AVATAR_TYPE_NOT_ALLOWED']; - } + $avatar = phpbb_get_user_avatar($user->data, 'USER_AVATAR', true); $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', - 'AVATAR' => get_user_avatar($user->data['user_avatar'], $user->data['user_avatar_type'], $user->data['user_avatar_width'], $user->data['user_avatar_height'], 'USER_AVATAR', true), - 'AVATAR_SIZE' => $config['avatar_filesize'], + 'AVATAR' => $avatar, - 'U_GALLERY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&mode=avatar&display_gallery=1'), + 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"', - 'S_FORM_ENCTYPE' => ($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '', + 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(), - 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], $config['avatar_filesize'] / 1024), + 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled), )); - if ($config['allow_avatar'] && $display_gallery && $auth->acl_get('u_chgavatar') && $config['allow_avatar_local']) + break; + + case 'autologin_keys': + + add_form_key('ucp_autologin_keys'); + + if ($submit) { - avatar_gallery($category, $avatar_select, 4); + $keys = request_var('keys', array('')); + + if (!check_form_key('ucp_autologin_keys')) + { + $error[] = 'FORM_INVALID'; + } + + if (!sizeof($error)) + { + if (!empty($keys)) + { + foreach ($keys as $key => $id) + { + $keys[$key] = $db->sql_like_expression($id . $db->get_any_char()); + } + $sql_where = '(key_id ' . implode(' OR key_id ', $keys) . ')'; + $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . ' + WHERE user_id = ' . (int) $user->data['user_id'] . ' + AND ' . $sql_where ; + + $db->sql_query($sql); + + meta_refresh(3, $this->u_action); + $message = $user->lang['AUTOLOGIN_SESSION_KEYS_DELETED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>'); + trigger_error($message); + } + } + + // Replace "error" strings with their real, localised form + $error = array_map(array($user, 'lang'), $error); } - else if ($config['allow_avatar']) - { - $avatars_enabled = (($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) || ($auth->acl_get('u_chgavatar') && ($config['allow_avatar_local'] || $config['allow_avatar_remote']))) ? true : false; - $template->assign_vars(array( - 'AVATAR_WIDTH' => request_var('width', $user->data['user_avatar_width']), - 'AVATAR_HEIGHT' => request_var('height', $user->data['user_avatar_height']), - - 'S_AVATARS_ENABLED' => $avatars_enabled, - 'S_UPLOAD_AVATAR_FILE' => ($can_upload && $config['allow_avatar_upload']) ? true : false, - 'S_UPLOAD_AVATAR_URL' => ($can_upload && $config['allow_avatar_remote_upload']) ? true : false, - 'S_LINK_AVATAR' => ($auth->acl_get('u_chgavatar') && $config['allow_avatar_remote']) ? true : false, - 'S_DISPLAY_GALLERY' => ($auth->acl_get('u_chgavatar') && $config['allow_avatar_local']) ? true : false) - ); + $sql = 'SELECT key_id, last_ip, last_login + FROM ' . SESSIONS_KEYS_TABLE . ' + WHERE user_id = ' . (int) $user->data['user_id'] . ' + ORDER BY last_login ASC'; + + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $template->assign_block_vars('sessions', array( + 'KEY' => substr($row['key_id'], 0, 8), + 'IP' => $row['last_ip'], + 'LOGIN_TIME' => $user->format_date($row['last_login']), + )); } + $db->sql_freeresult($result); + break; } $template->assign_vars(array( + 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', + 'L_TITLE' => $user->lang['UCP_PROFILE_' . strtoupper($mode)], 'S_HIDDEN_FIELDS' => $s_hidden_fields, @@ -642,5 +780,3 @@ class ucp_profile $this->page_title = 'UCP_PROFILE_' . strtoupper($mode); } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index 6ad3a55589..0ee45b0706 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * ucp_register * Board registration -* @package ucp */ class ucp_register { @@ -28,18 +30,18 @@ class ucp_register function main($id, $mode) { global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx; + global $request, $phpbb_container, $phpbb_dispatcher; // - if ($config['require_activation'] == USER_ACTIVATION_DISABLE) + if ($config['require_activation'] == USER_ACTIVATION_DISABLE || + (in_array($config['require_activation'], array(USER_ACTIVATION_SELF, USER_ACTIVATION_ADMIN)) && !$config['email_enable'])) { trigger_error('UCP_REGISTER_DISABLE'); } - include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); - - $coppa = (isset($_REQUEST['coppa'])) ? ((!empty($_REQUEST['coppa'])) ? 1 : 0) : false; - $agreed = (!empty($_POST['agreed'])) ? 1 : 0; - $submit = (isset($_POST['submit'])) ? true : false; + $coppa = $request->is_set('coppa') ? (int) $request->variable('coppa', false) : false; + $agreed = $request->variable('agreed', false); + $submit = $request->is_set_post('submit'); $change_lang = request_var('change_lang', ''); $user_lang = request_var('lang', $user->lang_name); @@ -63,13 +65,10 @@ class ucp_register $submit = false; // Setting back agreed to let the user view the agreement in his/her language - $agreed = (empty($_GET['change_lang'])) ? 0 : $agreed; + $agreed = false; } - $user->lang_name = $user_lang = $use_lang; - $user->lang = array(); - $user->data['user_lang'] = $user->lang_name; - $user->add_lang(array('common', 'ucp')); + $user_lang = $use_lang; } else { @@ -78,19 +77,36 @@ class ucp_register } } - - $cp = new custom_profile(); + $cp = $phpbb_container->get('profilefields.manager'); $error = $cp_data = $cp_error = array(); + $s_hidden_fields = array(); + + // Handle login_link data added to $_hidden_fields + $login_link_data = $this->get_login_link_data_array(); + + if (!empty($login_link_data)) + { + // Confirm that we have all necessary data + $provider_collection = $phpbb_container->get('auth.provider_collection'); + $auth_provider = $provider_collection->get_provider($request->variable('auth_provider', '')); + + $result = $auth_provider->login_link_has_necessary_data($login_link_data); + if ($result !== null) + { + $error[] = $user->lang[$result]; + } + + $s_hidden_fields = array_merge($s_hidden_fields, $this->get_login_link_data_for_hidden_fields($login_link_data)); + } if (!$agreed || ($coppa === false && $config['coppa_enable']) || ($coppa && !$config['coppa_enable'])) { - $add_lang = ($change_lang) ? '&change_lang=' . urlencode($change_lang) : ''; $add_coppa = ($coppa !== false) ? '&coppa=' . $coppa : ''; - $s_hidden_fields = array( - 'change_lang' => $change_lang, - ); + $s_hidden_fields = array_merge($s_hidden_fields, array( + 'change_lang' => '', + )); // If we change the language, we want to pass on some more possible parameter. if ($change_lang) @@ -99,9 +115,8 @@ class ucp_register $s_hidden_fields = array_merge($s_hidden_fields, array( 'username' => utf8_normalize_nfc(request_var('username', '', true)), 'email' => strtolower(request_var('email', '')), - 'email_confirm' => strtolower(request_var('email_confirm', '')), 'lang' => $user->lang_name, - 'tz' => request_var('tz', (float) $config['board_timezone']), + 'tz' => request_var('tz', $config['board_timezone']), )); } @@ -121,7 +136,10 @@ class ucp_register if ($coppa === false && $config['coppa_enable']) { $now = getdate(); - $coppa_birthday = $user->format_date(mktime($now['hours'] + $user->data['user_dst'], $now['minutes'], $now['seconds'], $now['mon'], $now['mday'] - 1, $now['year'] - 13), $user->lang['DATE_FORMAT']); + $coppa_birthday = $user->create_datetime() + ->setDate($now['year'] - 13, $now['mon'], $now['mday'] - 1) + ->setTime(0, 0, 0) + ->format($user->lang['DATE_FORMAT'], true); unset($now); $template->assign_vars(array( @@ -129,12 +147,15 @@ class ucp_register 'L_COPPA_NO' => sprintf($user->lang['UCP_COPPA_BEFORE'], $coppa_birthday), 'L_COPPA_YES' => sprintf($user->lang['UCP_COPPA_ON_AFTER'], $coppa_birthday), - 'U_COPPA_NO' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=0' . $add_lang), - 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=1' . $add_lang), + 'U_COPPA_NO' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=0'), + 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=1'), 'S_SHOW_COPPA' => true, 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_lang), + 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), + + 'COOKIE_NAME' => $config['cookie_name'], + 'COOKIE_PATH' => $config['cookie_path'], )); } else @@ -146,7 +167,10 @@ class ucp_register 'S_SHOW_COPPA' => false, 'S_REGISTRATION' => true, 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields), - 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_lang . $add_coppa), + 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_coppa), + + 'COOKIE_NAME' => $config['cookie_name'], + 'COOKIE_PATH' => $config['cookie_path'], ) ); } @@ -156,27 +180,36 @@ class ucp_register return; } - - // The CAPTCHA kicks in here. We can't help that the information gets lost on language change. + // The CAPTCHA kicks in here. We can't help that the information gets lost on language change. if ($config['enable_confirm']) { - include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - $captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']); $captcha->init(CONFIRM_REG); } - $is_dst = $config['board_dst']; $timezone = $config['board_timezone']; $data = array( 'username' => utf8_normalize_nfc(request_var('username', '', true)), - 'new_password' => request_var('new_password', '', true), - 'password_confirm' => request_var('password_confirm', '', true), + 'new_password' => $request->variable('new_password', '', true), + 'password_confirm' => $request->variable('password_confirm', '', true), 'email' => strtolower(request_var('email', '')), - 'email_confirm' => strtolower(request_var('email_confirm', '')), 'lang' => basename(request_var('lang', $user->lang_name)), - 'tz' => request_var('tz', (float) $timezone), + 'tz' => request_var('tz', $timezone), ); + /** + * Add UCP register data before they are assigned to the template or submitted + * + * To assign data to the template, use $template->assign_vars() + * + * @event core.ucp_register_data_before + * @var bool submit Do we display the form only + * or did the user press submit + * @var array data Array with current ucp registration data + * @since 3.1.4-RC1 + */ + $vars = array('submit', 'data'); + extract($phpbb_dispatcher->trigger_event('core.ucp_register_data_before', compact($vars))); // Check and initialize some variables if needed if ($submit) @@ -191,9 +224,8 @@ class ucp_register 'password_confirm' => array('string', false, $config['min_pass_chars'], $config['max_pass_chars']), 'email' => array( array('string', false, 6, 60), - array('email')), - 'email_confirm' => array('string', false, 6, 60), - 'tz' => array('num', false, -14, 14), + array('user_email')), + 'tz' => array('timezone'), 'lang' => array('language_iso_name'), )); @@ -203,7 +235,7 @@ class ucp_register } // Replace "error" strings with their real, localised form - $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + $error = array_map(array($user, 'lang'), $error); if ($config['enable_confirm']) { @@ -237,12 +269,20 @@ class ucp_register { $error[] = $user->lang['NEW_PASSWORD_ERROR']; } - - if ($data['email'] != $data['email_confirm']) - { - $error[] = $user->lang['NEW_EMAIL_ERROR']; - } } + /** + * Check UCP registration data after they are submitted + * + * @event core.ucp_register_data_after + * @var bool submit Do we display the form only + * or did the user press submit + * @var array data Array with current ucp registration data + * @var array cp_data Array with custom profile fields data + * @var array error Array with list of errors + * @since 3.1.4-RC1 + */ + $vars = array('submit', 'data', 'cp_data', 'error'); + extract($phpbb_dispatcher->trigger_event('core.ucp_register_data_after', compact($vars))); if (!sizeof($error)) { @@ -283,13 +323,15 @@ class ucp_register $user_inactive_time = 0; } + // Instantiate passwords manager + $passwords_manager = $phpbb_container->get('passwords.manager'); + $user_row = array( 'username' => $data['username'], - 'user_password' => phpbb_hash($data['new_password']), + 'user_password' => $passwords_manager->hash($data['new_password']), 'user_email' => $data['email'], 'group_id' => (int) $group_id, - 'user_timezone' => (float) $data['tz'], - 'user_dst' => $is_dst, + 'user_timezone' => $data['tz'], 'user_lang' => $data['lang'], 'user_type' => $user_type, 'user_actkey' => $user_actkey, @@ -303,6 +345,20 @@ class ucp_register { $user_row['user_new'] = 1; } + /** + * Add into $user_row before user_add + * + * user_add allows adding more data into the users table + * + * @event core.ucp_register_user_row_after + * @var bool submit Do we display the form only + * or did the user press submit + * @var array cp_data Array with custom profile fields data + * @var array user_row Array with current ucp registration data + * @since 3.1.4-RC1 + */ + $vars = array('submit', 'cp_data', 'user_row'); + extract($phpbb_dispatcher->trigger_event('core.ucp_register_user_row_after', compact($vars))); // Register user... $user_id = user_add($user_row, $cp_data); @@ -369,41 +425,28 @@ class ucp_register } $messenger->send(NOTIFY_EMAIL); + } + + if ($config['require_activation'] == USER_ACTIVATION_ADMIN) + { + $phpbb_notifications = $phpbb_container->get('notification_manager'); + $phpbb_notifications->add_notifications('notification.type.admin_activate_user', array( + 'user_id' => $user_id, + 'user_actkey' => $user_row['user_actkey'], + 'user_regdate' => $user_row['user_regdate'], + )); + } - if ($config['require_activation'] == USER_ACTIVATION_ADMIN) + // Perform account linking if necessary + if (!empty($login_link_data)) + { + $login_link_data['user_id'] = $user_id; + + $result = $auth_provider->link_account($login_link_data); + + if ($result) { - // Grab an array of user_id's with a_user permissions ... these users can activate a user - $admin_ary = $auth->acl_get_list(false, 'a_user', false); - $admin_ary = (!empty($admin_ary[0]['a_user'])) ? $admin_ary[0]['a_user'] : array(); - - // Also include founders - $where_sql = ' WHERE user_type = ' . USER_FOUNDER; - - if (sizeof($admin_ary)) - { - $where_sql .= ' OR ' . $db->sql_in_set('user_id', $admin_ary); - } - - $sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type - FROM ' . USERS_TABLE . ' ' . - $where_sql; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - $messenger->template('admin_activate', $row['user_lang']); - $messenger->to($row['user_email'], $row['username']); - $messenger->im($row['user_jabber'], $row['username']); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($data['username']), - 'U_USER_DETAILS' => "$server_url/memberlist.$phpEx?mode=viewprofile&u=$user_id", - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u=$user_id&k=$user_actkey") - ); - - $messenger->send($row['user_notify_type']); - } - $db->sql_freeresult($result); + $message = $message . '<br /><br />' . $user->lang[$result]; } } @@ -412,10 +455,10 @@ class ucp_register } } - $s_hidden_fields = array( + $s_hidden_fields = array_merge($s_hidden_fields, array( 'agreed' => 'true', 'change_lang' => 0, - ); + )); if ($config['coppa_enable']) { @@ -450,25 +493,28 @@ class ucp_register break; } + $timezone_selects = phpbb_timezone_select($template, $user, $data['tz'], true); $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', 'USERNAME' => $data['username'], 'PASSWORD' => $data['new_password'], 'PASSWORD_CONFIRM' => $data['password_confirm'], 'EMAIL' => $data['email'], - 'EMAIL_CONFIRM' => $data['email_confirm'], 'L_REG_COND' => $l_reg_cond, - 'L_USERNAME_EXPLAIN' => sprintf($user->lang[$config['allow_name_chars'] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), - 'L_PASSWORD_EXPLAIN' => sprintf($user->lang[$config['pass_complex'] . '_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), + 'L_USERNAME_EXPLAIN' => $user->lang($config['allow_name_chars'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_name_chars']), $user->lang('CHARACTERS', (int) $config['max_name_chars'])), + 'L_PASSWORD_EXPLAIN' => $user->lang($config['pass_complex'] . '_EXPLAIN', $user->lang('CHARACTERS', (int) $config['min_pass_chars']), $user->lang('CHARACTERS', (int) $config['max_pass_chars'])), 'S_LANG_OPTIONS' => language_select($data['lang']), - 'S_TZ_OPTIONS' => tz_select($data['tz']), + 'S_TZ_PRESELECT' => !$submit, 'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh']) ? true : false, 'S_REGISTRATION' => true, 'S_COPPA' => $coppa, 'S_HIDDEN_FIELDS' => $s_hidden_fields, 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), + + 'COOKIE_NAME' => $config['cookie_name'], + 'COOKIE_PATH' => $config['cookie_path'], )); // @@ -481,6 +527,49 @@ class ucp_register $this->tpl_name = 'ucp_register'; $this->page_title = 'UCP_REGISTRATION'; } -} -?>
\ No newline at end of file + /** + * Creates the login_link data array + * + * @return array Returns an array of all POST paramaters whose names + * begin with 'login_link_' + */ + protected function get_login_link_data_array() + { + global $request; + + $var_names = $request->variable_names(\phpbb\request\request_interface::POST); + $login_link_data = array(); + $string_start_length = strlen('login_link_'); + + foreach ($var_names as $var_name) + { + if (strpos($var_name, 'login_link_') === 0) + { + $key_name = substr($var_name, $string_start_length); + $login_link_data[$key_name] = $request->variable($var_name, '', false, \phpbb\request\request_interface::POST); + } + } + + return $login_link_data; + } + + /** + * Prepends they key names of an associative array with 'login_link_' for + * inclusion on the page as hidden fields. + * + * @param array $data The array to be modified + * @return array The modified array + */ + protected function get_login_link_data_for_hidden_fields($data) + { + $new_data = array(); + + foreach ($data as $key => $value) + { + $new_data['login_link_' . $key] = $value; + } + + return $new_data; + } +} diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php index bcb21cbedc..415bf0e84d 100644 --- a/phpBB/includes/ucp/ucp_remind.php +++ b/phpBB/includes/ucp/ucp_remind.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * ucp_remind * Sending password reminders -* @package ucp */ class ucp_remind { @@ -28,7 +30,12 @@ class ucp_remind function main($id, $mode) { global $config, $phpbb_root_path, $phpEx; - global $db, $user, $auth, $template; + global $db, $user, $auth, $template, $phpbb_container; + + if (!$config['allow_password_reset']) + { + trigger_error($user->lang('UCP_PASSWORD_RESET_DISABLED', '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>')); + } $username = request_var('username', '', true); $email = strtolower(request_var('email', '')); @@ -67,7 +74,7 @@ class ucp_remind } // Check users permissions - $auth2 = new auth(); + $auth2 = new \phpbb\auth\auth(); $auth2->acl($user_row); if (!$auth2->acl_get('u_chgpasswd')) @@ -84,8 +91,11 @@ class ucp_remind // For the activation key a random length between 6 and 10 will do. $user_actkey = gen_rand_string(mt_rand(6, 10)); + // Instantiate passwords manager + $passwords_manager = $phpbb_container->get('passwords.manager'); + $sql = 'UPDATE ' . USERS_TABLE . " - SET user_newpasswd = '" . $db->sql_escape(phpbb_hash($user_password)) . "', user_actkey = '" . $db->sql_escape($user_actkey) . "' + SET user_newpasswd = '" . $db->sql_escape($passwords_manager->hash($user_password)) . "', user_actkey = '" . $db->sql_escape($user_actkey) . "' WHERE user_id = " . $user_row['user_id']; $db->sql_query($sql); @@ -95,8 +105,7 @@ class ucp_remind $messenger->template('user_activate_passwd', $user_row['user_lang']); - $messenger->to($user_row['user_email'], $user_row['username']); - $messenger->im($user_row['user_jabber'], $user_row['username']); + $messenger->set_addresses($user_row); $messenger->anti_abuse_headers($config, $user); @@ -124,5 +133,3 @@ class ucp_remind $this->page_title = 'UCP_REMIND'; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_resend.php b/phpBB/includes/ucp/ucp_resend.php index 4d181dba49..9fe8850000 100644 --- a/phpBB/includes/ucp/ucp_resend.php +++ b/phpBB/includes/ucp/ucp_resend.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -19,7 +22,6 @@ if (!defined('IN_PHPBB')) /** * ucp_resend * Resending activation emails -* @package ucp */ class ucp_resend { @@ -92,7 +94,7 @@ class ucp_resend if ($config['require_activation'] == USER_ACTIVATION_SELF || $coppa) { $messenger->template(($coppa) ? 'coppa_resend_inactive' : 'user_resend_inactive', $user_row['user_lang']); - $messenger->to($user_row['user_email'], $user_row['username']); + $messenger->set_addresses($user_row); $messenger->anti_abuse_headers($config, $user); @@ -127,8 +129,7 @@ class ucp_resend while ($row = $db->sql_fetchrow($result)) { $messenger->template('admin_activate', $row['user_lang']); - $messenger->to($row['user_email'], $row['username']); - $messenger->im($row['user_jabber'], $row['username']); + $messenger->set_addresses($row); $messenger->anti_abuse_headers($config, $user); @@ -160,5 +161,3 @@ class ucp_resend $this->page_title = 'UCP_RESEND'; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_zebra.php b/phpBB/includes/ucp/ucp_zebra.php index 5ed4db7520..dbf8cf31c1 100644 --- a/phpBB/includes/ucp/ucp_zebra.php +++ b/phpBB/includes/ucp/ucp_zebra.php @@ -1,10 +1,13 @@ <?php /** * -* @package ucp -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -16,17 +19,13 @@ if (!defined('IN_PHPBB')) exit; } -/** -* ucp_zebra -* @package ucp -*/ class ucp_zebra { var $u_action; function main($id, $mode) { - global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx; + global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx, $request, $phpbb_dispatcher; $submit = (isset($_POST['submit']) || isset($_GET['add']) || isset($_GET['remove'])) ? true : false; $s_hidden_fields = ''; @@ -55,9 +54,22 @@ class ucp_zebra // Remove users if (!empty($data['usernames'])) { + $user_ids = $data['usernames']; + + /** + * Remove users from friends/foes + * + * @event core.ucp_remove_zebra + * @var string mode Zebra type: friends|foes + * @var array user_ids User ids we remove + * @since 3.1.0-a1 + */ + $vars = array('mode', 'user_ids'); + extract($phpbb_dispatcher->trigger_event('core.ucp_remove_zebra', compact($vars))); + $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' WHERE user_id = ' . $user->data['user_id'] . ' - AND ' . $db->sql_in_set('zebra_id', $data['usernames']); + AND ' . $db->sql_in_set('zebra_id', $user_ids); $db->sql_query($sql); $updated = true; @@ -187,6 +199,19 @@ class ucp_zebra ); } + /** + * Add users to friends/foes + * + * @event core.ucp_add_zebra + * @var string mode Zebra type: + * friends|foes + * @var array sql_ary Array of + * entries we add + * @since 3.1.0-a1 + */ + $vars = array('mode', 'sql_ary'); + extract($phpbb_dispatcher->trigger_event('core.ucp_add_zebra', compact($vars))); + $db->sql_multi_insert(ZEBRA_TABLE, $sql_ary); $updated = true; @@ -200,7 +225,23 @@ class ucp_zebra } } - if ($updated) + if ($request->is_ajax()) + { + $message = ($updated) ? $user->lang[$l_mode . '_UPDATED'] : implode('<br />', $error); + + $json_response = new \phpbb\json_response; + $json_response->send(array( + 'success' => $updated, + + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $message, + 'REFRESH_DATA' => array( + 'time' => 3, + 'url' => $this->u_action + ) + )); + } + else if ($updated) { meta_refresh(3, $this->u_action); $message = $user->lang[$l_mode . '_UPDATED'] . '<br />' . implode('<br />', $error) . ((sizeof($error)) ? '<br />' : '') . '<br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>'); @@ -253,5 +294,3 @@ class ucp_zebra $this->page_title = 'UCP_ZEBRA_' . $l_mode; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/utf/data/case_fold_c.php b/phpBB/includes/utf/data/case_fold_c.php index 00de1ba349..a5e3fc7990 100644 --- a/phpBB/includes/utf/data/case_fold_c.php +++ b/phpBB/includes/utf/data/case_fold_c.php @@ -1 +1 @@ -<?php return array('A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','µ'=>'μ','À'=>'à','Á'=>'á','Â'=>'â','Ã'=>'ã','Ä'=>'ä','Å'=>'å','Æ'=>'æ','Ç'=>'ç','È'=>'è','É'=>'é','Ê'=>'ê','Ë'=>'ë','Ì'=>'ì','Í'=>'í','Î'=>'î','Ï'=>'ï','Ð'=>'ð','Ñ'=>'ñ','Ò'=>'ò','Ó'=>'ó','Ô'=>'ô','Õ'=>'õ','Ö'=>'ö','Ø'=>'ø','Ù'=>'ù','Ú'=>'ú','Û'=>'û','Ü'=>'ü','Ý'=>'ý','Þ'=>'þ','Ā'=>'ā','Ă'=>'ă','Ą'=>'ą','Ć'=>'ć','Ĉ'=>'ĉ','Ċ'=>'ċ','Č'=>'č','Ď'=>'ď','Đ'=>'đ','Ē'=>'ē','Ĕ'=>'ĕ','Ė'=>'ė','Ę'=>'ę','Ě'=>'ě','Ĝ'=>'ĝ','Ğ'=>'ğ','Ġ'=>'ġ','Ģ'=>'ģ','Ĥ'=>'ĥ','Ħ'=>'ħ','Ĩ'=>'ĩ','Ī'=>'ī','Ĭ'=>'ĭ','Į'=>'į','IJ'=>'ij','Ĵ'=>'ĵ','Ķ'=>'ķ','Ĺ'=>'ĺ','Ļ'=>'ļ','Ľ'=>'ľ','Ŀ'=>'ŀ','Ł'=>'ł','Ń'=>'ń','Ņ'=>'ņ','Ň'=>'ň','Ŋ'=>'ŋ','Ō'=>'ō','Ŏ'=>'ŏ','Ő'=>'ő','Œ'=>'œ','Ŕ'=>'ŕ','Ŗ'=>'ŗ','Ř'=>'ř','Ś'=>'ś','Ŝ'=>'ŝ','Ş'=>'ş','Š'=>'š','Ţ'=>'ţ','Ť'=>'ť','Ŧ'=>'ŧ','Ũ'=>'ũ','Ū'=>'ū','Ŭ'=>'ŭ','Ů'=>'ů','Ű'=>'ű','Ų'=>'ų','Ŵ'=>'ŵ','Ŷ'=>'ŷ','Ÿ'=>'ÿ','Ź'=>'ź','Ż'=>'ż','Ž'=>'ž','ſ'=>'s','Ɓ'=>'ɓ','Ƃ'=>'ƃ','Ƅ'=>'ƅ','Ɔ'=>'ɔ','Ƈ'=>'ƈ','Ɖ'=>'ɖ','Ɗ'=>'ɗ','Ƌ'=>'ƌ','Ǝ'=>'ǝ','Ə'=>'ə','Ɛ'=>'ɛ','Ƒ'=>'ƒ','Ɠ'=>'ɠ','Ɣ'=>'ɣ','Ɩ'=>'ɩ','Ɨ'=>'ɨ','Ƙ'=>'ƙ','Ɯ'=>'ɯ','Ɲ'=>'ɲ','Ɵ'=>'ɵ','Ơ'=>'ơ','Ƣ'=>'ƣ','Ƥ'=>'ƥ','Ʀ'=>'ʀ','Ƨ'=>'ƨ','Ʃ'=>'ʃ','Ƭ'=>'ƭ','Ʈ'=>'ʈ','Ư'=>'ư','Ʊ'=>'ʊ','Ʋ'=>'ʋ','Ƴ'=>'ƴ','Ƶ'=>'ƶ','Ʒ'=>'ʒ','Ƹ'=>'ƹ','Ƽ'=>'ƽ','DŽ'=>'dž','Dž'=>'dž','LJ'=>'lj','Lj'=>'lj','NJ'=>'nj','Nj'=>'nj','Ǎ'=>'ǎ','Ǐ'=>'ǐ','Ǒ'=>'ǒ','Ǔ'=>'ǔ','Ǖ'=>'ǖ','Ǘ'=>'ǘ','Ǚ'=>'ǚ','Ǜ'=>'ǜ','Ǟ'=>'ǟ','Ǡ'=>'ǡ','Ǣ'=>'ǣ','Ǥ'=>'ǥ','Ǧ'=>'ǧ','Ǩ'=>'ǩ','Ǫ'=>'ǫ','Ǭ'=>'ǭ','Ǯ'=>'ǯ','DZ'=>'dz','Dz'=>'dz','Ǵ'=>'ǵ','Ƕ'=>'ƕ','Ƿ'=>'ƿ','Ǹ'=>'ǹ','Ǻ'=>'ǻ','Ǽ'=>'ǽ','Ǿ'=>'ǿ','Ȁ'=>'ȁ','Ȃ'=>'ȃ','Ȅ'=>'ȅ','Ȇ'=>'ȇ','Ȉ'=>'ȉ','Ȋ'=>'ȋ','Ȍ'=>'ȍ','Ȏ'=>'ȏ','Ȑ'=>'ȑ','Ȓ'=>'ȓ','Ȕ'=>'ȕ','Ȗ'=>'ȗ','Ș'=>'ș','Ț'=>'ț','Ȝ'=>'ȝ','Ȟ'=>'ȟ','Ƞ'=>'ƞ','Ȣ'=>'ȣ','Ȥ'=>'ȥ','Ȧ'=>'ȧ','Ȩ'=>'ȩ','Ȫ'=>'ȫ','Ȭ'=>'ȭ','Ȯ'=>'ȯ','Ȱ'=>'ȱ','Ȳ'=>'ȳ','Ⱥ'=>'ⱥ','Ȼ'=>'ȼ','Ƚ'=>'ƚ','Ⱦ'=>'ⱦ','Ɂ'=>'ɂ','Ƀ'=>'ƀ','Ʉ'=>'ʉ','Ʌ'=>'ʌ','Ɇ'=>'ɇ','Ɉ'=>'ɉ','Ɋ'=>'ɋ','Ɍ'=>'ɍ','Ɏ'=>'ɏ','ͅ'=>'ι','Ά'=>'ά','Έ'=>'έ','Ή'=>'ή','Ί'=>'ί','Ό'=>'ό','Ύ'=>'ύ','Ώ'=>'ώ','Α'=>'α','Β'=>'β','Γ'=>'γ','Δ'=>'δ','Ε'=>'ε','Ζ'=>'ζ','Η'=>'η','Θ'=>'θ','Ι'=>'ι','Κ'=>'κ','Λ'=>'λ','Μ'=>'μ','Ν'=>'ν','Ξ'=>'ξ','Ο'=>'ο','Π'=>'π','Ρ'=>'ρ','Σ'=>'σ','Τ'=>'τ','Υ'=>'υ','Φ'=>'φ','Χ'=>'χ','Ψ'=>'ψ','Ω'=>'ω','Ϊ'=>'ϊ','Ϋ'=>'ϋ','ς'=>'σ','ϐ'=>'β','ϑ'=>'θ','ϕ'=>'φ','ϖ'=>'π','Ϙ'=>'ϙ','Ϛ'=>'ϛ','Ϝ'=>'ϝ','Ϟ'=>'ϟ','Ϡ'=>'ϡ','Ϣ'=>'ϣ','Ϥ'=>'ϥ','Ϧ'=>'ϧ','Ϩ'=>'ϩ','Ϫ'=>'ϫ','Ϭ'=>'ϭ','Ϯ'=>'ϯ','ϰ'=>'κ','ϱ'=>'ρ','ϴ'=>'θ','ϵ'=>'ε','Ϸ'=>'ϸ','Ϲ'=>'ϲ','Ϻ'=>'ϻ','Ͻ'=>'ͻ','Ͼ'=>'ͼ','Ͽ'=>'ͽ','Ѐ'=>'ѐ','Ё'=>'ё','Ђ'=>'ђ','Ѓ'=>'ѓ','Є'=>'є','Ѕ'=>'ѕ','І'=>'і','Ї'=>'ї','Ј'=>'ј','Љ'=>'љ','Њ'=>'њ','Ћ'=>'ћ','Ќ'=>'ќ','Ѝ'=>'ѝ','Ў'=>'ў','Џ'=>'џ','А'=>'а','Б'=>'б','В'=>'в','Г'=>'г','Д'=>'д','Е'=>'е','Ж'=>'ж','З'=>'з','И'=>'и','Й'=>'й','К'=>'к','Л'=>'л','М'=>'м','Н'=>'н','О'=>'о','П'=>'п','Р'=>'р','С'=>'с','Т'=>'т','У'=>'у','Ф'=>'ф','Х'=>'х','Ц'=>'ц','Ч'=>'ч','Ш'=>'ш','Щ'=>'щ','Ъ'=>'ъ','Ы'=>'ы','Ь'=>'ь','Э'=>'э','Ю'=>'ю','Я'=>'я','Ѡ'=>'ѡ','Ѣ'=>'ѣ','Ѥ'=>'ѥ','Ѧ'=>'ѧ','Ѩ'=>'ѩ','Ѫ'=>'ѫ','Ѭ'=>'ѭ','Ѯ'=>'ѯ','Ѱ'=>'ѱ','Ѳ'=>'ѳ','Ѵ'=>'ѵ','Ѷ'=>'ѷ','Ѹ'=>'ѹ','Ѻ'=>'ѻ','Ѽ'=>'ѽ','Ѿ'=>'ѿ','Ҁ'=>'ҁ','Ҋ'=>'ҋ','Ҍ'=>'ҍ','Ҏ'=>'ҏ','Ґ'=>'ґ','Ғ'=>'ғ','Ҕ'=>'ҕ','Җ'=>'җ','Ҙ'=>'ҙ','Қ'=>'қ','Ҝ'=>'ҝ','Ҟ'=>'ҟ','Ҡ'=>'ҡ','Ң'=>'ң','Ҥ'=>'ҥ','Ҧ'=>'ҧ','Ҩ'=>'ҩ','Ҫ'=>'ҫ','Ҭ'=>'ҭ','Ү'=>'ү','Ұ'=>'ұ','Ҳ'=>'ҳ','Ҵ'=>'ҵ','Ҷ'=>'ҷ','Ҹ'=>'ҹ','Һ'=>'һ','Ҽ'=>'ҽ','Ҿ'=>'ҿ','Ӏ'=>'ӏ','Ӂ'=>'ӂ','Ӄ'=>'ӄ','Ӆ'=>'ӆ','Ӈ'=>'ӈ','Ӊ'=>'ӊ','Ӌ'=>'ӌ','Ӎ'=>'ӎ','Ӑ'=>'ӑ','Ӓ'=>'ӓ','Ӕ'=>'ӕ','Ӗ'=>'ӗ','Ә'=>'ә','Ӛ'=>'ӛ','Ӝ'=>'ӝ','Ӟ'=>'ӟ','Ӡ'=>'ӡ','Ӣ'=>'ӣ','Ӥ'=>'ӥ','Ӧ'=>'ӧ','Ө'=>'ө','Ӫ'=>'ӫ','Ӭ'=>'ӭ','Ӯ'=>'ӯ','Ӱ'=>'ӱ','Ӳ'=>'ӳ','Ӵ'=>'ӵ','Ӷ'=>'ӷ','Ӹ'=>'ӹ','Ӻ'=>'ӻ','Ӽ'=>'ӽ','Ӿ'=>'ӿ','Ԁ'=>'ԁ','Ԃ'=>'ԃ','Ԅ'=>'ԅ','Ԇ'=>'ԇ','Ԉ'=>'ԉ','Ԋ'=>'ԋ','Ԍ'=>'ԍ','Ԏ'=>'ԏ','Ԑ'=>'ԑ','Ԓ'=>'ԓ','Ա'=>'ա','Բ'=>'բ','Գ'=>'գ','Դ'=>'դ','Ե'=>'ե','Զ'=>'զ','Է'=>'է','Ը'=>'ը','Թ'=>'թ','Ժ'=>'ժ','Ի'=>'ի','Լ'=>'լ','Խ'=>'խ','Ծ'=>'ծ','Կ'=>'կ','Հ'=>'հ','Ձ'=>'ձ','Ղ'=>'ղ','Ճ'=>'ճ','Մ'=>'մ','Յ'=>'յ','Ն'=>'ն','Շ'=>'շ','Ո'=>'ո','Չ'=>'չ','Պ'=>'պ','Ջ'=>'ջ','Ռ'=>'ռ','Ս'=>'ս','Վ'=>'վ','Տ'=>'տ','Ր'=>'ր','Ց'=>'ց','Ւ'=>'ւ','Փ'=>'փ','Ք'=>'ք','Օ'=>'օ','Ֆ'=>'ֆ','Ⴀ'=>'ⴀ','Ⴁ'=>'ⴁ','Ⴂ'=>'ⴂ','Ⴃ'=>'ⴃ','Ⴄ'=>'ⴄ','Ⴅ'=>'ⴅ','Ⴆ'=>'ⴆ','Ⴇ'=>'ⴇ','Ⴈ'=>'ⴈ','Ⴉ'=>'ⴉ','Ⴊ'=>'ⴊ','Ⴋ'=>'ⴋ','Ⴌ'=>'ⴌ','Ⴍ'=>'ⴍ','Ⴎ'=>'ⴎ','Ⴏ'=>'ⴏ','Ⴐ'=>'ⴐ','Ⴑ'=>'ⴑ','Ⴒ'=>'ⴒ','Ⴓ'=>'ⴓ','Ⴔ'=>'ⴔ','Ⴕ'=>'ⴕ','Ⴖ'=>'ⴖ','Ⴗ'=>'ⴗ','Ⴘ'=>'ⴘ','Ⴙ'=>'ⴙ','Ⴚ'=>'ⴚ','Ⴛ'=>'ⴛ','Ⴜ'=>'ⴜ','Ⴝ'=>'ⴝ','Ⴞ'=>'ⴞ','Ⴟ'=>'ⴟ','Ⴠ'=>'ⴠ','Ⴡ'=>'ⴡ','Ⴢ'=>'ⴢ','Ⴣ'=>'ⴣ','Ⴤ'=>'ⴤ','Ⴥ'=>'ⴥ','Ḁ'=>'ḁ','Ḃ'=>'ḃ','Ḅ'=>'ḅ','Ḇ'=>'ḇ','Ḉ'=>'ḉ','Ḋ'=>'ḋ','Ḍ'=>'ḍ','Ḏ'=>'ḏ','Ḑ'=>'ḑ','Ḓ'=>'ḓ','Ḕ'=>'ḕ','Ḗ'=>'ḗ','Ḙ'=>'ḙ','Ḛ'=>'ḛ','Ḝ'=>'ḝ','Ḟ'=>'ḟ','Ḡ'=>'ḡ','Ḣ'=>'ḣ','Ḥ'=>'ḥ','Ḧ'=>'ḧ','Ḩ'=>'ḩ','Ḫ'=>'ḫ','Ḭ'=>'ḭ','Ḯ'=>'ḯ','Ḱ'=>'ḱ','Ḳ'=>'ḳ','Ḵ'=>'ḵ','Ḷ'=>'ḷ','Ḹ'=>'ḹ','Ḻ'=>'ḻ','Ḽ'=>'ḽ','Ḿ'=>'ḿ','Ṁ'=>'ṁ','Ṃ'=>'ṃ','Ṅ'=>'ṅ','Ṇ'=>'ṇ','Ṉ'=>'ṉ','Ṋ'=>'ṋ','Ṍ'=>'ṍ','Ṏ'=>'ṏ','Ṑ'=>'ṑ','Ṓ'=>'ṓ','Ṕ'=>'ṕ','Ṗ'=>'ṗ','Ṙ'=>'ṙ','Ṛ'=>'ṛ','Ṝ'=>'ṝ','Ṟ'=>'ṟ','Ṡ'=>'ṡ','Ṣ'=>'ṣ','Ṥ'=>'ṥ','Ṧ'=>'ṧ','Ṩ'=>'ṩ','Ṫ'=>'ṫ','Ṭ'=>'ṭ','Ṯ'=>'ṯ','Ṱ'=>'ṱ','Ṳ'=>'ṳ','Ṵ'=>'ṵ','Ṷ'=>'ṷ','Ṹ'=>'ṹ','Ṻ'=>'ṻ','Ṽ'=>'ṽ','Ṿ'=>'ṿ','Ẁ'=>'ẁ','Ẃ'=>'ẃ','Ẅ'=>'ẅ','Ẇ'=>'ẇ','Ẉ'=>'ẉ','Ẋ'=>'ẋ','Ẍ'=>'ẍ','Ẏ'=>'ẏ','Ẑ'=>'ẑ','Ẓ'=>'ẓ','Ẕ'=>'ẕ','ẛ'=>'ṡ','Ạ'=>'ạ','Ả'=>'ả','Ấ'=>'ấ','Ầ'=>'ầ','Ẩ'=>'ẩ','Ẫ'=>'ẫ','Ậ'=>'ậ','Ắ'=>'ắ','Ằ'=>'ằ','Ẳ'=>'ẳ','Ẵ'=>'ẵ','Ặ'=>'ặ','Ẹ'=>'ẹ','Ẻ'=>'ẻ','Ẽ'=>'ẽ','Ế'=>'ế','Ề'=>'ề','Ể'=>'ể','Ễ'=>'ễ','Ệ'=>'ệ','Ỉ'=>'ỉ','Ị'=>'ị','Ọ'=>'ọ','Ỏ'=>'ỏ','Ố'=>'ố','Ồ'=>'ồ','Ổ'=>'ổ','Ỗ'=>'ỗ','Ộ'=>'ộ','Ớ'=>'ớ','Ờ'=>'ờ','Ở'=>'ở','Ỡ'=>'ỡ','Ợ'=>'ợ','Ụ'=>'ụ','Ủ'=>'ủ','Ứ'=>'ứ','Ừ'=>'ừ','Ử'=>'ử','Ữ'=>'ữ','Ự'=>'ự','Ỳ'=>'ỳ','Ỵ'=>'ỵ','Ỷ'=>'ỷ','Ỹ'=>'ỹ','Ἀ'=>'ἀ','Ἁ'=>'ἁ','Ἂ'=>'ἂ','Ἃ'=>'ἃ','Ἄ'=>'ἄ','Ἅ'=>'ἅ','Ἆ'=>'ἆ','Ἇ'=>'ἇ','Ἐ'=>'ἐ','Ἑ'=>'ἑ','Ἒ'=>'ἒ','Ἓ'=>'ἓ','Ἔ'=>'ἔ','Ἕ'=>'ἕ','Ἠ'=>'ἠ','Ἡ'=>'ἡ','Ἢ'=>'ἢ','Ἣ'=>'ἣ','Ἤ'=>'ἤ','Ἥ'=>'ἥ','Ἦ'=>'ἦ','Ἧ'=>'ἧ','Ἰ'=>'ἰ','Ἱ'=>'ἱ','Ἲ'=>'ἲ','Ἳ'=>'ἳ','Ἴ'=>'ἴ','Ἵ'=>'ἵ','Ἶ'=>'ἶ','Ἷ'=>'ἷ','Ὀ'=>'ὀ','Ὁ'=>'ὁ','Ὂ'=>'ὂ','Ὃ'=>'ὃ','Ὄ'=>'ὄ','Ὅ'=>'ὅ','Ὑ'=>'ὑ','Ὓ'=>'ὓ','Ὕ'=>'ὕ','Ὗ'=>'ὗ','Ὠ'=>'ὠ','Ὡ'=>'ὡ','Ὢ'=>'ὢ','Ὣ'=>'ὣ','Ὤ'=>'ὤ','Ὥ'=>'ὥ','Ὦ'=>'ὦ','Ὧ'=>'ὧ','Ᾰ'=>'ᾰ','Ᾱ'=>'ᾱ','Ὰ'=>'ὰ','Ά'=>'ά','ι'=>'ι','Ὲ'=>'ὲ','Έ'=>'έ','Ὴ'=>'ὴ','Ή'=>'ή','Ῐ'=>'ῐ','Ῑ'=>'ῑ','Ὶ'=>'ὶ','Ί'=>'ί','Ῠ'=>'ῠ','Ῡ'=>'ῡ','Ὺ'=>'ὺ','Ύ'=>'ύ','Ῥ'=>'ῥ','Ὸ'=>'ὸ','Ό'=>'ό','Ὼ'=>'ὼ','Ώ'=>'ώ','Ω'=>'ω','K'=>'k','Å'=>'å','Ⅎ'=>'ⅎ','Ⅰ'=>'ⅰ','Ⅱ'=>'ⅱ','Ⅲ'=>'ⅲ','Ⅳ'=>'ⅳ','Ⅴ'=>'ⅴ','Ⅵ'=>'ⅵ','Ⅶ'=>'ⅶ','Ⅷ'=>'ⅷ','Ⅸ'=>'ⅸ','Ⅹ'=>'ⅹ','Ⅺ'=>'ⅺ','Ⅻ'=>'ⅻ','Ⅼ'=>'ⅼ','Ⅽ'=>'ⅽ','Ⅾ'=>'ⅾ','Ⅿ'=>'ⅿ','Ↄ'=>'ↄ','Ⓐ'=>'ⓐ','Ⓑ'=>'ⓑ','Ⓒ'=>'ⓒ','Ⓓ'=>'ⓓ','Ⓔ'=>'ⓔ','Ⓕ'=>'ⓕ','Ⓖ'=>'ⓖ','Ⓗ'=>'ⓗ','Ⓘ'=>'ⓘ','Ⓙ'=>'ⓙ','Ⓚ'=>'ⓚ','Ⓛ'=>'ⓛ','Ⓜ'=>'ⓜ','Ⓝ'=>'ⓝ','Ⓞ'=>'ⓞ','Ⓟ'=>'ⓟ','Ⓠ'=>'ⓠ','Ⓡ'=>'ⓡ','Ⓢ'=>'ⓢ','Ⓣ'=>'ⓣ','Ⓤ'=>'ⓤ','Ⓥ'=>'ⓥ','Ⓦ'=>'ⓦ','Ⓧ'=>'ⓧ','Ⓨ'=>'ⓨ','Ⓩ'=>'ⓩ','Ⰰ'=>'ⰰ','Ⰱ'=>'ⰱ','Ⰲ'=>'ⰲ','Ⰳ'=>'ⰳ','Ⰴ'=>'ⰴ','Ⰵ'=>'ⰵ','Ⰶ'=>'ⰶ','Ⰷ'=>'ⰷ','Ⰸ'=>'ⰸ','Ⰹ'=>'ⰹ','Ⰺ'=>'ⰺ','Ⰻ'=>'ⰻ','Ⰼ'=>'ⰼ','Ⰽ'=>'ⰽ','Ⰾ'=>'ⰾ','Ⰿ'=>'ⰿ','Ⱀ'=>'ⱀ','Ⱁ'=>'ⱁ','Ⱂ'=>'ⱂ','Ⱃ'=>'ⱃ','Ⱄ'=>'ⱄ','Ⱅ'=>'ⱅ','Ⱆ'=>'ⱆ','Ⱇ'=>'ⱇ','Ⱈ'=>'ⱈ','Ⱉ'=>'ⱉ','Ⱊ'=>'ⱊ','Ⱋ'=>'ⱋ','Ⱌ'=>'ⱌ','Ⱍ'=>'ⱍ','Ⱎ'=>'ⱎ','Ⱏ'=>'ⱏ','Ⱐ'=>'ⱐ','Ⱑ'=>'ⱑ','Ⱒ'=>'ⱒ','Ⱓ'=>'ⱓ','Ⱔ'=>'ⱔ','Ⱕ'=>'ⱕ','Ⱖ'=>'ⱖ','Ⱗ'=>'ⱗ','Ⱘ'=>'ⱘ','Ⱙ'=>'ⱙ','Ⱚ'=>'ⱚ','Ⱛ'=>'ⱛ','Ⱜ'=>'ⱜ','Ⱝ'=>'ⱝ','Ⱞ'=>'ⱞ','Ⱡ'=>'ⱡ','Ɫ'=>'ɫ','Ᵽ'=>'ᵽ','Ɽ'=>'ɽ','Ⱨ'=>'ⱨ','Ⱪ'=>'ⱪ','Ⱬ'=>'ⱬ','Ⱶ'=>'ⱶ','Ⲁ'=>'ⲁ','Ⲃ'=>'ⲃ','Ⲅ'=>'ⲅ','Ⲇ'=>'ⲇ','Ⲉ'=>'ⲉ','Ⲋ'=>'ⲋ','Ⲍ'=>'ⲍ','Ⲏ'=>'ⲏ','Ⲑ'=>'ⲑ','Ⲓ'=>'ⲓ','Ⲕ'=>'ⲕ','Ⲗ'=>'ⲗ','Ⲙ'=>'ⲙ','Ⲛ'=>'ⲛ','Ⲝ'=>'ⲝ','Ⲟ'=>'ⲟ','Ⲡ'=>'ⲡ','Ⲣ'=>'ⲣ','Ⲥ'=>'ⲥ','Ⲧ'=>'ⲧ','Ⲩ'=>'ⲩ','Ⲫ'=>'ⲫ','Ⲭ'=>'ⲭ','Ⲯ'=>'ⲯ','Ⲱ'=>'ⲱ','Ⲳ'=>'ⲳ','Ⲵ'=>'ⲵ','Ⲷ'=>'ⲷ','Ⲹ'=>'ⲹ','Ⲻ'=>'ⲻ','Ⲽ'=>'ⲽ','Ⲿ'=>'ⲿ','Ⳁ'=>'ⳁ','Ⳃ'=>'ⳃ','Ⳅ'=>'ⳅ','Ⳇ'=>'ⳇ','Ⳉ'=>'ⳉ','Ⳋ'=>'ⳋ','Ⳍ'=>'ⳍ','Ⳏ'=>'ⳏ','Ⳑ'=>'ⳑ','Ⳓ'=>'ⳓ','Ⳕ'=>'ⳕ','Ⳗ'=>'ⳗ','Ⳙ'=>'ⳙ','Ⳛ'=>'ⳛ','Ⳝ'=>'ⳝ','Ⳟ'=>'ⳟ','Ⳡ'=>'ⳡ','Ⳣ'=>'ⳣ','A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','𐐀'=>'𐐨','𐐁'=>'𐐩','𐐂'=>'𐐪','𐐃'=>'𐐫','𐐄'=>'𐐬','𐐅'=>'𐐭','𐐆'=>'𐐮','𐐇'=>'𐐯','𐐈'=>'𐐰','𐐉'=>'𐐱','𐐊'=>'𐐲','𐐋'=>'𐐳','𐐌'=>'𐐴','𐐍'=>'𐐵','𐐎'=>'𐐶','𐐏'=>'𐐷','𐐐'=>'𐐸','𐐑'=>'𐐹','𐐒'=>'𐐺','𐐓'=>'𐐻','𐐔'=>'𐐼','𐐕'=>'𐐽','𐐖'=>'𐐾','𐐗'=>'𐐿','𐐘'=>'𐑀','𐐙'=>'𐑁','𐐚'=>'𐑂','𐐛'=>'𐑃','𐐜'=>'𐑄','𐐝'=>'𐑅','𐐞'=>'𐑆','𐐟'=>'𐑇','𐐠'=>'𐑈','𐐡'=>'𐑉','𐐢'=>'𐑊','𐐣'=>'𐑋','𐐤'=>'𐑌','𐐥'=>'𐑍','𐐦'=>'𐑎','𐐧'=>'𐑏');
\ No newline at end of file +<?php return array('A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','µ'=>'μ','À'=>'à','Á'=>'á','Â'=>'â','Ã'=>'ã','Ä'=>'ä','Å'=>'å','Æ'=>'æ','Ç'=>'ç','È'=>'è','É'=>'é','Ê'=>'ê','Ë'=>'ë','Ì'=>'ì','Í'=>'í','Î'=>'î','Ï'=>'ï','Ð'=>'ð','Ñ'=>'ñ','Ò'=>'ò','Ó'=>'ó','Ô'=>'ô','Õ'=>'õ','Ö'=>'ö','Ø'=>'ø','Ù'=>'ù','Ú'=>'ú','Û'=>'û','Ü'=>'ü','Ý'=>'ý','Þ'=>'þ','Ā'=>'ā','Ă'=>'ă','Ą'=>'ą','Ć'=>'ć','Ĉ'=>'ĉ','Ċ'=>'ċ','Č'=>'č','Ď'=>'ď','Đ'=>'đ','Ē'=>'ē','Ĕ'=>'ĕ','Ė'=>'ė','Ę'=>'ę','Ě'=>'ě','Ĝ'=>'ĝ','Ğ'=>'ğ','Ġ'=>'ġ','Ģ'=>'ģ','Ĥ'=>'ĥ','Ħ'=>'ħ','Ĩ'=>'ĩ','Ī'=>'ī','Ĭ'=>'ĭ','Į'=>'į','IJ'=>'ij','Ĵ'=>'ĵ','Ķ'=>'ķ','Ĺ'=>'ĺ','Ļ'=>'ļ','Ľ'=>'ľ','Ŀ'=>'ŀ','Ł'=>'ł','Ń'=>'ń','Ņ'=>'ņ','Ň'=>'ň','Ŋ'=>'ŋ','Ō'=>'ō','Ŏ'=>'ŏ','Ő'=>'ő','Œ'=>'œ','Ŕ'=>'ŕ','Ŗ'=>'ŗ','Ř'=>'ř','Ś'=>'ś','Ŝ'=>'ŝ','Ş'=>'ş','Š'=>'š','Ţ'=>'ţ','Ť'=>'ť','Ŧ'=>'ŧ','Ũ'=>'ũ','Ū'=>'ū','Ŭ'=>'ŭ','Ů'=>'ů','Ű'=>'ű','Ų'=>'ų','Ŵ'=>'ŵ','Ŷ'=>'ŷ','Ÿ'=>'ÿ','Ź'=>'ź','Ż'=>'ż','Ž'=>'ž','ſ'=>'s','Ɓ'=>'ɓ','Ƃ'=>'ƃ','Ƅ'=>'ƅ','Ɔ'=>'ɔ','Ƈ'=>'ƈ','Ɖ'=>'ɖ','Ɗ'=>'ɗ','Ƌ'=>'ƌ','Ǝ'=>'ǝ','Ə'=>'ə','Ɛ'=>'ɛ','Ƒ'=>'ƒ','Ɠ'=>'ɠ','Ɣ'=>'ɣ','Ɩ'=>'ɩ','Ɨ'=>'ɨ','Ƙ'=>'ƙ','Ɯ'=>'ɯ','Ɲ'=>'ɲ','Ɵ'=>'ɵ','Ơ'=>'ơ','Ƣ'=>'ƣ','Ƥ'=>'ƥ','Ʀ'=>'ʀ','Ƨ'=>'ƨ','Ʃ'=>'ʃ','Ƭ'=>'ƭ','Ʈ'=>'ʈ','Ư'=>'ư','Ʊ'=>'ʊ','Ʋ'=>'ʋ','Ƴ'=>'ƴ','Ƶ'=>'ƶ','Ʒ'=>'ʒ','Ƹ'=>'ƹ','Ƽ'=>'ƽ','DŽ'=>'dž','Dž'=>'dž','LJ'=>'lj','Lj'=>'lj','NJ'=>'nj','Nj'=>'nj','Ǎ'=>'ǎ','Ǐ'=>'ǐ','Ǒ'=>'ǒ','Ǔ'=>'ǔ','Ǖ'=>'ǖ','Ǘ'=>'ǘ','Ǚ'=>'ǚ','Ǜ'=>'ǜ','Ǟ'=>'ǟ','Ǡ'=>'ǡ','Ǣ'=>'ǣ','Ǥ'=>'ǥ','Ǧ'=>'ǧ','Ǩ'=>'ǩ','Ǫ'=>'ǫ','Ǭ'=>'ǭ','Ǯ'=>'ǯ','DZ'=>'dz','Dz'=>'dz','Ǵ'=>'ǵ','Ƕ'=>'ƕ','Ƿ'=>'ƿ','Ǹ'=>'ǹ','Ǻ'=>'ǻ','Ǽ'=>'ǽ','Ǿ'=>'ǿ','Ȁ'=>'ȁ','Ȃ'=>'ȃ','Ȅ'=>'ȅ','Ȇ'=>'ȇ','Ȉ'=>'ȉ','Ȋ'=>'ȋ','Ȍ'=>'ȍ','Ȏ'=>'ȏ','Ȑ'=>'ȑ','Ȓ'=>'ȓ','Ȕ'=>'ȕ','Ȗ'=>'ȗ','Ș'=>'ș','Ț'=>'ț','Ȝ'=>'ȝ','Ȟ'=>'ȟ','Ƞ'=>'ƞ','Ȣ'=>'ȣ','Ȥ'=>'ȥ','Ȧ'=>'ȧ','Ȩ'=>'ȩ','Ȫ'=>'ȫ','Ȭ'=>'ȭ','Ȯ'=>'ȯ','Ȱ'=>'ȱ','Ȳ'=>'ȳ','Ⱥ'=>'ⱥ','Ȼ'=>'ȼ','Ƚ'=>'ƚ','Ⱦ'=>'ⱦ','Ɂ'=>'ɂ','Ƀ'=>'ƀ','Ʉ'=>'ʉ','Ʌ'=>'ʌ','Ɇ'=>'ɇ','Ɉ'=>'ɉ','Ɋ'=>'ɋ','Ɍ'=>'ɍ','Ɏ'=>'ɏ','ͅ'=>'ι','Ά'=>'ά','Έ'=>'έ','Ή'=>'ή','Ί'=>'ί','Ό'=>'ό','Ύ'=>'ύ','Ώ'=>'ώ','Α'=>'α','Β'=>'β','Γ'=>'γ','Δ'=>'δ','Ε'=>'ε','Ζ'=>'ζ','Η'=>'η','Θ'=>'θ','Ι'=>'ι','Κ'=>'κ','Λ'=>'λ','Μ'=>'μ','Ν'=>'ν','Ξ'=>'ξ','Ο'=>'ο','Π'=>'π','Ρ'=>'ρ','Σ'=>'σ','Τ'=>'τ','Υ'=>'υ','Φ'=>'φ','Χ'=>'χ','Ψ'=>'ψ','Ω'=>'ω','Ϊ'=>'ϊ','Ϋ'=>'ϋ','ς'=>'σ','ϐ'=>'β','ϑ'=>'θ','ϕ'=>'φ','ϖ'=>'π','Ϙ'=>'ϙ','Ϛ'=>'ϛ','Ϝ'=>'ϝ','Ϟ'=>'ϟ','Ϡ'=>'ϡ','Ϣ'=>'ϣ','Ϥ'=>'ϥ','Ϧ'=>'ϧ','Ϩ'=>'ϩ','Ϫ'=>'ϫ','Ϭ'=>'ϭ','Ϯ'=>'ϯ','ϰ'=>'κ','ϱ'=>'ρ','ϴ'=>'θ','ϵ'=>'ε','Ϸ'=>'ϸ','Ϲ'=>'ϲ','Ϻ'=>'ϻ','Ͻ'=>'ͻ','Ͼ'=>'ͼ','Ͽ'=>'ͽ','Ѐ'=>'ѐ','Ё'=>'ё','Ђ'=>'ђ','Ѓ'=>'ѓ','Є'=>'є','Ѕ'=>'ѕ','І'=>'і','Ї'=>'ї','Ј'=>'ј','Љ'=>'љ','Њ'=>'њ','Ћ'=>'ћ','Ќ'=>'ќ','Ѝ'=>'ѝ','Ў'=>'ў','Џ'=>'џ','А'=>'а','Б'=>'б','В'=>'в','Г'=>'г','Д'=>'д','Е'=>'е','Ж'=>'ж','З'=>'з','И'=>'и','Й'=>'й','К'=>'к','Л'=>'л','М'=>'м','Н'=>'н','О'=>'о','П'=>'п','Р'=>'р','С'=>'с','Т'=>'т','У'=>'у','Ф'=>'ф','Х'=>'х','Ц'=>'ц','Ч'=>'ч','Ш'=>'ш','Щ'=>'щ','Ъ'=>'ъ','Ы'=>'ы','Ь'=>'ь','Э'=>'э','Ю'=>'ю','Я'=>'я','Ѡ'=>'ѡ','Ѣ'=>'ѣ','Ѥ'=>'ѥ','Ѧ'=>'ѧ','Ѩ'=>'ѩ','Ѫ'=>'ѫ','Ѭ'=>'ѭ','Ѯ'=>'ѯ','Ѱ'=>'ѱ','Ѳ'=>'ѳ','Ѵ'=>'ѵ','Ѷ'=>'ѷ','Ѹ'=>'ѹ','Ѻ'=>'ѻ','Ѽ'=>'ѽ','Ѿ'=>'ѿ','Ҁ'=>'ҁ','Ҋ'=>'ҋ','Ҍ'=>'ҍ','Ҏ'=>'ҏ','Ґ'=>'ґ','Ғ'=>'ғ','Ҕ'=>'ҕ','Җ'=>'җ','Ҙ'=>'ҙ','Қ'=>'қ','Ҝ'=>'ҝ','Ҟ'=>'ҟ','Ҡ'=>'ҡ','Ң'=>'ң','Ҥ'=>'ҥ','Ҧ'=>'ҧ','Ҩ'=>'ҩ','Ҫ'=>'ҫ','Ҭ'=>'ҭ','Ү'=>'ү','Ұ'=>'ұ','Ҳ'=>'ҳ','Ҵ'=>'ҵ','Ҷ'=>'ҷ','Ҹ'=>'ҹ','Һ'=>'һ','Ҽ'=>'ҽ','Ҿ'=>'ҿ','Ӏ'=>'ӏ','Ӂ'=>'ӂ','Ӄ'=>'ӄ','Ӆ'=>'ӆ','Ӈ'=>'ӈ','Ӊ'=>'ӊ','Ӌ'=>'ӌ','Ӎ'=>'ӎ','Ӑ'=>'ӑ','Ӓ'=>'ӓ','Ӕ'=>'ӕ','Ӗ'=>'ӗ','Ә'=>'ә','Ӛ'=>'ӛ','Ӝ'=>'ӝ','Ӟ'=>'ӟ','Ӡ'=>'ӡ','Ӣ'=>'ӣ','Ӥ'=>'ӥ','Ӧ'=>'ӧ','Ө'=>'ө','Ӫ'=>'ӫ','Ӭ'=>'ӭ','Ӯ'=>'ӯ','Ӱ'=>'ӱ','Ӳ'=>'ӳ','Ӵ'=>'ӵ','Ӷ'=>'ӷ','Ӹ'=>'ӹ','Ӻ'=>'ӻ','Ӽ'=>'ӽ','Ӿ'=>'ӿ','Ԁ'=>'ԁ','Ԃ'=>'ԃ','Ԅ'=>'ԅ','Ԇ'=>'ԇ','Ԉ'=>'ԉ','Ԋ'=>'ԋ','Ԍ'=>'ԍ','Ԏ'=>'ԏ','Ԑ'=>'ԑ','Ԓ'=>'ԓ','Ա'=>'ա','Բ'=>'բ','Գ'=>'գ','Դ'=>'դ','Ե'=>'ե','Զ'=>'զ','Է'=>'է','Ը'=>'ը','Թ'=>'թ','Ժ'=>'ժ','Ի'=>'ի','Լ'=>'լ','Խ'=>'խ','Ծ'=>'ծ','Կ'=>'կ','Հ'=>'հ','Ձ'=>'ձ','Ղ'=>'ղ','Ճ'=>'ճ','Մ'=>'մ','Յ'=>'յ','Ն'=>'ն','Շ'=>'շ','Ո'=>'ո','Չ'=>'չ','Պ'=>'պ','Ջ'=>'ջ','Ռ'=>'ռ','Ս'=>'ս','Վ'=>'վ','Տ'=>'տ','Ր'=>'ր','Ց'=>'ց','Ւ'=>'ւ','Փ'=>'փ','Ք'=>'ք','Օ'=>'օ','Ֆ'=>'ֆ','Ⴀ'=>'ⴀ','Ⴁ'=>'ⴁ','Ⴂ'=>'ⴂ','Ⴃ'=>'ⴃ','Ⴄ'=>'ⴄ','Ⴅ'=>'ⴅ','Ⴆ'=>'ⴆ','Ⴇ'=>'ⴇ','Ⴈ'=>'ⴈ','Ⴉ'=>'ⴉ','Ⴊ'=>'ⴊ','Ⴋ'=>'ⴋ','Ⴌ'=>'ⴌ','Ⴍ'=>'ⴍ','Ⴎ'=>'ⴎ','Ⴏ'=>'ⴏ','Ⴐ'=>'ⴐ','Ⴑ'=>'ⴑ','Ⴒ'=>'ⴒ','Ⴓ'=>'ⴓ','Ⴔ'=>'ⴔ','Ⴕ'=>'ⴕ','Ⴖ'=>'ⴖ','Ⴗ'=>'ⴗ','Ⴘ'=>'ⴘ','Ⴙ'=>'ⴙ','Ⴚ'=>'ⴚ','Ⴛ'=>'ⴛ','Ⴜ'=>'ⴜ','Ⴝ'=>'ⴝ','Ⴞ'=>'ⴞ','Ⴟ'=>'ⴟ','Ⴠ'=>'ⴠ','Ⴡ'=>'ⴡ','Ⴢ'=>'ⴢ','Ⴣ'=>'ⴣ','Ⴤ'=>'ⴤ','Ⴥ'=>'ⴥ','Ḁ'=>'ḁ','Ḃ'=>'ḃ','Ḅ'=>'ḅ','Ḇ'=>'ḇ','Ḉ'=>'ḉ','Ḋ'=>'ḋ','Ḍ'=>'ḍ','Ḏ'=>'ḏ','Ḑ'=>'ḑ','Ḓ'=>'ḓ','Ḕ'=>'ḕ','Ḗ'=>'ḗ','Ḙ'=>'ḙ','Ḛ'=>'ḛ','Ḝ'=>'ḝ','Ḟ'=>'ḟ','Ḡ'=>'ḡ','Ḣ'=>'ḣ','Ḥ'=>'ḥ','Ḧ'=>'ḧ','Ḩ'=>'ḩ','Ḫ'=>'ḫ','Ḭ'=>'ḭ','Ḯ'=>'ḯ','Ḱ'=>'ḱ','Ḳ'=>'ḳ','Ḵ'=>'ḵ','Ḷ'=>'ḷ','Ḹ'=>'ḹ','Ḻ'=>'ḻ','Ḽ'=>'ḽ','Ḿ'=>'ḿ','Ṁ'=>'ṁ','Ṃ'=>'ṃ','Ṅ'=>'ṅ','Ṇ'=>'ṇ','Ṉ'=>'ṉ','Ṋ'=>'ṋ','Ṍ'=>'ṍ','Ṏ'=>'ṏ','Ṑ'=>'ṑ','Ṓ'=>'ṓ','Ṕ'=>'ṕ','Ṗ'=>'ṗ','Ṙ'=>'ṙ','Ṛ'=>'ṛ','Ṝ'=>'ṝ','Ṟ'=>'ṟ','Ṡ'=>'ṡ','Ṣ'=>'ṣ','Ṥ'=>'ṥ','Ṧ'=>'ṧ','Ṩ'=>'ṩ','Ṫ'=>'ṫ','Ṭ'=>'ṭ','Ṯ'=>'ṯ','Ṱ'=>'ṱ','Ṳ'=>'ṳ','Ṵ'=>'ṵ','Ṷ'=>'ṷ','Ṹ'=>'ṹ','Ṻ'=>'ṻ','Ṽ'=>'ṽ','Ṿ'=>'ṿ','Ẁ'=>'ẁ','Ẃ'=>'ẃ','Ẅ'=>'ẅ','Ẇ'=>'ẇ','Ẉ'=>'ẉ','Ẋ'=>'ẋ','Ẍ'=>'ẍ','Ẏ'=>'ẏ','Ẑ'=>'ẑ','Ẓ'=>'ẓ','Ẕ'=>'ẕ','ẛ'=>'ṡ','Ạ'=>'ạ','Ả'=>'ả','Ấ'=>'ấ','Ầ'=>'ầ','Ẩ'=>'ẩ','Ẫ'=>'ẫ','Ậ'=>'ậ','Ắ'=>'ắ','Ằ'=>'ằ','Ẳ'=>'ẳ','Ẵ'=>'ẵ','Ặ'=>'ặ','Ẹ'=>'ẹ','Ẻ'=>'ẻ','Ẽ'=>'ẽ','Ế'=>'ế','Ề'=>'ề','Ể'=>'ể','Ễ'=>'ễ','Ệ'=>'ệ','Ỉ'=>'ỉ','Ị'=>'ị','Ọ'=>'ọ','Ỏ'=>'ỏ','Ố'=>'ố','Ồ'=>'ồ','Ổ'=>'ổ','Ỗ'=>'ỗ','Ộ'=>'ộ','Ớ'=>'ớ','Ờ'=>'ờ','Ở'=>'ở','Ỡ'=>'ỡ','Ợ'=>'ợ','Ụ'=>'ụ','Ủ'=>'ủ','Ứ'=>'ứ','Ừ'=>'ừ','Ử'=>'ử','Ữ'=>'ữ','Ự'=>'ự','Ỳ'=>'ỳ','Ỵ'=>'ỵ','Ỷ'=>'ỷ','Ỹ'=>'ỹ','Ἀ'=>'ἀ','Ἁ'=>'ἁ','Ἂ'=>'ἂ','Ἃ'=>'ἃ','Ἄ'=>'ἄ','Ἅ'=>'ἅ','Ἆ'=>'ἆ','Ἇ'=>'ἇ','Ἐ'=>'ἐ','Ἑ'=>'ἑ','Ἒ'=>'ἒ','Ἓ'=>'ἓ','Ἔ'=>'ἔ','Ἕ'=>'ἕ','Ἠ'=>'ἠ','Ἡ'=>'ἡ','Ἢ'=>'ἢ','Ἣ'=>'ἣ','Ἤ'=>'ἤ','Ἥ'=>'ἥ','Ἦ'=>'ἦ','Ἧ'=>'ἧ','Ἰ'=>'ἰ','Ἱ'=>'ἱ','Ἲ'=>'ἲ','Ἳ'=>'ἳ','Ἴ'=>'ἴ','Ἵ'=>'ἵ','Ἶ'=>'ἶ','Ἷ'=>'ἷ','Ὀ'=>'ὀ','Ὁ'=>'ὁ','Ὂ'=>'ὂ','Ὃ'=>'ὃ','Ὄ'=>'ὄ','Ὅ'=>'ὅ','Ὑ'=>'ὑ','Ὓ'=>'ὓ','Ὕ'=>'ὕ','Ὗ'=>'ὗ','Ὠ'=>'ὠ','Ὡ'=>'ὡ','Ὢ'=>'ὢ','Ὣ'=>'ὣ','Ὤ'=>'ὤ','Ὥ'=>'ὥ','Ὦ'=>'ὦ','Ὧ'=>'ὧ','Ᾰ'=>'ᾰ','Ᾱ'=>'ᾱ','Ὰ'=>'ὰ','Ά'=>'ά','ι'=>'ι','Ὲ'=>'ὲ','Έ'=>'έ','Ὴ'=>'ὴ','Ή'=>'ή','Ῐ'=>'ῐ','Ῑ'=>'ῑ','Ὶ'=>'ὶ','Ί'=>'ί','Ῠ'=>'ῠ','Ῡ'=>'ῡ','Ὺ'=>'ὺ','Ύ'=>'ύ','Ῥ'=>'ῥ','Ὸ'=>'ὸ','Ό'=>'ό','Ὼ'=>'ὼ','Ώ'=>'ώ','Ω'=>'ω','K'=>'k','Å'=>'å','Ⅎ'=>'ⅎ','Ⅰ'=>'ⅰ','Ⅱ'=>'ⅱ','Ⅲ'=>'ⅲ','Ⅳ'=>'ⅳ','Ⅴ'=>'ⅴ','Ⅵ'=>'ⅵ','Ⅶ'=>'ⅶ','Ⅷ'=>'ⅷ','Ⅸ'=>'ⅸ','Ⅹ'=>'ⅹ','Ⅺ'=>'ⅺ','Ⅻ'=>'ⅻ','Ⅼ'=>'ⅼ','Ⅽ'=>'ⅽ','Ⅾ'=>'ⅾ','Ⅿ'=>'ⅿ','Ↄ'=>'ↄ','Ⓐ'=>'ⓐ','Ⓑ'=>'ⓑ','Ⓒ'=>'ⓒ','Ⓓ'=>'ⓓ','Ⓔ'=>'ⓔ','Ⓕ'=>'ⓕ','Ⓖ'=>'ⓖ','Ⓗ'=>'ⓗ','Ⓘ'=>'ⓘ','Ⓙ'=>'ⓙ','Ⓚ'=>'ⓚ','Ⓛ'=>'ⓛ','Ⓜ'=>'ⓜ','Ⓝ'=>'ⓝ','Ⓞ'=>'ⓞ','Ⓟ'=>'ⓟ','Ⓠ'=>'ⓠ','Ⓡ'=>'ⓡ','Ⓢ'=>'ⓢ','Ⓣ'=>'ⓣ','Ⓤ'=>'ⓤ','Ⓥ'=>'ⓥ','Ⓦ'=>'ⓦ','Ⓧ'=>'ⓧ','Ⓨ'=>'ⓨ','Ⓩ'=>'ⓩ','Ⰰ'=>'ⰰ','Ⰱ'=>'ⰱ','Ⰲ'=>'ⰲ','Ⰳ'=>'ⰳ','Ⰴ'=>'ⰴ','Ⰵ'=>'ⰵ','Ⰶ'=>'ⰶ','Ⰷ'=>'ⰷ','Ⰸ'=>'ⰸ','Ⰹ'=>'ⰹ','Ⰺ'=>'ⰺ','Ⰻ'=>'ⰻ','Ⰼ'=>'ⰼ','Ⰽ'=>'ⰽ','Ⰾ'=>'ⰾ','Ⰿ'=>'ⰿ','Ⱀ'=>'ⱀ','Ⱁ'=>'ⱁ','Ⱂ'=>'ⱂ','Ⱃ'=>'ⱃ','Ⱄ'=>'ⱄ','Ⱅ'=>'ⱅ','Ⱆ'=>'ⱆ','Ⱇ'=>'ⱇ','Ⱈ'=>'ⱈ','Ⱉ'=>'ⱉ','Ⱊ'=>'ⱊ','Ⱋ'=>'ⱋ','Ⱌ'=>'ⱌ','Ⱍ'=>'ⱍ','Ⱎ'=>'ⱎ','Ⱏ'=>'ⱏ','Ⱐ'=>'ⱐ','Ⱑ'=>'ⱑ','Ⱒ'=>'ⱒ','Ⱓ'=>'ⱓ','Ⱔ'=>'ⱔ','Ⱕ'=>'ⱕ','Ⱖ'=>'ⱖ','Ⱗ'=>'ⱗ','Ⱘ'=>'ⱘ','Ⱙ'=>'ⱙ','Ⱚ'=>'ⱚ','Ⱛ'=>'ⱛ','Ⱜ'=>'ⱜ','Ⱝ'=>'ⱝ','Ⱞ'=>'ⱞ','Ⱡ'=>'ⱡ','Ɫ'=>'ɫ','Ᵽ'=>'ᵽ','Ɽ'=>'ɽ','Ⱨ'=>'ⱨ','Ⱪ'=>'ⱪ','Ⱬ'=>'ⱬ','Ⱶ'=>'ⱶ','Ⲁ'=>'ⲁ','Ⲃ'=>'ⲃ','Ⲅ'=>'ⲅ','Ⲇ'=>'ⲇ','Ⲉ'=>'ⲉ','Ⲋ'=>'ⲋ','Ⲍ'=>'ⲍ','Ⲏ'=>'ⲏ','Ⲑ'=>'ⲑ','Ⲓ'=>'ⲓ','Ⲕ'=>'ⲕ','Ⲗ'=>'ⲗ','Ⲙ'=>'ⲙ','Ⲛ'=>'ⲛ','Ⲝ'=>'ⲝ','Ⲟ'=>'ⲟ','Ⲡ'=>'ⲡ','Ⲣ'=>'ⲣ','Ⲥ'=>'ⲥ','Ⲧ'=>'ⲧ','Ⲩ'=>'ⲩ','Ⲫ'=>'ⲫ','Ⲭ'=>'ⲭ','Ⲯ'=>'ⲯ','Ⲱ'=>'ⲱ','Ⲳ'=>'ⲳ','Ⲵ'=>'ⲵ','Ⲷ'=>'ⲷ','Ⲹ'=>'ⲹ','Ⲻ'=>'ⲻ','Ⲽ'=>'ⲽ','Ⲿ'=>'ⲿ','Ⳁ'=>'ⳁ','Ⳃ'=>'ⳃ','Ⳅ'=>'ⳅ','Ⳇ'=>'ⳇ','Ⳉ'=>'ⳉ','Ⳋ'=>'ⳋ','Ⳍ'=>'ⳍ','Ⳏ'=>'ⳏ','Ⳑ'=>'ⳑ','Ⳓ'=>'ⳓ','Ⳕ'=>'ⳕ','Ⳗ'=>'ⳗ','Ⳙ'=>'ⳙ','Ⳛ'=>'ⳛ','Ⳝ'=>'ⳝ','Ⳟ'=>'ⳟ','Ⳡ'=>'ⳡ','Ⳣ'=>'ⳣ','A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','𐐀'=>'𐐨','𐐁'=>'𐐩','𐐂'=>'𐐪','𐐃'=>'𐐫','𐐄'=>'𐐬','𐐅'=>'𐐭','𐐆'=>'𐐮','𐐇'=>'𐐯','𐐈'=>'𐐰','𐐉'=>'𐐱','𐐊'=>'𐐲','𐐋'=>'𐐳','𐐌'=>'𐐴','𐐍'=>'𐐵','𐐎'=>'𐐶','𐐏'=>'𐐷','𐐐'=>'𐐸','𐐑'=>'𐐹','𐐒'=>'𐐺','𐐓'=>'𐐻','𐐔'=>'𐐼','𐐕'=>'𐐽','𐐖'=>'𐐾','𐐗'=>'𐐿','𐐘'=>'𐑀','𐐙'=>'𐑁','𐐚'=>'𐑂','𐐛'=>'𐑃','𐐜'=>'𐑄','𐐝'=>'𐑅','𐐞'=>'𐑆','𐐟'=>'𐑇','𐐠'=>'𐑈','𐐡'=>'𐑉','𐐢'=>'𐑊','𐐣'=>'𐑋','𐐤'=>'𐑌','𐐥'=>'𐑍','𐐦'=>'𐑎','𐐧'=>'𐑏'); diff --git a/phpBB/includes/utf/data/case_fold_f.php b/phpBB/includes/utf/data/case_fold_f.php index 7e2ffb25ec..5f2d88ec92 100644 --- a/phpBB/includes/utf/data/case_fold_f.php +++ b/phpBB/includes/utf/data/case_fold_f.php @@ -1 +1 @@ -<?php return array('ß'=>'ss','İ'=>'i̇','ʼn'=>'ʼn','ǰ'=>'ǰ','ΐ'=>'ΐ','ΰ'=>'ΰ','և'=>'եւ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẚ'=>'aʾ','ὐ'=>'ὐ','ὒ'=>'ὒ','ὔ'=>'ὔ','ὖ'=>'ὖ','ᾀ'=>'ἀι','ᾁ'=>'ἁι','ᾂ'=>'ἂι','ᾃ'=>'ἃι','ᾄ'=>'ἄι','ᾅ'=>'ἅι','ᾆ'=>'ἆι','ᾇ'=>'ἇι','ᾈ'=>'ἀι','ᾉ'=>'ἁι','ᾊ'=>'ἂι','ᾋ'=>'ἃι','ᾌ'=>'ἄι','ᾍ'=>'ἅι','ᾎ'=>'ἆι','ᾏ'=>'ἇι','ᾐ'=>'ἠι','ᾑ'=>'ἡι','ᾒ'=>'ἢι','ᾓ'=>'ἣι','ᾔ'=>'ἤι','ᾕ'=>'ἥι','ᾖ'=>'ἦι','ᾗ'=>'ἧι','ᾘ'=>'ἠι','ᾙ'=>'ἡι','ᾚ'=>'ἢι','ᾛ'=>'ἣι','ᾜ'=>'ἤι','ᾝ'=>'ἥι','ᾞ'=>'ἦι','ᾟ'=>'ἧι','ᾠ'=>'ὠι','ᾡ'=>'ὡι','ᾢ'=>'ὢι','ᾣ'=>'ὣι','ᾤ'=>'ὤι','ᾥ'=>'ὥι','ᾦ'=>'ὦι','ᾧ'=>'ὧι','ᾨ'=>'ὠι','ᾩ'=>'ὡι','ᾪ'=>'ὢι','ᾫ'=>'ὣι','ᾬ'=>'ὤι','ᾭ'=>'ὥι','ᾮ'=>'ὦι','ᾯ'=>'ὧι','ᾲ'=>'ὰι','ᾳ'=>'αι','ᾴ'=>'άι','ᾶ'=>'ᾶ','ᾷ'=>'ᾶι','ᾼ'=>'αι','ῂ'=>'ὴι','ῃ'=>'ηι','ῄ'=>'ήι','ῆ'=>'ῆ','ῇ'=>'ῆι','ῌ'=>'ηι','ῒ'=>'ῒ','ΐ'=>'ΐ','ῖ'=>'ῖ','ῗ'=>'ῗ','ῢ'=>'ῢ','ΰ'=>'ΰ','ῤ'=>'ῤ','ῦ'=>'ῦ','ῧ'=>'ῧ','ῲ'=>'ὼι','ῳ'=>'ωι','ῴ'=>'ώι','ῶ'=>'ῶ','ῷ'=>'ῶι','ῼ'=>'ωι','ff'=>'ff','fi'=>'fi','fl'=>'fl','ffi'=>'ffi','ffl'=>'ffl','ſt'=>'st','st'=>'st','ﬓ'=>'մն','ﬔ'=>'մե','ﬕ'=>'մի','ﬖ'=>'վն','ﬗ'=>'մխ');
\ No newline at end of file +<?php return array('ß'=>'ss','İ'=>'i̇','ʼn'=>'ʼn','ǰ'=>'ǰ','ΐ'=>'ΐ','ΰ'=>'ΰ','և'=>'եւ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẚ'=>'aʾ','ὐ'=>'ὐ','ὒ'=>'ὒ','ὔ'=>'ὔ','ὖ'=>'ὖ','ᾀ'=>'ἀι','ᾁ'=>'ἁι','ᾂ'=>'ἂι','ᾃ'=>'ἃι','ᾄ'=>'ἄι','ᾅ'=>'ἅι','ᾆ'=>'ἆι','ᾇ'=>'ἇι','ᾈ'=>'ἀι','ᾉ'=>'ἁι','ᾊ'=>'ἂι','ᾋ'=>'ἃι','ᾌ'=>'ἄι','ᾍ'=>'ἅι','ᾎ'=>'ἆι','ᾏ'=>'ἇι','ᾐ'=>'ἠι','ᾑ'=>'ἡι','ᾒ'=>'ἢι','ᾓ'=>'ἣι','ᾔ'=>'ἤι','ᾕ'=>'ἥι','ᾖ'=>'ἦι','ᾗ'=>'ἧι','ᾘ'=>'ἠι','ᾙ'=>'ἡι','ᾚ'=>'ἢι','ᾛ'=>'ἣι','ᾜ'=>'ἤι','ᾝ'=>'ἥι','ᾞ'=>'ἦι','ᾟ'=>'ἧι','ᾠ'=>'ὠι','ᾡ'=>'ὡι','ᾢ'=>'ὢι','ᾣ'=>'ὣι','ᾤ'=>'ὤι','ᾥ'=>'ὥι','ᾦ'=>'ὦι','ᾧ'=>'ὧι','ᾨ'=>'ὠι','ᾩ'=>'ὡι','ᾪ'=>'ὢι','ᾫ'=>'ὣι','ᾬ'=>'ὤι','ᾭ'=>'ὥι','ᾮ'=>'ὦι','ᾯ'=>'ὧι','ᾲ'=>'ὰι','ᾳ'=>'αι','ᾴ'=>'άι','ᾶ'=>'ᾶ','ᾷ'=>'ᾶι','ᾼ'=>'αι','ῂ'=>'ὴι','ῃ'=>'ηι','ῄ'=>'ήι','ῆ'=>'ῆ','ῇ'=>'ῆι','ῌ'=>'ηι','ῒ'=>'ῒ','ΐ'=>'ΐ','ῖ'=>'ῖ','ῗ'=>'ῗ','ῢ'=>'ῢ','ΰ'=>'ΰ','ῤ'=>'ῤ','ῦ'=>'ῦ','ῧ'=>'ῧ','ῲ'=>'ὼι','ῳ'=>'ωι','ῴ'=>'ώι','ῶ'=>'ῶ','ῷ'=>'ῶι','ῼ'=>'ωι','ff'=>'ff','fi'=>'fi','fl'=>'fl','ffi'=>'ffi','ffl'=>'ffl','ſt'=>'st','st'=>'st','ﬓ'=>'մն','ﬔ'=>'մե','ﬕ'=>'մի','ﬖ'=>'վն','ﬗ'=>'մխ'); diff --git a/phpBB/includes/utf/data/case_fold_s.php b/phpBB/includes/utf/data/case_fold_s.php index 5f09ffa1dd..4ee5d8dc69 100644 --- a/phpBB/includes/utf/data/case_fold_s.php +++ b/phpBB/includes/utf/data/case_fold_s.php @@ -1 +1 @@ -<?php return array('ᾈ'=>'ᾀ','ᾉ'=>'ᾁ','ᾊ'=>'ᾂ','ᾋ'=>'ᾃ','ᾌ'=>'ᾄ','ᾍ'=>'ᾅ','ᾎ'=>'ᾆ','ᾏ'=>'ᾇ','ᾘ'=>'ᾐ','ᾙ'=>'ᾑ','ᾚ'=>'ᾒ','ᾛ'=>'ᾓ','ᾜ'=>'ᾔ','ᾝ'=>'ᾕ','ᾞ'=>'ᾖ','ᾟ'=>'ᾗ','ᾨ'=>'ᾠ','ᾩ'=>'ᾡ','ᾪ'=>'ᾢ','ᾫ'=>'ᾣ','ᾬ'=>'ᾤ','ᾭ'=>'ᾥ','ᾮ'=>'ᾦ','ᾯ'=>'ᾧ','ᾼ'=>'ᾳ','ῌ'=>'ῃ','ῼ'=>'ῳ');
\ No newline at end of file +<?php return array('ᾈ'=>'ᾀ','ᾉ'=>'ᾁ','ᾊ'=>'ᾂ','ᾋ'=>'ᾃ','ᾌ'=>'ᾄ','ᾍ'=>'ᾅ','ᾎ'=>'ᾆ','ᾏ'=>'ᾇ','ᾘ'=>'ᾐ','ᾙ'=>'ᾑ','ᾚ'=>'ᾒ','ᾛ'=>'ᾓ','ᾜ'=>'ᾔ','ᾝ'=>'ᾕ','ᾞ'=>'ᾖ','ᾟ'=>'ᾗ','ᾨ'=>'ᾠ','ᾩ'=>'ᾡ','ᾪ'=>'ᾢ','ᾫ'=>'ᾣ','ᾬ'=>'ᾤ','ᾭ'=>'ᾥ','ᾮ'=>'ᾦ','ᾯ'=>'ᾧ','ᾼ'=>'ᾳ','ῌ'=>'ῃ','ῼ'=>'ῳ'); diff --git a/phpBB/includes/utf/data/confusables.php b/phpBB/includes/utf/data/confusables.php index 7564978a26..767d242948 100644 --- a/phpBB/includes/utf/data/confusables.php +++ b/phpBB/includes/utf/data/confusables.php @@ -1 +1 @@ -<?php return array('¡'=>'i','ǃ'=>'!','α'=>'a',' '=>' ',''=>'',''=>'',''=>'','᠆'=>'',''=>'',''=>'',''=>'',''=>'','
'=>'','
'=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'','۬'=>'۟','̓'=>'̓','ُ'=>'̓','֜'=>'́','́'=>'́','݇'=>'́','॔'=>'́','̀'=>'̀','॓'=>'̀','̌'=>'̆','̑'=>'̂','֯'=>'̊','ஂ'=>'̊','ํ'=>'̊','ໍ'=>'̊','ံ'=>'̊','ំ'=>'̊','៓'=>'̊','゚'=>'̊','゚'=>'̊','ͦ'=>'̊','͂'=>'̃','ׄ'=>'̇','ֹ'=>'̇','ׂ'=>'̇','ׁ'=>'̇','݁'=>'̇','ं'=>'̇','ਂ'=>'̇','ં'=>'̇','்'=>'̇','̅'=>'̄','〬'=>'̉','̱'=>'̠','॒'=>'̠','̧'=>'̡','̦'=>'̡','̨'=>'̢','़'=>'̣','়'=>'̣','਼'=>'̣','઼'=>'̣','଼'=>'̣','͇'=>'̳','̶'=>'̵','ﱞ'=>'ﹲّ','ﱟ'=>'ﹴّ','ﳲ'=>'ﹷّ','ﱠ'=>'ﹶّ','ﳳ'=>'ﹹّ','ﱡ'=>'ﹸّ','ﳴ'=>'ﹻّ','ﱢ'=>'ﹺّ','ﱣ'=>'ﹼٰ','ٴ'=>'ٔ','݂'=>'ܼ','౦'=>'o','೦'=>'o','゙'=>'゙',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ','`'=>'`','`'=>'`','῀'=>'˜','^'=>'^','︿'=>'^','_'=>'_','﹍'=>'_','﹎'=>'_','﹏'=>'_','⌇'=>'︴','-'=>'-','‐'=>'-','‑'=>'-','‒'=>'-','–'=>'-','﹘'=>'-','∼'=>'⁓','・'=>'・','•'=>'・',','=>',','‚'=>',','٬'=>'،','、'=>'、',';'=>';',';'=>';',':'=>':','։'=>':','︰'=>':','׃'=>':','⩴'=>'::=','.'=>'.','․'=>'.','܂'=>'.','‥'=>'..','…'=>'...','。'=>'。','·'=>'·','‧'=>'·','∙'=>'·','⋅'=>'·','ᐧ'=>'·','ᔯ'=>'·4','ᐌ'=>'·ᐁ','ᐎ'=>'·ᐃ','ᐐ'=>'·ᐄ','ᐒ'=>'·ᐅ','ᐔ'=>'·ᐆ','ᐗ'=>'·ᐊ','ᐙ'=>'·ᐋ','ᐷ'=>'·ᐳ','ᑀ'=>'·ᐳ','ᑂ'=>'·ᐴ','ᑄ'=>'·ᐸ','ᑆ'=>'·ᐹ','ᑗ'=>'·ᑌ','ᑙ'=>'·ᑎ','ᑛ'=>'·ᑏ','ᑔ'=>'·ᑐ','ᑝ'=>'·ᑐ','ᑟ'=>'·ᑑ','ᑡ'=>'·ᑕ','ᑣ'=>'·ᑖ','ᑴ'=>'·ᑫ','ᑸ'=>'·ᑮ','ᑼ'=>'·ᑰ','ᑾ'=>'·ᑲ','ᒀ'=>'·ᑳ','ᒒ'=>'·ᒉ','ᒔ'=>'·ᒋ','ᒖ'=>'·ᒌ','ᒚ'=>'·ᒎ','ᒜ'=>'·ᒐ','ᒞ'=>'·ᒑ','ᒬ'=>'·ᒣ','ᒮ'=>'·ᒥ','ᒰ'=>'·ᒦ','ᒲ'=>'·ᒧ','ᒴ'=>'·ᒨ','ᒶ'=>'·L','ᒸ'=>'·ᒫ','ᓉ'=>'·ᓀ','ᓋ'=>'·ᓇ','ᓍ'=>'·ᓈ','ᓜ'=>'·ᓓ','ᓞ'=>'·ᓕ','ᓠ'=>'·ᓖ','ᓢ'=>'·ᓗ','ᓤ'=>'·ᓘ','ᓦ'=>'·ᓚ','ᓨ'=>'·ᓛ','ᓶ'=>'·ᓭ','ᓸ'=>'·ᓯ','ᓺ'=>'·ᓰ','ᓼ'=>'·ᓱ','ᓾ'=>'·ᓲ','ᔀ'=>'·ᓴ','ᔂ'=>'·ᓵ','ᔗ'=>'·ᔐ','ᔙ'=>'·ᔑ','ᔛ'=>'·ᔒ','ᔝ'=>'·ᔓ','ᔟ'=>'·ᔔ','ᔡ'=>'·ᔕ','ᔣ'=>'·ᔖ','ᔱ'=>'·ᔨ','ᔳ'=>'·ᔩ','ᔵ'=>'·ᔪ','ᔷ'=>'·ᔫ','ᔹ'=>'·ᔭ','ᔻ'=>'·ᔮ','ᕎ'=>'·ᕌ','ᕛ'=>'·ᕚ','ᕨ'=>'·ᕧ','('=>'(','⑴'=>'(1)','⒧'=>'(l)','⑽'=>'(10)','⑾'=>'(11)','⑿'=>'(12)','⒀'=>'(13)','⒁'=>'(14)','⒂'=>'(15)','⒃'=>'(16)','⒄'=>'(17)','⒅'=>'(18)','⒆'=>'(19)','⑵'=>'(2)','⒇'=>'(20)','⑶'=>'(3)','⑷'=>'(4)','⑸'=>'(5)','⑹'=>'(6)','⑺'=>'(7)','⑻'=>'(8)','⑼'=>'(9)','⒜'=>'(a)','⒝'=>'(b)','⒞'=>'(c)','⒟'=>'(d)','⒠'=>'(e)','⒡'=>'(f)','⒢'=>'(g)','⒣'=>'(h)','⒤'=>'(i)','⒥'=>'(j)','⒦'=>'(k)','⒨'=>'(m)','⒩'=>'(n)','⒪'=>'(o)','⒫'=>'(p)','⒬'=>'(q)','⒭'=>'(r)','⒮'=>'(s)','⒯'=>'(t)','⒰'=>'(u)','⒱'=>'(v)','⒲'=>'(w)','⒳'=>'(x)','⒴'=>'(y)','⒵'=>'(z)','㈀'=>'(ᄀ)','㈎'=>'(가)','㈁'=>'(ᄂ)','㈏'=>'(나)','㈂'=>'(ᄃ)','㈐'=>'(다)','㈃'=>'(ᄅ)','㈑'=>'(라)','㈄'=>'(ᄆ)','㈒'=>'(마)','㈅'=>'(ᄇ)','㈓'=>'(바)','㈆'=>'(ᄉ)','㈔'=>'(사)','㈇'=>'(ᄋ)','㈕'=>'(아)','㈝'=>'(오전)','㈞'=>'(오후)','㈈'=>'(ᄌ)','㈖'=>'(자)','㈜'=>'(주)','㈉'=>'(ᄎ)','㈗'=>'(차)','㈊'=>'(ᄏ)','㈘'=>'(카)','㈋'=>'(ᄐ)','㈙'=>'(타)','㈌'=>'(ᄑ)','㈚'=>'(파)','㈍'=>'(ᄒ)','㈛'=>'(하)','㈠'=>'(一)','㈦'=>'(七)','㈢'=>'(三)','㈨'=>'(九)','㈡'=>'(二)','㈤'=>'(五)','㈹'=>'(代)','㈽'=>'(企)','㉁'=>'(休)','㈧'=>'(八)','㈥'=>'(六)','㈸'=>'(労)','㈩'=>'(十)','㈿'=>'(協)','㈴'=>'(名)','㈺'=>'(呼)','㈣'=>'(四)','㈯'=>'(土)','㈻'=>'(学)','㈰'=>'(日)','㈪'=>'(月)','㈲'=>'(有)','㈭'=>'(木)','㈱'=>'(株)','㈬'=>'(水)','㈫'=>'(火)','㈵'=>'(特)','㈼'=>'(監)','㈳'=>'(社)','㈷'=>'(祝)','㉀'=>'(祭)','㉂'=>'(自)','㉃'=>'(至)','㈶'=>'(財)','㈾'=>'(資)','㈮'=>'(金)',')'=>')','['=>'[','〔'=>'[',']'=>']','〕'=>']','{'=>'{','}'=>'}','⦅'=>'⦅','⦆'=>'⦆','「'=>'「','」'=>'」','@'=>'@','*'=>'*','/'=>'/','⁄'=>'/','∕'=>'/','\'=>'\\','&'=>'&','#'=>'#','%'=>'%','‶'=>'‵‵','‷'=>'‵‵‵','༌'=>'་','´'=>'ʹ','΄'=>'ʹ','´'=>'ʹ','\''=>'ʹ','''=>'ʹ','′'=>'ʹ','׳'=>'ʹ','ʹ'=>'ʹ','ˊ'=>'ʹ','"'=>'ʹʹ','"'=>'ʹʹ','″'=>'ʹʹ','〃'=>'ʹʹ','״'=>'ʹʹ','ʺ'=>'ʹʹ','‴'=>'ʹʹʹ','⁗'=>'ʹʹʹʹ','¯'=>'ˉ',' ̄'=>'ˉ','‾'=>'ˉ','﹉'=>'ˉ','﹊'=>'ˉ','﹋'=>'ˉ','﹌'=>'ˉ','˚'=>'°','௵'=>'௳','←'=>'←','→'=>'→','↑'=>'↑','↓'=>'↓','↵'=>'↲','⨡'=>'↾','𝛛'=>'∂','𝜕'=>'∂','𝝏'=>'∂','𝞉'=>'∂','𝟃'=>'∂','𝛁'=>'∇','𝛻'=>'∇','𝜵'=>'∇','𝝯'=>'∇','𝞩'=>'∇','+'=>'+','﬩'=>'+','‹'=>'<','<'=>'<','='=>'=','⩵'=>'==','⩶'=>'===','›'=>'>','>'=>'>','¬'=>'¬','¦'=>'¦','〜'=>'~','~'=>'~','﹨'=>'∖','⋀'=>'∧','⋁'=>'∨','⋂'=>'∩','⋃'=>'∪','∯'=>'∮∮','∰'=>'∮∮∮','≣'=>'≡','♁'=>'⊕','☉'=>'⊙','⟂'=>'⊥','▷'=>'⊲','⨝'=>'⋈','⨽'=>'⌙','☸'=>'⎈','⎮'=>'⎥','│'=>'│','▐'=>'▌','■'=>'■','☐'=>'□','○'=>'○','⦾'=>'◎','〛'=>'⟧','〈'=>'⟨','〈'=>'⟨','〉'=>'⟩','〉'=>'⟩','⧙'=>'⦚','〶'=>'〒','ー'=>'ー','¢'=>'¢','$'=>'$','£'=>'£','¥'=>'Y̵','₩'=>'W̵','0'=>'0','𝟎'=>'0','𝟘'=>'0','𝟢'=>'0','𝟬'=>'0','𝟶'=>'0','০'=>'0','୦'=>'0','௦'=>'0','᠐'=>'0','〇'=>'0','𝐎'=>'0','𝑂'=>'0','𝑶'=>'0','𝒪'=>'0','𝓞'=>'0','𝔒'=>'0','𝕆'=>'0','𝕺'=>'0','𝖮'=>'0','𝗢'=>'0','𝘖'=>'0','𝙊'=>'0','𝙾'=>'0','𝚶'=>'0','𝛰'=>'0','𝜪'=>'0','𝝤'=>'0','𝞞'=>'0','ⵔ'=>'0','ഠ'=>'0','⊖'=>'0̵','𝚯'=>'0̵','𝚹'=>'0̵','𝛩'=>'0̵','𝛳'=>'0̵','𝜣'=>'0̵','𝜭'=>'0̵','𝝝'=>'0̵','𝝧'=>'0̵','𝞗'=>'0̵','𝞡'=>'0̵','ⴱ'=>'0̵','Ꮎ'=>'0̵','۰'=>'٠','᭜'=>'᭐','㍘'=>'0点','1'=>'1','𝟏'=>'1','𝟙'=>'1','𝟣'=>'1','𝟭'=>'1','𝟷'=>'1','ℐ'=>'1','ℑ'=>'1','𝐈'=>'1','𝐼'=>'1','𝑰'=>'1','𝓘'=>'1','𝕀'=>'1','𝕴'=>'1','𝖨'=>'1','𝗜'=>'1','𝘐'=>'1','𝙄'=>'1','𝙸'=>'1','l'=>'l','l'=>'l','ⅼ'=>'1','ℓ'=>'l','𝐥'=>'l','𝑙'=>'l','𝒍'=>'l','𝓁'=>'l','𝓵'=>'l','𝔩'=>'l','𝕝'=>'l','𝖑'=>'l','𝗅'=>'l','𝗹'=>'l','𝘭'=>'l','𝙡'=>'l','𝚕'=>'l','𝚰'=>'l','𝛪'=>'l','𝜤'=>'l','𝝞'=>'l','𝞘'=>'l','①'=>'➀','ɭ'=>'l̢','ɫ'=>'l̴','ƚ'=>'l̵','ł'=>'l̷','۱'=>'١','⒈'=>'1.','ŀ'=>'l·','ᒷ'=>'1·','⑩'=>'➉','⒑'=>'10.','㏩'=>'10日','㋉'=>'10月','㍢'=>'10点','⒒'=>'11.','㏪'=>'11日','㋊'=>'11月','㍣'=>'11点','⒓'=>'12.','㏫'=>'12日','㋋'=>'12月','㍤'=>'12点','⒔'=>'13.','㏬'=>'13日','㍥'=>'13点','⒕'=>'14.','㏭'=>'14日','㍦'=>'14点','⒖'=>'15.','㏮'=>'15日','㍧'=>'15点','⒗'=>'16.','㏯'=>'16日','㍨'=>'16点','⒘'=>'17.','㏰'=>'17日','㍩'=>'17点','⒙'=>'18.','㏱'=>'18日','㍪'=>'18点','⒚'=>'19.','㏲'=>'19日','㍫'=>'19点','lj'=>'lj','㏠'=>'1日','㋀'=>'1月','㍙'=>'1点','2'=>'2','𝟐'=>'2','𝟚'=>'2','𝟤'=>'2','𝟮'=>'2','𝟸'=>'2','ᒿ'=>'2','②'=>'➁','۲'=>'٢','⒉'=>'2.','⒛'=>'20.','㏳'=>'20日','㍬'=>'20点','㏴'=>'21日','㍭'=>'21点','㏵'=>'22日','㍮'=>'22点','㏶'=>'23日','㍯'=>'23点','㏷'=>'24日','㍰'=>'24点','㏸'=>'25日','㏹'=>'26日','㏺'=>'27日','㏻'=>'28日','㏼'=>'29日','㏡'=>'2日','㋁'=>'2月','㍚'=>'2点','3'=>'3','𝟑'=>'3','𝟛'=>'3','𝟥'=>'3','𝟯'=>'3','𝟹'=>'3','③'=>'➂','۳'=>'٣','⒊'=>'3.','㏽'=>'30日','㏾'=>'31日','㏢'=>'3日','㋂'=>'3月','㍛'=>'3点','4'=>'4','𝟒'=>'4','𝟜'=>'4','𝟦'=>'4','𝟰'=>'4','𝟺'=>'4','Ꮞ'=>'4','④'=>'➃','⒋'=>'4.','ᔰ'=>'4·','㏣'=>'4日','㋃'=>'4月','㍜'=>'4点','5'=>'5','𝟓'=>'5','𝟝'=>'5','𝟧'=>'5','𝟱'=>'5','𝟻'=>'5','⑤'=>'➄','⒌'=>'5.','㏤'=>'5日','㋄'=>'5月','㍝'=>'5点','6'=>'6','𝟔'=>'6','𝟞'=>'6','𝟨'=>'6','𝟲'=>'6','𝟼'=>'6','б'=>'6','⑥'=>'➅','⒍'=>'6.','㏥'=>'6日','㋅'=>'6月','㍞'=>'6点','7'=>'7','𝟕'=>'7','𝟟'=>'7','𝟩'=>'7','𝟳'=>'7','𝟽'=>'7','⑦'=>'➆','۷'=>'٧','⒎'=>'7.','㏦'=>'7日','㋆'=>'7月','㍟'=>'7点','ଃ'=>'8','৪'=>'8','੪'=>'8','8'=>'8','𝟖'=>'8','𝟠'=>'8','𝟪'=>'8','𝟴'=>'8','𝟾'=>'8','ȣ'=>'8','⑧'=>'➇','۸'=>'٨','⒏'=>'8.','㏧'=>'8日','㋇'=>'8月','㍠'=>'8点','੧'=>'9','୨'=>'9','৭'=>'9','9'=>'9','𝟗'=>'9','𝟡'=>'9','𝟫'=>'9','𝟵'=>'9','𝟿'=>'9','⑨'=>'➈','۹'=>'٩','⒐'=>'9.','㏨'=>'9日','㋈'=>'9月','㍡'=>'9点','a'=>'a','𝐚'=>'a','𝑎'=>'a','𝒂'=>'a','𝒶'=>'a','𝓪'=>'a','𝔞'=>'a','𝕒'=>'a','𝖆'=>'a','𝖺'=>'a','𝗮'=>'a','𝘢'=>'a','𝙖'=>'a','𝚊'=>'a','℀'=>'a/c','℁'=>'a/s','æ'=>'ae','b'=>'b','𝐛'=>'b','𝑏'=>'b','𝒃'=>'b','𝒷'=>'b','𝓫'=>'b','𝔟'=>'b','𝕓'=>'b','𝖇'=>'b','𝖻'=>'b','𝗯'=>'b','𝘣'=>'b','𝙗'=>'b','𝚋'=>'b','ɓ'=>'b̔','ƃ'=>'b̄','ƀ'=>'b̵','c'=>'c','ⅽ'=>'c','𝐜'=>'c','𝑐'=>'c','𝒄'=>'c','𝒸'=>'c','𝓬'=>'c','𝔠'=>'c','𝕔'=>'c','𝖈'=>'c','𝖼'=>'c','𝗰'=>'c','𝘤'=>'c','𝙘'=>'c','𝚌'=>'c','𝛓'=>'c','𝜍'=>'c','𝝇'=>'c','𝞁'=>'c','𝞻'=>'c','℅'=>'c/o','℆'=>'c/u','d'=>'d','ⅾ'=>'d','ⅆ'=>'d','𝐝'=>'d','𝑑'=>'d','𝒅'=>'d','𝒹'=>'d','𝓭'=>'d','𝔡'=>'d','𝕕'=>'d','𝖉'=>'d','𝖽'=>'d','𝗱'=>'d','𝘥'=>'d','𝙙'=>'d','𝚍'=>'d','ɗ'=>'d̔','ƌ'=>'d̄','ɖ'=>'d̢','đ'=>'d̵','dz'=>'dz','dž'=>'dž','e'=>'e','ℯ'=>'e','ⅇ'=>'e','𝐞'=>'e','𝑒'=>'e','𝒆'=>'e','𝓮'=>'e','𝔢'=>'e','𝕖'=>'e','𝖊'=>'e','𝖾'=>'e','𝗲'=>'e','𝘦'=>'e','𝙚'=>'e','𝚎'=>'e','ⴹ'=>'E','ə'=>'ǝ','ɚ'=>'ǝ˞','⋴'=>'ɛ','𝛆'=>'ɛ','𝛜'=>'ɛ','𝜀'=>'ɛ','𝜖'=>'ɛ','𝜺'=>'ɛ','𝝐'=>'ɛ','𝝴'=>'ɛ','𝞊'=>'ɛ','𝞮'=>'ɛ','𝟄'=>'ɛ','f'=>'f','𝐟'=>'f','𝑓'=>'f','𝒇'=>'f','𝒻'=>'f','𝓯'=>'f','𝔣'=>'f','𝕗'=>'f','𝖋'=>'f','𝖿'=>'f','𝗳'=>'f','𝘧'=>'f','𝙛'=>'f','𝚏'=>'f','ƒ'=>'f̡','g'=>'g','ℊ'=>'g','𝐠'=>'g','𝑔'=>'g','𝒈'=>'g','𝓰'=>'g','𝔤'=>'g','𝕘'=>'g','𝖌'=>'g','𝗀'=>'g','𝗴'=>'g','𝘨'=>'g','𝙜'=>'g','𝚐'=>'g','ɡ'=>'g','ɠ'=>'g̔','ǥ'=>'g̵','h'=>'h','ℎ'=>'h','𝐡'=>'h','𝒉'=>'h','𝒽'=>'h','𝓱'=>'h','𝔥'=>'h','𝕙'=>'h','𝖍'=>'h','𝗁'=>'h','𝗵'=>'h','𝘩'=>'h','𝙝'=>'h','𝚑'=>'h','ɦ'=>'h̔','ħ'=>'h̵','ℏ'=>'h̵','῾'=>'ʻ','‘'=>'ʻ','‛'=>'ʻ','ʽ'=>'ʻ','⍳'=>'i','i'=>'i','ⅰ'=>'i','ℹ'=>'i','ⅈ'=>'i','𝐢'=>'i','𝑖'=>'i','𝒊'=>'i','𝒾'=>'i','𝓲'=>'i','𝔦'=>'i','𝕚'=>'i','𝖎'=>'i','𝗂'=>'i','𝗶'=>'i','𝘪'=>'i','𝙞'=>'i','𝚒'=>'i','ı'=>'i','𝚤'=>'i','ɪ'=>'i','ɩ'=>'i','𝛊'=>'i','𝜄'=>'i','𝜾'=>'i','𝝸'=>'i','𝞲'=>'i','ɨ'=>'i̵','ⅱ'=>'ii','ⅲ'=>'iii','ij'=>'ij','ⅳ'=>'iv','ⅸ'=>'ix','j'=>'j','ⅉ'=>'j','𝐣'=>'j','𝑗'=>'j','𝒋'=>'j','𝒿'=>'j','𝓳'=>'j','𝔧'=>'j','𝕛'=>'j','𝖏'=>'j','𝗃'=>'j','𝗷'=>'j','𝘫'=>'j','𝙟'=>'j','𝚓'=>'j','ϳ'=>'j','𝚥'=>'ȷ','k'=>'k','𝐤'=>'k','𝑘'=>'k','𝒌'=>'k','𝓀'=>'k','𝓴'=>'k','𝔨'=>'k','𝕜'=>'k','𝖐'=>'k','𝗄'=>'k','𝗸'=>'k','𝘬'=>'k','𝙠'=>'k','𝚔'=>'k','ƙ'=>'k̔','m'=>'m','ⅿ'=>'m','𝐦'=>'m','𝑚'=>'m','𝒎'=>'m','𝓂'=>'m','𝓶'=>'m','𝔪'=>'m','𝕞'=>'m','𝖒'=>'m','𝗆'=>'m','𝗺'=>'m','𝘮'=>'m','𝙢'=>'m','𝚖'=>'m','ɱ'=>'m̡','n'=>'n','𝐧'=>'n','𝑛'=>'n','𝒏'=>'n','𝓃'=>'n','𝓷'=>'n','𝔫'=>'n','𝕟'=>'n','𝖓'=>'n','𝗇'=>'n','𝗻'=>'n','𝘯'=>'n','𝙣'=>'n','𝚗'=>'n','𝐍'=>'N','𝑁'=>'N','𝑵'=>'N','𝒩'=>'N','𝓝'=>'N','𝔑'=>'N','𝕹'=>'N','𝖭'=>'N','𝗡'=>'N','𝘕'=>'N','𝙉'=>'N','𝙽'=>'N','𝚴'=>'N','𝛮'=>'N','𝜨'=>'N','𝝢'=>'N','𝞜'=>'N','ɲ'=>'ņ','ɳ'=>'n̢','ƞ'=>'n̩','𝛈'=>'n̩','𝜂'=>'n̩','𝜼'=>'n̩','𝝶'=>'n̩','𝞰'=>'n̩','nj'=>'nj','o'=>'o','ℴ'=>'o','𝐨'=>'o','𝑜'=>'o','𝒐'=>'o','𝓸'=>'o','𝔬'=>'o','𝕠'=>'o','𝖔'=>'o','𝗈'=>'o','𝗼'=>'o','𝘰'=>'o','𝙤'=>'o','𝚘'=>'o','ᴏ'=>'o','𝛐'=>'o','𝜊'=>'o','𝝄'=>'o','𝝾'=>'o','𝞸'=>'o','ɵ'=>'o̵','ǿ'=>'ó̵','ø'=>'o̷','œ'=>'oe','ơ'=>'oʼ','⍴'=>'p','p'=>'p','𝐩'=>'p','𝑝'=>'p','𝒑'=>'p','𝓅'=>'p','𝓹'=>'p','𝔭'=>'p','𝕡'=>'p','𝖕'=>'p','𝗉'=>'p','𝗽'=>'p','𝘱'=>'p','𝙥'=>'p','𝚙'=>'p','𝛒'=>'p','𝛠'=>'p','𝜌'=>'p','𝜚'=>'p','𝝆'=>'p','𝝔'=>'p','𝞀'=>'p','𝞎'=>'p','𝞺'=>'p','𝟈'=>'p','ƥ'=>'p̔','q'=>'q','𝐪'=>'q','𝑞'=>'q','𝒒'=>'q','𝓆'=>'q','𝓺'=>'q','𝔮'=>'q','𝕢'=>'q','𝖖'=>'q','𝗊'=>'q','𝗾'=>'q','𝘲'=>'q','𝙦'=>'q','𝚚'=>'q','𝐐'=>'Q','𝑄'=>'Q','𝑸'=>'Q','𝒬'=>'Q','𝓠'=>'Q','𝔔'=>'Q','𝕼'=>'Q','𝖰'=>'Q','𝗤'=>'Q','𝘘'=>'Q','𝙌'=>'Q','𝚀'=>'Q','ʠ'=>'q̔','𝛋'=>'ĸ','𝛞'=>'ĸ','𝜅'=>'ĸ','𝜘'=>'ĸ','𝜿'=>'ĸ','𝝒'=>'ĸ','𝝹'=>'ĸ','𝞌'=>'ĸ','𝞳'=>'ĸ','𝟆'=>'ĸ','r'=>'r','𝐫'=>'r','𝑟'=>'r','𝒓'=>'r','𝓇'=>'r','𝓻'=>'r','𝔯'=>'r','𝕣'=>'r','𝖗'=>'r','𝗋'=>'r','𝗿'=>'r','𝘳'=>'r','𝙧'=>'r','𝚛'=>'r','ɽ'=>'r̢','ɼ'=>'r̩','s'=>'s','𝐬'=>'s','𝑠'=>'s','𝒔'=>'s','𝓈'=>'s','𝓼'=>'s','𝔰'=>'s','𝕤'=>'s','𝖘'=>'s','𝗌'=>'s','𝘀'=>'s','𝘴'=>'s','𝙨'=>'s','𝚜'=>'s','ƽ'=>'s','ʂ'=>'s̢','∫'=>'ʃ','∬'=>'ʃʃ','∭'=>'ʃʃʃ','⨌'=>'ʃʃʃʃ','t'=>'t','𝐭'=>'t','𝑡'=>'t','𝒕'=>'t','𝓉'=>'t','𝓽'=>'t','𝔱'=>'t','𝕥'=>'t','𝖙'=>'t','𝗍'=>'t','𝘁'=>'t','𝘵'=>'t','𝙩'=>'t','𝚝'=>'t','𝑇'=>'T','𝑻'=>'T','𝒯'=>'T','𝓣'=>'T','𝔗'=>'T','𝕋'=>'T','𝕿'=>'T','𝖳'=>'T','𝗧'=>'T','𝘛'=>'T','𝙏'=>'T','𝚃'=>'T','𝚻'=>'T','𝛵'=>'T','𝜯'=>'T','𝝩'=>'T','𝞣'=>'T','ƭ'=>'t̔','ț'=>'ţ','ƫ'=>'ţ','ŧ'=>'t̵','u'=>'u','𝐮'=>'u','𝑢'=>'u','𝒖'=>'u','𝓊'=>'u','𝓾'=>'u','𝔲'=>'u','𝕦'=>'u','𝖚'=>'u','𝗎'=>'u','𝘂'=>'u','𝘶'=>'u','𝙪'=>'u','𝚞'=>'u','ʊ'=>'u','ʋ'=>'u','𝛖'=>'u','𝜐'=>'u','𝝊'=>'u','𝞄'=>'u','𝞾'=>'u','𝑈'=>'U','𝑼'=>'U','𝒰'=>'U','𝓤'=>'U','𝔘'=>'U','𝕌'=>'U','𝖀'=>'U','𝖴'=>'U','𝗨'=>'U','𝘜'=>'U','𝙐'=>'U','𝚄'=>'U','v'=>'v','ⅴ'=>'v','𝐯'=>'v','𝑣'=>'v','𝒗'=>'v','𝓋'=>'v','𝓿'=>'v','𝔳'=>'v','𝕧'=>'v','𝖛'=>'v','𝗏'=>'v','𝘃'=>'v','𝘷'=>'v','𝙫'=>'v','𝚟'=>'v','𝛎'=>'v','𝜈'=>'v','𝝂'=>'v','𝝼'=>'v','𝞶'=>'v','ⅵ'=>'vi','ⅶ'=>'vii','ⅷ'=>'viii','ɯ'=>'w','w'=>'w','𝐰'=>'w','𝑤'=>'w','𝒘'=>'w','𝓌'=>'w','𝔀'=>'w','𝔴'=>'w','𝕨'=>'w','𝖜'=>'w','𝗐'=>'w','𝘄'=>'w','𝘸'=>'w','𝙬'=>'w','𝚠'=>'w','𝑊'=>'W','𝑾'=>'W','𝒲'=>'W','𝓦'=>'W','𝔚'=>'W','𝕎'=>'W','𝖂'=>'W','𝖶'=>'W','𝗪'=>'W','𝘞'=>'W','𝙒'=>'W','𝚆'=>'W','×'=>'x','x'=>'x','ⅹ'=>'x','𝐱'=>'x','𝑥'=>'x','𝒙'=>'x','𝓍'=>'x','𝔁'=>'x','𝔵'=>'x','𝕩'=>'x','𝖝'=>'x','𝗑'=>'x','𝘅'=>'x','𝘹'=>'x','𝙭'=>'x','𝚡'=>'x','᙭'=>'X','𝑋'=>'X','𝑿'=>'X','𝒳'=>'X','𝓧'=>'X','𝔛'=>'X','𝕏'=>'X','𝖃'=>'X','𝖷'=>'X','𝗫'=>'X','𝘟'=>'X','𝙓'=>'X','𝚇'=>'X','𝚾'=>'X','𝛸'=>'X','𝜲'=>'X','𝝬'=>'X','𝞦'=>'X','ⅺ'=>'xi','ⅻ'=>'xii','y'=>'y','𝐲'=>'y','𝑦'=>'y','𝒚'=>'y','𝓎'=>'y','𝔂'=>'y','𝔶'=>'y','𝕪'=>'y','𝖞'=>'y','𝗒'=>'y','𝘆'=>'y','𝘺'=>'y','𝙮'=>'y','𝚢'=>'y','ƴ'=>'y̔','z'=>'z','𝐳'=>'z','𝑧'=>'z','𝒛'=>'z','𝓏'=>'z','𝔃'=>'z','𝔷'=>'z','𝕫'=>'z','𝖟'=>'z','𝗓'=>'z','𝘇'=>'z','𝘻'=>'z','𝙯'=>'z','𝚣'=>'z','ȥ'=>'z̡','ʐ'=>'z̢','ƶ'=>'z̵','ȝ'=>'ʒ','?'=>'ʔ','?'=>'ʔ','⁇'=>'ʔʔ','⁈'=>'ʔǃ','᾽'=>'ʼ','᾿'=>'ʼ','’'=>'ʼ','ʾ'=>'ʼ','!'=>'ǃ','!'=>'ǃ','⁉'=>'ǃʔ','‼'=>'ǃǃ','⍺'=>'α','𝛂'=>'α','𝛼'=>'α','𝜶'=>'α','𝝰'=>'α','𝞪'=>'α','𝛃'=>'β','𝛽'=>'β','𝜷'=>'β','𝝱'=>'β','𝞫'=>'β','ℽ'=>'γ','𝛄'=>'γ','𝛾'=>'γ','𝜸'=>'γ','𝝲'=>'γ','𝞬'=>'γ','𝛅'=>'δ','𝛿'=>'δ','𝜹'=>'δ','𝝳'=>'δ','𝞭'=>'δ','𝟋'=>'ϝ','𝛇'=>'ζ','𝜁'=>'ζ','𝜻'=>'ζ','𝝵'=>'ζ','𝞯'=>'ζ','⍬'=>'θ','𝛉'=>'θ','𝛝'=>'θ','𝜃'=>'θ','𝜗'=>'θ','𝜽'=>'θ','𝝑'=>'θ','𝝷'=>'θ','𝞋'=>'θ','𝞱'=>'θ','𝟅'=>'θ','𝛌'=>'λ','𝜆'=>'λ','𝝀'=>'λ','𝝺'=>'λ','𝞴'=>'λ','𝛬'=>'Λ','𝜦'=>'Λ','𝝠'=>'Λ','𝞚'=>'Λ','𝛍'=>'μ','𝜇'=>'μ','𝝁'=>'μ','𝝻'=>'μ','𝞵'=>'μ','𝛏'=>'ξ','𝜉'=>'ξ','𝝃'=>'ξ','𝝽'=>'ξ','𝞷'=>'ξ','𝛯'=>'Ξ','𝜩'=>'Ξ','𝝣'=>'Ξ','𝞝'=>'Ξ','ℼ'=>'π','𝛑'=>'π','𝛡'=>'π','𝜋'=>'π','𝜛'=>'π','𝝅'=>'π','𝝕'=>'π','𝝿'=>'π','𝞏'=>'π','𝞹'=>'π','𝟉'=>'π','ᴨ'=>'π','∏'=>'Π','𝚷'=>'Π','𝛱'=>'Π','𝜫'=>'Π','𝝥'=>'Π','𝞟'=>'Π','𝛔'=>'σ','𝜎'=>'σ','𝝈'=>'σ','𝞂'=>'σ','𝞼'=>'σ','𝛕'=>'τ','𝜏'=>'τ','𝝉'=>'τ','𝞃'=>'τ','𝞽'=>'τ','𝐘'=>'Y','𝑌'=>'Y','𝒀'=>'Y','𝒴'=>'Y','𝓨'=>'Y','𝔜'=>'Y','𝕐'=>'Y','𝖄'=>'Y','𝖸'=>'Y','𝗬'=>'Y','𝘠'=>'Y','𝙔'=>'Y','𝚈'=>'Y','𝚼'=>'Y','𝛶'=>'Y','𝜰'=>'Y','𝝪'=>'Y','𝞤'=>'Y','𝛗'=>'φ','𝛟'=>'φ','𝜑'=>'φ','𝜙'=>'φ','𝝋'=>'φ','𝝓'=>'φ','𝞅'=>'φ','𝞍'=>'φ','𝞿'=>'φ','𝟇'=>'φ','𝛷'=>'Φ','𝜱'=>'Φ','𝝫'=>'Φ','𝞥'=>'Φ','𝛘'=>'χ','𝜒'=>'χ','𝝌'=>'χ','𝞆'=>'χ','𝟀'=>'χ','𝛙'=>'ψ','𝜓'=>'ψ','𝝍'=>'ψ','𝞇'=>'ψ','𝟁'=>'ψ','𝛹'=>'Ψ','𝜳'=>'Ψ','𝝭'=>'Ψ','𝞧'=>'Ψ','⍵'=>'ω','𝛚'=>'ω','𝜔'=>'ω','𝝎'=>'ω','𝞈'=>'ω','𝟂'=>'ω','ӕ'=>'ae','ғ'=>'r̵','ґ'=>'rᑊ','җ'=>'ж̩','ҙ'=>'з̡','ӏ'=>'i','ҋ'=>'й̡','қ'=>'ĸ̩','ҟ'=>'ĸ̵','ᴫ'=>'л','ӆ'=>'л̡','ӎ'=>'м̡','ӊ'=>'н̡','ӈ'=>'н̡','ң'=>'н̩','ө'=>'o̵','ѳ'=>'o̵','ҫ'=>'c̡','ҭ'=>'т̩','ү'=>'y','ұ'=>'y̵','ћ'=>'h̵','ѽ'=>'ѡ҃','ӌ'=>'ҷ','ҿ'=>'ҽ̢','ҍ'=>'Ь̵','զ'=>'q','ռ'=>'n','ℵ'=>'א','ﬡ'=>'א','אָ'=>'אַ','אּ'=>'אַ','ﭏ'=>'אל','ℶ'=>'ב','ℷ'=>'ג','ℸ'=>'ד','ﬢ'=>'ד','ﬣ'=>'ה','ﬤ'=>'כ','ﬥ'=>'ל','ﬦ'=>'ם','ﬠ'=>'ע','ﬧ'=>'ר','ﬨ'=>'ת','ﺀ'=>'ء','ﺂ'=>'آ','ﺁ'=>'آ','ﺄ'=>'أ','ﺃ'=>'أ','ٵ'=>'أ','ﭑ'=>'ٱ','ﭐ'=>'ٱ','ﺆ'=>'ؤ','ﺅ'=>'ؤ','ٶ'=>'ؤ','ﺈ'=>'إ','ﺇ'=>'إ','ﺋ'=>'ئ','ﺌ'=>'ئ','ﺊ'=>'ئ','ﺉ'=>'ئ','ﯫ'=>'ئا','ﯪ'=>'ئا','ﯸ'=>'ئٻ','ﯷ'=>'ئٻ','ﯶ'=>'ئٻ','ﲗ'=>'ئج','ﰀ'=>'ئج','ﲘ'=>'ئح','ﰁ'=>'ئح','ﲙ'=>'ئخ','ﱤ'=>'ئر','ﱥ'=>'ئز','ﲚ'=>'ئم','ﳟ'=>'ئم','ﱦ'=>'ئم','ﰂ'=>'ئم','ﱧ'=>'ئن','ﲛ'=>'ئه','ﳠ'=>'ئه','ﯭ'=>'ئه','ﯬ'=>'ئه','ﯯ'=>'ئو','ﯮ'=>'ئو','ﯳ'=>'ئۆ','ﯲ'=>'ئۆ','ﯱ'=>'ئۇ','ﯰ'=>'ئۇ','ﯵ'=>'ئۈ','ﯴ'=>'ئۈ','ﯻ'=>'ئى','ﯺ'=>'ئى','ﱨ'=>'ئى','ﯹ'=>'ئى','ﰃ'=>'ئى','ﱩ'=>'ئى','ﰄ'=>'ئى','ﺎ'=>'ا','ﺍ'=>'ا','ﴼ'=>'اً','ﴽ'=>'اً','ﷳ'=>'اكبر','ﷲ'=>'الله','ﺑ'=>'ب','ﺒ'=>'ب','ﺐ'=>'ب','ﺏ'=>'ب','ﲜ'=>'بج','ﰅ'=>'بج','ﲝ'=>'بح','ﰆ'=>'بح','ﷂ'=>'بحى','ﲞ'=>'بخ','ﰇ'=>'بخ','ﶞ'=>'بخى','ﱪ'=>'بر','ﱫ'=>'بز','ﲟ'=>'بم','ﳡ'=>'بم','ﱬ'=>'بم','ﰈ'=>'بم','ﱭ'=>'بن','ﲠ'=>'به','ﳢ'=>'به','ﱮ'=>'بى','ﰉ'=>'بى','ﱯ'=>'بى','ﰊ'=>'بى','ﭔ'=>'ٻ','ﭕ'=>'ٻ','ﭓ'=>'ٻ','ﭒ'=>'ٻ','ې'=>'ٻ','ﯦ'=>'ٻ','ﯧ'=>'ٻ','ﯥ'=>'ٻ','ﯤ'=>'ٻ','ﭘ'=>'پ','ﭙ'=>'پ','ﭗ'=>'پ','ﭖ'=>'پ','ﭜ'=>'ڀ','ﭝ'=>'ڀ','ﭛ'=>'ڀ','ﭚ'=>'ڀ','ﺔ'=>'ة','ﺓ'=>'ة','ﺗ'=>'ت','ﺘ'=>'ت','ﺖ'=>'ت','ﺕ'=>'ت','ﲡ'=>'تج','ﰋ'=>'تج','ﵐ'=>'تجم','ﶠ'=>'تجى','ﶟ'=>'تجى','ﲢ'=>'تح','ﰌ'=>'تح','ﵒ'=>'تحج','ﵑ'=>'تحج','ﵓ'=>'تحم','ﲣ'=>'تخ','ﰍ'=>'تخ','ﵔ'=>'تخم','ﶢ'=>'تخى','ﶡ'=>'تخى','ﱰ'=>'تر','ﱱ'=>'تز','ﲤ'=>'تم','ﳣ'=>'تم','ﱲ'=>'تم','ﰎ'=>'تم','ﵕ'=>'تمج','ﵖ'=>'تمح','ﵗ'=>'تمخ','ﶤ'=>'تمى','ﶣ'=>'تمى','ﱳ'=>'تن','ﲥ'=>'ته','ﳤ'=>'ته','ﱴ'=>'تى','ﰏ'=>'تى','ﱵ'=>'تى','ﰐ'=>'تى','ﺛ'=>'ث','ﺜ'=>'ث','ﺚ'=>'ث','ﺙ'=>'ث','ﰑ'=>'ثج','ﱶ'=>'ثر','ﱷ'=>'ثز','ﲦ'=>'ثم','ﳥ'=>'ثم','ﱸ'=>'ثم','ﰒ'=>'ثم','ﱹ'=>'ثن','ﳦ'=>'ثه','ﱺ'=>'ثى','ﰓ'=>'ثى','ﱻ'=>'ثى','ﰔ'=>'ثى','ﭨ'=>'ٹ','ﭩ'=>'ٹ','ﭧ'=>'ٹ','ﭦ'=>'ٹ','ڻ'=>'ٹ','ﮢ'=>'ٹ','ﮣ'=>'ٹ','ﮡ'=>'ٹ','ﮠ'=>'ٹ','ﭠ'=>'ٺ','ﭡ'=>'ٺ','ﭟ'=>'ٺ','ﭞ'=>'ٺ','ﭤ'=>'ٿ','ﭥ'=>'ٿ','ﭣ'=>'ٿ','ﭢ'=>'ٿ','ﺟ'=>'ج','ﺠ'=>'ج','ﺞ'=>'ج','ﺝ'=>'ج','ﲧ'=>'جح','ﰕ'=>'جح','ﶦ'=>'جحى','ﶾ'=>'جحى','ﷻ'=>'جل جلاله','ﲨ'=>'جم','ﰖ'=>'جم','ﵙ'=>'جمح','ﵘ'=>'جمح','ﶧ'=>'جمى','ﶥ'=>'جمى','ﴝ'=>'جى','ﴁ'=>'جى','ﴞ'=>'جى','ﴂ'=>'جى','ﭸ'=>'ڃ','ﭹ'=>'ڃ','ﭷ'=>'ڃ','ﭶ'=>'ڃ','ﭴ'=>'ڄ','ﭵ'=>'ڄ','ﭳ'=>'ڄ','ﭲ'=>'ڄ','ﭼ'=>'چ','ﭽ'=>'چ','ﭻ'=>'چ','ﭺ'=>'چ','ﮀ'=>'ڇ','ﮁ'=>'ڇ','ﭿ'=>'ڇ','ﭾ'=>'ڇ','ﺣ'=>'ح','ﺤ'=>'ح','ﺢ'=>'ح','ﺡ'=>'ح','ﲩ'=>'حج','ﰗ'=>'حج','ﶿ'=>'حجى','ﲪ'=>'حم','ﰘ'=>'حم','ﵛ'=>'حمى','ﵚ'=>'حمى','ﴛ'=>'حى','ﳿ'=>'حى','ﴜ'=>'حى','ﴀ'=>'حى','ﺧ'=>'خ','ﺨ'=>'خ','ﺦ'=>'خ','ﺥ'=>'خ','ﲫ'=>'خج','ﰙ'=>'خج','ﰚ'=>'خح','ﲬ'=>'خم','ﰛ'=>'خم','ﴟ'=>'خى','ﴃ'=>'خى','ﴠ'=>'خى','ﴄ'=>'خى','ﺪ'=>'د','ﺩ'=>'د','ﺬ'=>'ذ','ﺫ'=>'ذ','ﱛ'=>'ذٰ','ﮉ'=>'ڈ','ﮈ'=>'ڈ','ﮅ'=>'ڌ','ﮄ'=>'ڌ','ﮃ'=>'ڍ','ﮂ'=>'ڍ','ﮇ'=>'ڎ','ﮆ'=>'ڎ','ﺮ'=>'ر','ﺭ'=>'ر','ﱜ'=>'رٰ','ﷶ'=>'رسول','﷼'=>'رىال','ﺰ'=>'ز','ﺯ'=>'ز','ﮍ'=>'ڑ','ﮌ'=>'ڑ','ﮋ'=>'ژ','ﮊ'=>'ژ','ﺳ'=>'س','ﺴ'=>'س','ﺲ'=>'س','ﺱ'=>'س','ﲭ'=>'سج','ﴴ'=>'سج','ﰜ'=>'سج','ﵝ'=>'سجح','ﵞ'=>'سجى','ﲮ'=>'سح','ﴵ'=>'سح','ﰝ'=>'سح','ﵜ'=>'سحج','ﲯ'=>'سخ','ﴶ'=>'سخ','ﰞ'=>'سخ','ﶨ'=>'سخى','ﷆ'=>'سخى','ﴪ'=>'سر','ﴎ'=>'سر','ﲰ'=>'سم','ﳧ'=>'سم','ﰟ'=>'سم','ﵡ'=>'سمج','ﵠ'=>'سمح','ﵟ'=>'سمح','ﵣ'=>'سمم','ﵢ'=>'سمم','ﴱ'=>'سه','ﳨ'=>'سه','ﴗ'=>'سى','ﳻ'=>'سى','ﴘ'=>'سى','ﳼ'=>'سى','ﺷ'=>'ش','ﺸ'=>'ش','ﺶ'=>'ش','ﺵ'=>'ش','ﴭ'=>'شج','ﴷ'=>'شج','ﴥ'=>'شج','ﴉ'=>'شج','ﵩ'=>'شجى','ﴮ'=>'شح','ﴸ'=>'شح','ﴦ'=>'شح','ﴊ'=>'شح','ﵨ'=>'شحم','ﵧ'=>'شحم','ﶪ'=>'شحى','ﴯ'=>'شخ','ﴹ'=>'شخ','ﴧ'=>'شخ','ﴋ'=>'شخ','ﴩ'=>'شر','ﴍ'=>'شر','ﴰ'=>'شم','ﳩ'=>'شم','ﴨ'=>'شم','ﴌ'=>'شم','ﵫ'=>'شمخ','ﵪ'=>'شمخ','ﵭ'=>'شمم','ﵬ'=>'شمم','ﴲ'=>'شه','ﳪ'=>'شه','ﴙ'=>'شى','ﳽ'=>'شى','ﴚ'=>'شى','ﳾ'=>'شى','ﺻ'=>'ص','ﺼ'=>'ص','ﺺ'=>'ص','ﺹ'=>'ص','ﲱ'=>'صح','ﰠ'=>'صح','ﵥ'=>'صحح','ﵤ'=>'صحح','ﶩ'=>'صحى','ﲲ'=>'صخ','ﴫ'=>'صر','ﴏ'=>'صر','ﷵ'=>'صلعم','ﷹ'=>'صلى','ﷺ'=>'صلى الله علىه وسلم','ﷰ'=>'صلے','ﲳ'=>'صم','ﰡ'=>'صم','ﷅ'=>'صمم','ﵦ'=>'صمم','ﴡ'=>'صى','ﴅ'=>'صى','ﴢ'=>'صى','ﴆ'=>'صى','ﺿ'=>'ض','ﻀ'=>'ض','ﺾ'=>'ض','ﺽ'=>'ض','ﲴ'=>'ضج','ﰢ'=>'ضج','ﲵ'=>'ضح','ﰣ'=>'ضح','ﵮ'=>'ضحى','ﶫ'=>'ضحى','ﲶ'=>'ضخ','ﰤ'=>'ضخ','ﵰ'=>'ضخم','ﵯ'=>'ضخم','ﴬ'=>'ضر','ﴐ'=>'ضر','ﲷ'=>'ضم','ﰥ'=>'ضم','ﴣ'=>'ضى','ﴇ'=>'ضى','ﴤ'=>'ضى','ﴈ'=>'ضى','ﻃ'=>'ط','ﻄ'=>'ط','ﻂ'=>'ط','ﻁ'=>'ط','ﲸ'=>'طح','ﰦ'=>'طح','ﴳ'=>'طم','ﴺ'=>'طم','ﰧ'=>'طم','ﵲ'=>'طمح','ﵱ'=>'طمح','ﵳ'=>'طمم','ﵴ'=>'طمى','ﴑ'=>'طى','ﳵ'=>'طى','ﴒ'=>'طى','ﳶ'=>'طى','ﻇ'=>'ظ','ﻈ'=>'ظ','ﻆ'=>'ظ','ﻅ'=>'ظ','ﲹ'=>'ظم','ﴻ'=>'ظم','ﰨ'=>'ظم','ﻋ'=>'ع','ﻌ'=>'ع','ﻊ'=>'ع','ﻉ'=>'ع','ﲺ'=>'عج','ﰩ'=>'عج','ﷄ'=>'عجم','ﵵ'=>'عجم','ﷷ'=>'علىه','ﲻ'=>'عم','ﰪ'=>'عم','ﵷ'=>'عمم','ﵶ'=>'عمم','ﵸ'=>'عمى','ﶶ'=>'عمى','ﴓ'=>'عى','ﳷ'=>'عى','ﴔ'=>'عى','ﳸ'=>'عى','ﻏ'=>'غ','ﻐ'=>'غ','ﻎ'=>'غ','ﻍ'=>'غ','ﲼ'=>'غج','ﰫ'=>'غج','ﲽ'=>'غم','ﰬ'=>'غم','ﵹ'=>'غمم','ﵻ'=>'غمى','ﵺ'=>'غمى','ﴕ'=>'غى','ﳹ'=>'غى','ﴖ'=>'غى','ﳺ'=>'غى','ﻓ'=>'ف','ﻔ'=>'ف','ﻒ'=>'ف','ﻑ'=>'ف','ﲾ'=>'فج','ﰭ'=>'فج','ﲿ'=>'فح','ﰮ'=>'فح','ﳀ'=>'فخ','ﰯ'=>'فخ','ﵽ'=>'فخم','ﵼ'=>'فخم','ﳁ'=>'فم','ﰰ'=>'فم','ﷁ'=>'فمى','ﱼ'=>'فى','ﰱ'=>'فى','ﱽ'=>'فى','ﰲ'=>'فى','ﭬ'=>'ڤ','ﭭ'=>'ڤ','ﭫ'=>'ڤ','ﭪ'=>'ڤ','ﭰ'=>'ڦ','ﭱ'=>'ڦ','ﭯ'=>'ڦ','ﭮ'=>'ڦ','ﻗ'=>'ق','ﻘ'=>'ق','ﻖ'=>'ق','ﻕ'=>'ق','ﳂ'=>'قح','ﰳ'=>'قح','ﷱ'=>'قلے','ﳃ'=>'قم','ﰴ'=>'قم','ﶴ'=>'قمح','ﵾ'=>'قمح','ﵿ'=>'قمم','ﶲ'=>'قمى','ﱾ'=>'قى','ﰵ'=>'قى','ﱿ'=>'قى','ﰶ'=>'قى','ﻛ'=>'ك','ﻜ'=>'ك','ﻚ'=>'ك','ﻙ'=>'ك','ک'=>'ك','ﮐ'=>'ك','ﮑ'=>'ك','ﮏ'=>'ك','ﮎ'=>'ك','ﲀ'=>'كا','ﰷ'=>'كا','ﳄ'=>'كج','ﰸ'=>'كج','ﳅ'=>'كح','ﰹ'=>'كح','ﳆ'=>'كخ','ﰺ'=>'كخ','ﳇ'=>'كل','ﳫ'=>'كل','ﲁ'=>'كل','ﰻ'=>'كل','ﳈ'=>'كم','ﳬ'=>'كم','ﲂ'=>'كم','ﰼ'=>'كم','ﷃ'=>'كمم','ﶻ'=>'كمم','ﶷ'=>'كمى','ﲃ'=>'كى','ﰽ'=>'كى','ﲄ'=>'كى','ﰾ'=>'كى','ﯕ'=>'ڭ','ﯖ'=>'ڭ','ﯔ'=>'ڭ','ﯓ'=>'ڭ','ﮔ'=>'گ','ﮕ'=>'گ','ﮓ'=>'گ','ﮒ'=>'گ','ﮜ'=>'ڱ','ﮝ'=>'ڱ','ﮛ'=>'ڱ','ﮚ'=>'ڱ','ﮘ'=>'ڳ','ﮙ'=>'ڳ','ﮗ'=>'ڳ','ﮖ'=>'ڳ','ﻟ'=>'ل','ﻠ'=>'ل','ﻞ'=>'ل','ﻝ'=>'ل','ﻶ'=>'لآ','ﻵ'=>'لآ','ﻸ'=>'لأ','ﻷ'=>'لأ','ﻺ'=>'لإ','ﻹ'=>'لإ','ﻼ'=>'لا','ﻻ'=>'لا','ﳉ'=>'لج','ﰿ'=>'لج','ﶃ'=>'لجج','ﶄ'=>'لجج','ﶺ'=>'لجم','ﶼ'=>'لجم','ﶬ'=>'لجى','ﳊ'=>'لح','ﱀ'=>'لح','ﶵ'=>'لحم','ﶀ'=>'لحم','ﶂ'=>'لحى','ﶁ'=>'لحى','ﳋ'=>'لخ','ﱁ'=>'لخ','ﶆ'=>'لخم','ﶅ'=>'لخم','ﳌ'=>'لم','ﳭ'=>'لم','ﲅ'=>'لم','ﱂ'=>'لم','ﶈ'=>'لمح','ﶇ'=>'لمح','ﶭ'=>'لمى','ﳍ'=>'له','ﲆ'=>'لى','ﱃ'=>'لى','ﲇ'=>'لى','ﱄ'=>'لى','ﻣ'=>'م','ﻤ'=>'م','ﻢ'=>'م','ﻡ'=>'م','ﲈ'=>'ما','ﳎ'=>'مج','ﱅ'=>'مج','ﶌ'=>'مجح','ﶒ'=>'مجخ','ﶍ'=>'مجم','ﷀ'=>'مجى','ﳏ'=>'مح','ﱆ'=>'مح','ﶉ'=>'محج','ﶊ'=>'محم','ﷴ'=>'محمد','ﶋ'=>'محى','ﳐ'=>'مخ','ﱇ'=>'مخ','ﶎ'=>'مخج','ﶏ'=>'مخم','ﶹ'=>'مخى','ﳑ'=>'مم','ﲉ'=>'مم','ﱈ'=>'مم','ﶱ'=>'ممى','ﱉ'=>'مى','ﱊ'=>'مى','ﻧ'=>'ن','ﻨ'=>'ن','ﻦ'=>'ن','ﻥ'=>'ن','ﳒ'=>'نج','ﱋ'=>'نج','ﶸ'=>'نجح','ﶽ'=>'نجح','ﶘ'=>'نجم','ﶗ'=>'نجم','ﶙ'=>'نجى','ﷇ'=>'نجى','ﳓ'=>'نح','ﱌ'=>'نح','ﶕ'=>'نحم','ﶖ'=>'نحى','ﶳ'=>'نحى','ﳔ'=>'نخ','ﱍ'=>'نخ','ﲊ'=>'نر','ﲋ'=>'نز','ﳕ'=>'نم','ﳮ'=>'نم','ﲌ'=>'نم','ﱎ'=>'نم','ﶛ'=>'نمى','ﶚ'=>'نمى','ﲍ'=>'نن','ﳖ'=>'نه','ﳯ'=>'نه','ﲎ'=>'نى','ﱏ'=>'نى','ﲏ'=>'نى','ﱐ'=>'نى','ﮟ'=>'ں','ﮞ'=>'ں','ﻫ'=>'ه','ﻬ'=>'ه','ﻪ'=>'ه','ﻩ'=>'ه','ھ'=>'ه','ﮬ'=>'ه','ﮭ'=>'ه','ﮫ'=>'ه','ﮪ'=>'ه','ہ'=>'ه','ﮨ'=>'ه','ﮩ'=>'ه','ﮧ'=>'ه','ﮦ'=>'ه','ە'=>'ه','ﳙ'=>'هٰ','ﳗ'=>'هج','ﱑ'=>'هج','ﳘ'=>'هم','ﱒ'=>'هم','ﶓ'=>'همج','ﶔ'=>'همم','ﱓ'=>'هى','ﱔ'=>'هى','ﮥ'=>'ۀ','ﮤ'=>'ۀ','ﻮ'=>'و','ﻭ'=>'و','ﷸ'=>'وسلم','ﯡ'=>'ۅ','ﯠ'=>'ۅ','ﯚ'=>'ۆ','ﯙ'=>'ۆ','ﯘ'=>'ۇ','ﯗ'=>'ۇ','ٷ'=>'ۇٔ','ﯝ'=>'ۇٔ','ﯜ'=>'ۈ','ﯛ'=>'ۈ','ﯣ'=>'ۉ','ﯢ'=>'ۉ','ﯟ'=>'ۋ','ﯞ'=>'ۋ','ﯨ'=>'ى','ﯩ'=>'ى','ﻰ'=>'ى','ﻯ'=>'ى','ي'=>'ى','ﻳ'=>'ى','ﻴ'=>'ى','ﻲ'=>'ى','ﻱ'=>'ى','ی'=>'ى','ﯾ'=>'ى','ﯿ'=>'ى','ﯽ'=>'ى','ﯼ'=>'ى','ٸ'=>'ىٔ','ﲐ'=>'ىٰ','ﱝ'=>'ىٰ','ﳚ'=>'ىج','ﱕ'=>'ىج','ﶯ'=>'ىجى','ﳛ'=>'ىح','ﱖ'=>'ىح','ﶮ'=>'ىحى','ﳜ'=>'ىخ','ﱗ'=>'ىخ','ﲑ'=>'ىر','ﲒ'=>'ىز','ﳝ'=>'ىم','ﳰ'=>'ىم','ﲓ'=>'ىم','ﱘ'=>'ىم','ﶝ'=>'ىمم','ﶜ'=>'ىمم','ﶰ'=>'ىمى','ﲔ'=>'ىن','ﳞ'=>'ىه','ﳱ'=>'ىه','ﲕ'=>'ىى','ﱙ'=>'ىى','ﲖ'=>'ىى','ﱚ'=>'ىى','ۧ'=>'ۦ','ﮯ'=>'ے','ﮮ'=>'ے','ﮱ'=>'ۓ','ﮰ'=>'ۓ','∃'=>'ⴺ','आ'=>'अा','ऒ'=>'अाॆ','ओ'=>'अाे','औ'=>'अाै','ऄ'=>'अॆ','ऑ'=>'अॉ','ऍ'=>'एॅ','ऎ'=>'एॆ','ऐ'=>'एे','ई'=>'र्इ','আ'=>'অা','ৠ'=>'ঋৃ','ৡ'=>'ঌৢ','ਉ'=>'ੳੁ','ਊ'=>'ੳੂ','ਆ'=>'ਅਾ','ਐ'=>'ਅੈ','ਔ'=>'ਅੌ','ਇ'=>'ੲਿ','ਈ'=>'ੲੀ','ਏ'=>'ੲੇ','આ'=>'અા','ઑ'=>'અાૅ','ઓ'=>'અાે','ઔ'=>'અાૈ','ઍ'=>'અૅ','એ'=>'અે','ઐ'=>'અૈ','ଆ'=>'ଅା','௮'=>'அ','ர'=>'ஈ','ா'=>'ஈ','௫'=>'ஈு','௨'=>'உ','ஊ'=>'உள','௭'=>'எ','௷'=>'எவ','ஜ'=>'ஐ','௧'=>'க','௪'=>'ச','௬'=>'சு','௲'=>'சூ','௺'=>'நீ','ை'=>'ன','௴'=>'மீ','௰'=>'ய','ௗ'=>'ள','௸'=>'ஷ','ொ'=>'ெஈ','ௌ'=>'ெள','ோ'=>'ேஈ','ౠ'=>'ఋా','ౡ'=>'ఌా','ఔ'=>'ఒౌ','ఓ'=>'ఒౕ','ఢ'=>'డ̣','భ'=>'బ̣','ష'=>'వ̣','హ'=>'వా','మ'=>'వు','ూ'=>'ుా','ౄ'=>'ృా','ೡ'=>'ಌಾ','ಔ'=>'ఒౌ','ഈ'=>'ഇൗ','ഊ'=>'உൗ','ഐ'=>'എെ','ഓ'=>'ഒാ','ഔ'=>'ഒൗ','ൡ'=>'ഞ','൫'=>'ദ്ര','ഌ'=>'നூ','ങ'=>'നூ','൯'=>'ന്','റ'=>'ര','൪'=>'ര്','൮'=>'വ്','ീ'=>'ி','ൂ'=>'ூ','ൃ'=>'ூ','ൈ'=>'െെ','ฃ'=>'ข','ด'=>'ค','ต'=>'ค','ม'=>'ฆ','ซ'=>'ช','ฏ'=>'ฎ','ท'=>'ฑ','ๅ'=>'า','ำ'=>'̊า','แ'=>'เเ','ໜ'=>'ຫນ','ໝ'=>'ຫມ','ຳ'=>'̊າ','ཷ'=>'ྲཱྀ','ཹ'=>'ླཱྀ','၀'=>'o','ឣ'=>'អ','᧐'=>'ᦞ','᭒'=>'ᬍ','᭓'=>'ᬑ','᭘'=>'ᬨ','ᢖ'=>'ᡜ','ᡕ'=>'ᠵ','Ꮢ'=>'Ꭱ','Ꮍ'=>'y','𝐀'=>'A','𝐴'=>'A','𝑨'=>'A','𝒜'=>'A','𝓐'=>'A','𝔄'=>'A','𝔸'=>'A','𝕬'=>'A','𝖠'=>'A','𝗔'=>'A','𝘈'=>'A','𝘼'=>'A','𝙰'=>'A','𝚨'=>'A','𝛢'=>'A','𝜜'=>'A','𝝖'=>'A','𝞐'=>'A','𝐉'=>'J','𝐽'=>'J','𝑱'=>'J','𝒥'=>'J','𝓙'=>'J','𝔍'=>'J','𝕁'=>'J','𝕵'=>'J','𝖩'=>'J','𝗝'=>'J','𝘑'=>'J','𝙅'=>'J','𝙹'=>'J','Ꮷ'=>'J','⋿'=>'E','ℰ'=>'E','𝐄'=>'E','𝐸'=>'E','𝑬'=>'E','𝓔'=>'E','𝔈'=>'E','𝔼'=>'E','𝕰'=>'E','𝖤'=>'E','𝗘'=>'E','𝘌'=>'E','𝙀'=>'E','𝙴'=>'E','𝚬'=>'E','𝛦'=>'E','𝜠'=>'E','𝝚'=>'E','𝞔'=>'E','ℾ'=>'Ꮁ','𝚪'=>'Ꮁ','𝛤'=>'Ꮁ','𝜞'=>'Ꮁ','𝝘'=>'Ꮁ','𝞒'=>'Ꮁ','Ꮤ'=>'w','ℳ'=>'M','𝐌'=>'M','𝑀'=>'M','𝑴'=>'M','𝓜'=>'M','𝔐'=>'M','𝕄'=>'M','𝕸'=>'M','𝖬'=>'M','𝗠'=>'M','𝘔'=>'M','𝙈'=>'M','𝙼'=>'M','𝚳'=>'M','𝛭'=>'M','𝜧'=>'M','𝝡'=>'M','𝞛'=>'M','ℋ'=>'H','ℌ'=>'H','ℍ'=>'H','𝐇'=>'H','𝐻'=>'H','𝑯'=>'H','𝓗'=>'H','𝕳'=>'H','𝖧'=>'H','𝗛'=>'H','𝘏'=>'H','𝙃'=>'H','𝙷'=>'H','𝚮'=>'H','𝛨'=>'H','𝜢'=>'H','𝝜'=>'H','𝞖'=>'H','𝐆'=>'G','𝐺'=>'G','𝑮'=>'G','𝒢'=>'G','𝓖'=>'G','𝔊'=>'G','𝔾'=>'G','𝕲'=>'G','𝖦'=>'G','𝗚'=>'G','𝘎'=>'G','𝙂'=>'G','𝙶'=>'G','Ᏻ'=>'G','ℤ'=>'Z','ℨ'=>'Z','𝐙'=>'Z','𝑍'=>'Z','𝒁'=>'Z','𝒵'=>'Z','𝓩'=>'Z','𝖅'=>'Z','𝖹'=>'Z','𝗭'=>'Z','𝘡'=>'Z','𝙕'=>'Z','𝚉'=>'Z','𝚭'=>'Z','𝛧'=>'Z','𝜡'=>'Z','𝝛'=>'Z','𝞕'=>'Z','𝐒'=>'S','𝑆'=>'S','𝑺'=>'S','𝒮'=>'S','𝓢'=>'S','𝔖'=>'S','𝕊'=>'S','𝕾'=>'S','𝖲'=>'S','𝗦'=>'S','𝘚'=>'S','𝙎'=>'S','𝚂'=>'S','Ꮪ'=>'S','𝐕'=>'V','𝑉'=>'V','𝑽'=>'V','𝒱'=>'V','𝓥'=>'V','𝔙'=>'V','𝕍'=>'V','𝖁'=>'V','𝖵'=>'V','𝗩'=>'V','𝘝'=>'V','𝙑'=>'V','𝚅'=>'V','ℒ'=>'L','𝐋'=>'L','𝐿'=>'L','𝑳'=>'L','𝓛'=>'L','𝔏'=>'L','𝕃'=>'L','𝕷'=>'L','𝖫'=>'L','𝗟'=>'L','𝘓'=>'L','𝙇'=>'L','𝙻'=>'L','∑'=>'C','⅀'=>'C','ℂ'=>'C','ℭ'=>'C','𝐂'=>'C','𝐶'=>'C','𝑪'=>'C','𝒞'=>'C','𝓒'=>'C','𝕮'=>'C','𝖢'=>'C','𝗖'=>'C','𝘊'=>'C','𝘾'=>'C','𝙲'=>'C','𝚺'=>'C','𝛴'=>'C','𝜮'=>'C','𝝨'=>'C','𝞢'=>'C','ℙ'=>'P','𝐏'=>'P','𝑃'=>'P','𝑷'=>'P','𝒫'=>'P','𝓟'=>'P','𝔓'=>'P','𝕻'=>'P','𝖯'=>'P','𝗣'=>'P','𝘗'=>'P','𝙋'=>'P','𝙿'=>'P','𝚸'=>'P','𝛲'=>'P','𝜬'=>'P','𝝦'=>'P','𝞠'=>'P','𝐊'=>'K','𝐾'=>'K','𝑲'=>'K','𝒦'=>'K','𝓚'=>'K','𝔎'=>'K','𝕂'=>'K','𝕶'=>'K','𝖪'=>'K','𝗞'=>'K','𝘒'=>'K','𝙆'=>'K','𝙺'=>'K','𝚱'=>'K','𝛫'=>'K','𝜥'=>'K','𝝟'=>'K','𝞙'=>'K','ℬ'=>'B','𝐁'=>'B','𝐵'=>'B','𝑩'=>'B','𝓑'=>'B','𝔅'=>'B','𝔹'=>'B','𝕭'=>'B','𝖡'=>'B','𝗕'=>'B','𝘉'=>'B','𝘽'=>'B','𝙱'=>'B','𝚩'=>'B','𝛣'=>'B','𝜝'=>'B','𝝗'=>'B','𝞑'=>'B','ᐍ'=>'ᐁ·','∆'=>'ᐃ','𝚫'=>'ᐃ','𝛥'=>'ᐃ','𝜟'=>'ᐃ','𝝙'=>'ᐃ','𝞓'=>'ᐃ','ᐏ'=>'ᐃ·','ᐑ'=>'ᐄ·','ᐓ'=>'ᐅ·','ᐕ'=>'ᐆ·','ᐘ'=>'ᐊ·','ᐚ'=>'ᐋ·','ᓑ'=>'ᐡ','ᑶ'=>'·P','ᑺ'=>'·d','ᒘ'=>'·J','ᑁ'=>'ᐳ·','ᑃ'=>'ᐴ·','ᑅ'=>'ᐸ·','ᑇ'=>'ᐹ·','ˈ'=>'ᑊ','ᑘ'=>'ᑌ·','ᑧ'=>'ᑌᑊ','ᑚ'=>'ᑎ·','ᑨ'=>'ᑎᑊ','ᑜ'=>'ᑏ·','ᑞ'=>'ᑐ·','ᑩ'=>'ᑐᑊ','ᑠ'=>'ᑑ·','ᑢ'=>'ᑕ·','ᑪ'=>'ᑕᑊ','ᑤ'=>'ᑖ·','ᑵ'=>'ᑫ·','ᒅ'=>'ᑫᑊ','ᑷ'=>'P·','ᒆ'=>'Pᑊ','ᑹ'=>'ᑮ·','ᑻ'=>'d·','ᒇ'=>'dᑊ','ᑽ'=>'ᑰ·','ᑿ'=>'ᑲ·','ᒈ'=>'ᑲᑊ','ᒁ'=>'ᑳ·','ᘃ'=>'ᒉ','ᒓ'=>'ᒉ·','ᒕ'=>'ᒋ·','ᒗ'=>'ᒌ·','ᒙ'=>'J·','ᒛ'=>'ᒎ·','ᘂ'=>'ᒐ','ᒝ'=>'ᒐ·','ᒟ'=>'ᒑ·','ᒭ'=>'ᒣ·','ᒯ'=>'ᒥ·','ᒱ'=>'ᒦ·','ᒳ'=>'ᒧ·','ᒵ'=>'ᒨ·','ᒹ'=>'ᒫ·','ᓊ'=>'ᓀ·','ᓌ'=>'ᓇ·','ᓎ'=>'ᓈᒫ','ᘄ'=>'ᓓ','ᓝ'=>'ᓓ·','ᓟ'=>'ᓕ·','ᓡ'=>'ᓖ·','ᓣ'=>'ᓗ·','ᓥ'=>'ᓘ·','ᘇ'=>'ᓚ','ᓧ'=>'ᓚ·','ᓩ'=>'ᓛ·','ᓷ'=>'ᓭ·','ᓹ'=>'ᓯ·','ᓻ'=>'ᓰ·','ᓽ'=>'ᓱ·','ᓿ'=>'ᓲ·','ᔁ'=>'ᓴ·','ᔃ'=>'ᓵ·','ᔌ'=>'ᔋᐸ','ᔍ'=>'ᔋᑕ','ᔎ'=>'ᔋᑲ','ᔏ'=>'ᔋᒐ','ᔘ'=>'ᔐ·','ᔚ'=>'ᔑ·','ᔜ'=>'ᔒ·','ᔞ'=>'ᔓ·','ᔠ'=>'ᔔ·','ᔢ'=>'ᔕ·','ᔤ'=>'ᔖ·','ᔲ'=>'ᔨ·','ᔴ'=>'ᔩ·','ᔶ'=>'ᔪ·','ᔸ'=>'ᔫ·','ᔺ'=>'ᔭ·','ᔼ'=>'ᔮ·','᙮'=>'x','ᕽ'=>'x','ᘢ'=>'ᕃ','ᘣ'=>'ᕆ','ᘤ'=>'ᕊ','ᕏ'=>'ᕌ·','ᙯ'=>'ᕐᑫ','ᕾ'=>'ᕐᑬ','ᕿ'=>'ᕐP','ᖀ'=>'ᕐᑮ','ᖁ'=>'ᕐd','ᖂ'=>'ᕐᑰ','ᖃ'=>'ᕐᑲ','ᖄ'=>'ᕐᑳ','ᖅ'=>'ᕐᒃ','ᕜ'=>'ᕚ·','ᕩ'=>'ᕧ·','ℛ'=>'R','ℜ'=>'R','ℝ'=>'R','𝐑'=>'R','𝑅'=>'R','𝑹'=>'R','𝓡'=>'R','𝕽'=>'R','𝖱'=>'R','𝗥'=>'R','𝘙'=>'R','𝙍'=>'R','𝚁'=>'R','ᙰ'=>'ᖕᒉ','ᖎ'=>'ᖕᒊ','ᖏ'=>'ᖕᒋ','ᖐ'=>'ᖕᒌ','ᖑ'=>'ᖕJ','ᖒ'=>'ᖕᒎ','ᖓ'=>'ᖕᒐ','ᖔ'=>'ᖕᒑ','ᙱ'=>'ᖖᒋ','ᙲ'=>'ᖖᒌ','ᙳ'=>'ᖖJ','ᙴ'=>'ᖖᒎ','ᙵ'=>'ᖖᒐ','ᙶ'=>'ᖖᒑ','ℱ'=>'F','𝐅'=>'F','𝐹'=>'F','𝑭'=>'F','𝓕'=>'F','𝔉'=>'F','𝔽'=>'F','𝕱'=>'F','𝖥'=>'F','𝗙'=>'F','𝘍'=>'F','𝙁'=>'F','𝙵'=>'F','𝟊'=>'F','ⅅ'=>'D','𝐃'=>'D','𝐷'=>'D','𝑫'=>'D','𝒟'=>'D','𝓓'=>'D','𝔇'=>'D','𝔻'=>'D','𝕯'=>'D','𝖣'=>'D','𝗗'=>'D','𝘋'=>'D','𝘿'=>'D','𝙳'=>'D','ᗪ'=>'D','℧'=>'ᘮ','ᘴ'=>'ᘮ','𝛀'=>'ᘯ','𝛺'=>'ᘯ','𝜴'=>'ᘯ','𝝮'=>'ᘯ','𝞨'=>'ᘯ','ᘵ'=>'ᘯ','ㄱ'=>'ᄀ','ᄀ'=>'ᄀ','ᆨ'=>'ᄀ','ㄲ'=>'ᄁ','ᄁ'=>'ᄁ','ᆩ'=>'ᄁ','ㄴ'=>'ᄂ','ᄂ'=>'ᄂ','ᆫ'=>'ᄂ','ㄷ'=>'ᄃ','ᄃ'=>'ᄃ','ᆮ'=>'ᄃ','ㄸ'=>'ᄄ','ᄄ'=>'ᄄ','ㄹ'=>'ᄅ','ᄅ'=>'ᄅ','ᆯ'=>'ᄅ','ㅁ'=>'ᄆ','ᄆ'=>'ᄆ','ᆷ'=>'ᄆ','ㅂ'=>'ᄇ','ᄇ'=>'ᄇ','ᆸ'=>'ᄇ','ㅃ'=>'ᄈ','ᄈ'=>'ᄈ','ㅅ'=>'ᄉ','ᄉ'=>'ᄉ','ᆺ'=>'ᄉ','ㅆ'=>'ᄊ','ᄊ'=>'ᄊ','ᆻ'=>'ᄊ','ㅇ'=>'ᄋ','ᄋ'=>'ᄋ','ᆼ'=>'ᄋ','ㅈ'=>'ᄌ','ᄌ'=>'ᄌ','ᆽ'=>'ᄌ','ㅉ'=>'ᄍ','ᄍ'=>'ᄍ','ㅊ'=>'ᄎ','ᄎ'=>'ᄎ','ᆾ'=>'ᄎ','ㅋ'=>'ᄏ','ᄏ'=>'ᄏ','ᆿ'=>'ᄏ','ㅌ'=>'ᄐ','ᄐ'=>'ᄐ','ᇀ'=>'ᄐ','ㅍ'=>'ᄑ','ᄑ'=>'ᄑ','ᇁ'=>'ᄑ','ㅎ'=>'ᄒ','ᄒ'=>'ᄒ','ᇂ'=>'ᄒ','ᇅ'=>'ᄓ','ㅥ'=>'ᄔ','ㅦ'=>'ᄕ','ᇆ'=>'ᄕ','ᇊ'=>'ᄗ','ᇍ'=>'ᄘ','ᇐ'=>'ᄙ','ㅀ'=>'ᄚ','ᄚ'=>'ᄚ','ᄻ'=>'ᄚ','ᆶ'=>'ᄚ','ㅮ'=>'ᄜ','ᇜ'=>'ᄜ','ㅱ'=>'ᄝ','ᇢ'=>'ᄝ','ㅲ'=>'ᄞ','ㅳ'=>'ᄠ','ㅄ'=>'ᄡ','ᄡ'=>'ᄡ','ᆹ'=>'ᄡ','ㅴ'=>'ᄢ','ㅵ'=>'ᄣ','ㅶ'=>'ᄧ','ㅷ'=>'ᄩ','ㅸ'=>'ᄫ','ᇦ'=>'ᄫ','ㅹ'=>'ᄬ','ㅺ'=>'ᄭ','ᇧ'=>'ᄭ','ㅻ'=>'ᄮ','ㅼ'=>'ᄯ','ᇨ'=>'ᄯ','ᇩ'=>'ᄰ','ㅽ'=>'ᄲ','ᇪ'=>'ᄲ','ㅾ'=>'ᄶ','ㅿ'=>'ᅀ','ᇫ'=>'ᅀ','ᇬ'=>'ᅁ','ᇱ'=>'ᅅ','ㆂ'=>'ᅅ','ᇲ'=>'ᅆ','ㆃ'=>'ᅆ','ㆀ'=>'ᅇ','ᇮ'=>'ᅇ','ㆁ'=>'ᅌ','ᇰ'=>'ᅌ','ᇳ'=>'ᅖ','ㆄ'=>'ᅗ','ᇴ'=>'ᅗ','ㆅ'=>'ᅘ','ㆆ'=>'ᅙ','ᇹ'=>'ᅙ','ㅤ'=>'ᅠ','ᅠ'=>'ᅠ','ㅏ'=>'ᅡ','ᅡ'=>'ᅡ','ㅐ'=>'ᅢ','ᅢ'=>'ᅢ','ㅑ'=>'ᅣ','ᅣ'=>'ᅣ','ㅒ'=>'ᅤ','ᅤ'=>'ᅤ','ㅓ'=>'ᅥ','ᅥ'=>'ᅥ','ㅔ'=>'ᅦ','ᅦ'=>'ᅦ','ㅕ'=>'ᅧ','ᅧ'=>'ᅧ','ㅖ'=>'ᅨ','ᅨ'=>'ᅨ','ㅗ'=>'ᅩ','ᅩ'=>'ᅩ','ㅘ'=>'ᅪ','ᅪ'=>'ᅪ','ㅙ'=>'ᅫ','ᅫ'=>'ᅫ','ㅚ'=>'ᅬ','ᅬ'=>'ᅬ','ㅛ'=>'ᅭ','ᅭ'=>'ᅭ','ㅜ'=>'ᅮ','ᅮ'=>'ᅮ','ㅝ'=>'ᅯ','ᅯ'=>'ᅯ','ㅞ'=>'ᅰ','ᅰ'=>'ᅰ','ㅟ'=>'ᅱ','ᅱ'=>'ᅱ','ㅠ'=>'ᅲ','ᅲ'=>'ᅲ','ㅡ'=>'一','ᅳ'=>'一','ㅢ'=>'ᅴ','ᅴ'=>'ᅴ','ㅣ'=>'丨','ᅵ'=>'丨','ㆇ'=>'ᆄ','ᆆ'=>'ᆄ','ㆈ'=>'ᆅ','ㆉ'=>'ᆈ','ㆊ'=>'ᆑ','ㆋ'=>'ᆒ','ㆌ'=>'ᆔ','ㆍ'=>'ᆞ','ㆎ'=>'ᆡ','ㄳ'=>'ᆪ','ᆪ'=>'ᆪ','ㄵ'=>'ᆬ','ᆬ'=>'ᆬ','ㄶ'=>'ᆭ','ᆭ'=>'ᆭ','ㄺ'=>'ᆰ','ᆰ'=>'ᆰ','ㄻ'=>'ᆱ','ᆱ'=>'ᆱ','ㄼ'=>'ᆲ','ᆲ'=>'ᆲ','ㄽ'=>'ᆳ','ᆳ'=>'ᆳ','ㄾ'=>'ᆴ','ᆴ'=>'ᆴ','ㄿ'=>'ᆵ','ᆵ'=>'ᆵ','ㅧ'=>'ᇇ','ㅨ'=>'ᇈ','ㅩ'=>'ᇌ','ㅪ'=>'ᇎ','ㅫ'=>'ᇓ','ㅬ'=>'ᇗ','ㅭ'=>'ᇙ','ㅯ'=>'ᇝ','ㅰ'=>'ᇟ','ァ'=>'ァ','ア'=>'ア','ィ'=>'ィ','イ'=>'イ','ゥ'=>'ゥ','ウ'=>'ウ','ェ'=>'ェ','エ'=>'エ','ォ'=>'ォ','オ'=>'オ','カ'=>'カ','キ'=>'キ','ク'=>'ク','ケ'=>'ケ','コ'=>'コ','サ'=>'サ','シ'=>'シ','ス'=>'ス','セ'=>'セ','ソ'=>'ソ','タ'=>'タ','チ'=>'チ','ッ'=>'ッ','ツ'=>'ツ','テ'=>'テ','ト'=>'ト','ナ'=>'ナ','ニ'=>'ニ','ヌ'=>'ヌ','ネ'=>'ネ','ノ'=>'ノ','ハ'=>'ハ','ヒ'=>'ヒ','フ'=>'フ','ヘ'=>'へ','ホ'=>'ホ','マ'=>'マ','⧄'=>'〼','ミ'=>'ミ','ム'=>'ム','メ'=>'メ','モ'=>'モ','ャ'=>'ャ','ヤ'=>'ヤ','ュ'=>'ュ','ユ'=>'ユ','ョ'=>'ョ','ヨ'=>'ヨ','ラ'=>'ラ','リ'=>'リ','ル'=>'ル','レ'=>'レ','ロ'=>'ロ','ワ'=>'ワ','ヲ'=>'ヲ','ン'=>'ン','꒞'=>'ꁊ','꒬'=>'ꁐ','꒜'=>'ꃀ','꒿'=>'ꉙ','꒾'=>'ꊱ','꓀'=>'ꎫ','꓂'=>'ꎵ','꒺'=>'ꎿ','꒰'=>'ꏂ','𐒠'=>'𐒆','—'=>'一','―'=>'一','−'=>'一','─'=>'一','⼀'=>'一','不'=>'不','並'=>'並','|'=>'丨','|'=>'丨','∣'=>'丨','⼁'=>'丨','‖'=>'丨丨','∥'=>'丨丨','串'=>'串','⼂'=>'丶','丸'=>'丸','丹'=>'丹','丽'=>'丽','⼃'=>'丿','乁'=>'乁','⼄'=>'乙','亂'=>'亂','⼅'=>'亅','了'=>'了','⼆'=>'二','⼇'=>'亠','亮'=>'亮','⼈'=>'人','什'=>'什','仌'=>'仌','令'=>'令','你'=>'你','倂'=>'併','倂'=>'併','侀'=>'侀','來'=>'來','例'=>'例','侮'=>'侮','侮'=>'侮','侻'=>'侻','便'=>'便','值'=>'値','倫'=>'倫','偺'=>'偺','備'=>'備','像'=>'像','僚'=>'僚','僧'=>'僧','僧'=>'僧','⼉'=>'儿','兀'=>'兀','充'=>'充','免'=>'免','免'=>'免','兔'=>'兔','兤'=>'兤','⼊'=>'入','內'=>'內','全'=>'全','兩'=>'兩','⼋'=>'八','六'=>'六','具'=>'具','冀'=>'冀','⼌'=>'冂','再'=>'再','冒'=>'冒','冕'=>'冕','⼍'=>'冖','冗'=>'冗','冤'=>'冤','⼎'=>'冫','冬'=>'冬','况'=>'况','况'=>'况','冷'=>'冷','凉'=>'凉','凌'=>'凌','凜'=>'凜','凞'=>'凞','⼏'=>'几','凵'=>'凵','⼐'=>'凵','⼑'=>'刀','刃'=>'刃','切'=>'切','切'=>'切','列'=>'列','利'=>'利','刺'=>'刺','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','劉'=>'劉','力'=>'力','⼒'=>'力','劣'=>'劣','劳'=>'劳','勇'=>'勇','勇'=>'勇','勉'=>'勉','勉'=>'勉','勒'=>'勒','勞'=>'勞','勤'=>'勤','勤'=>'勤','勵'=>'勵','⼓'=>'勹','勺'=>'勺','勺'=>'勺','包'=>'包','匆'=>'匆','⼔'=>'匕','北'=>'北','北'=>'北','⼕'=>'匚','⼖'=>'匸','匿'=>'匿','⼗'=>'十','〸'=>'十','〹'=>'卄','〺'=>'卅','卉'=>'卉','卑'=>'卑','卑'=>'卑','博'=>'博','⼘'=>'卜','⼙'=>'卩','即'=>'即','卵'=>'卵','卽'=>'卽','卿'=>'卿','卿'=>'卿','卿'=>'卿','⼚'=>'厂','⼛'=>'厶','參'=>'參','⼜'=>'又','及'=>'及','叟'=>'叟','⼝'=>'口','句'=>'句','叫'=>'叫','叱'=>'叱','吆'=>'吆','吏'=>'吏','吝'=>'吝','吸'=>'吸','呂'=>'呂','呈'=>'呈','周'=>'周','咞'=>'咞','咢'=>'咢','咽'=>'咽','哶'=>'哶','唐'=>'唐','啓'=>'啓','啟'=>'啓','啕'=>'啕','啣'=>'啣','善'=>'善','善'=>'善','喇'=>'喇','喙'=>'喙','喙'=>'喙','喝'=>'喝','喝'=>'喝','喫'=>'喫','喳'=>'喳','嗀'=>'嗀','嗂'=>'嗂','嗢'=>'嗢','嘆'=>'嘆','嘆'=>'嘆','噑'=>'噑','器'=>'器','噴'=>'噴','⼞'=>'囗','囹'=>'囹','圖'=>'圖','圗'=>'圗','⼟'=>'土','型'=>'型','城'=>'城','埴'=>'埴','堍'=>'堍','報'=>'報','堲'=>'堲','塀'=>'塀','塚'=>'塚','塚'=>'塚','塞'=>'塞','填'=>'塡','墨'=>'墨','壿'=>'墫','墬'=>'墬','墳'=>'墳','壘'=>'壘','壟'=>'壟','⼠'=>'士','壮'=>'壮','売'=>'売','壷'=>'壷','⼡'=>'夂','夆'=>'夆','⼢'=>'夊','⼣'=>'夕','多'=>'多','夢'=>'夢','⼤'=>'大','奄'=>'奄','奈'=>'奈','契'=>'契','奔'=>'奔','奢'=>'奢','女'=>'女','⼥'=>'女','姘'=>'姘','姬'=>'姬','娛'=>'娛','娧'=>'娧','婢'=>'婢','婦'=>'婦','嬀'=>'媯','媵'=>'媵','嬈'=>'嬈','嬨'=>'嬨','嬾'=>'嬾','嬾'=>'嬾','⼦'=>'子','⼧'=>'宀','宅'=>'宅','寃'=>'寃','寘'=>'寘','寧'=>'寧','寧'=>'寧','寧'=>'寧','寮'=>'寮','寳'=>'寳','⼨'=>'寸','寿'=>'寿','将'=>'将','⼩'=>'小','尢'=>'尢','⼪'=>'尢','⼫'=>'尸','尿'=>'尿','屠'=>'屠','屢'=>'屢','層'=>'層','履'=>'履','屮'=>'屮','屮'=>'屮','⼬'=>'屮','⼭'=>'山','岍'=>'岍','峀'=>'峀','崙'=>'崙','嵃'=>'嵃','嵐'=>'嵐','嵫'=>'嵫','嵮'=>'嵮','嵼'=>'嵼','嶲'=>'嶲','嶺'=>'嶺','⼮'=>'巛','巡'=>'巡','巢'=>'巢','⼯'=>'工','⼰'=>'己','巽'=>'巽','⼱'=>'巾','帲'=>'帡','帨'=>'帨','帽'=>'帽','幩'=>'幩','⼲'=>'干','年'=>'年','⼳'=>'幺','⼴'=>'广','度'=>'度','庰'=>'庰','庳'=>'庳','庶'=>'庶','廉'=>'廉','廊'=>'廊','廊'=>'廊','廒'=>'廒','廓'=>'廓','廙'=>'廙','廬'=>'廬','⼵'=>'廴','廾'=>'廾','⼶'=>'廾','弄'=>'弄','⼷'=>'弋','⼸'=>'弓','弢'=>'弢','弢'=>'弢','⼹'=>'彐','当'=>'当','⼺'=>'彡','形'=>'形','彩'=>'彩','彫'=>'彫','⼻'=>'彳','律'=>'律','徚'=>'徚','復'=>'復','徭'=>'徭','⼼'=>'心','忍'=>'忍','志'=>'志','念'=>'念','忹'=>'忹','怒'=>'怒','怜'=>'怜','悁'=>'悁','悔'=>'悔','悔'=>'悔','惇'=>'惇','惘'=>'惘','惡'=>'惡','愈'=>'愈','慄'=>'慄','慈'=>'慈','慌'=>'慌','慌'=>'慌','慎'=>'慎','慎'=>'慎','慠'=>'慠','慨'=>'慨','慺'=>'慺','憎'=>'憎','憎'=>'憎','憎'=>'憎','憐'=>'憐','憤'=>'憤','憯'=>'憯','憲'=>'憲','懞'=>'懞','懲'=>'懲','懲'=>'懲','懲'=>'懲','懶'=>'懶','懶'=>'懶','戀'=>'戀','⼽'=>'戈','成'=>'成','戛'=>'戛','戮'=>'戮','戴'=>'戴','⼾'=>'戶','⼿'=>'手','扝'=>'扝','抱'=>'抱','拉'=>'拉','拏'=>'拏','拓'=>'拓','拔'=>'拔','拼'=>'拼','拾'=>'拾','挽'=>'挽','捐'=>'捐','捨'=>'捨','捻'=>'捻','掃'=>'掃','掠'=>'掠','掩'=>'掩','揄'=>'揄','揅'=>'揅','揤'=>'揤','㩁'=>'搉','搜'=>'搜','搢'=>'搢','摒'=>'摒','摩'=>'摩','摷'=>'摷','摾'=>'摾','撚'=>'撚','撝'=>'撝','擄'=>'擄','⽀'=>'支','⽁'=>'攴','敏'=>'敏','敏'=>'敏','敖'=>'敖','敬'=>'敬','數'=>'數','⽂'=>'文','⽃'=>'斗','料'=>'料','⽄'=>'斤','⽅'=>'方','旅'=>'旅','⽆'=>'无','既'=>'既','旣'=>'旣','⽇'=>'日','易'=>'易','晉'=>'晉','晩'=>'晚','䀿'=>'晣','晴'=>'晴','晴'=>'晴','暈'=>'暈','暑'=>'暑','暑'=>'暑','暜'=>'暜','暴'=>'暴','曆'=>'曆','⽈'=>'曰','更'=>'更','㫚'=>'曶','書'=>'書','最'=>'最','⽉'=>'月','肦'=>'朌','胐'=>'朏','胊'=>'朐','脁'=>'朓','朗'=>'朗','朗'=>'朗','朗'=>'朗','脧'=>'朘','望'=>'望','望'=>'望','朡'=>'朡','膧'=>'朣','⽊'=>'木','李'=>'李','杓'=>'杓','杖'=>'杖','杞'=>'杞','柿'=>'杮','杻'=>'杻','枅'=>'枅','林'=>'林','柳'=>'柳','柺'=>'柺','栗'=>'栗','栟'=>'栟','桒'=>'桒','梁'=>'梁','梅'=>'梅','梅'=>'梅','梎'=>'梎','梨'=>'梨','椔'=>'椔','楂'=>'楂','樧'=>'榝','榣'=>'榣','槪'=>'槪','樂'=>'樂','樂'=>'樂','樂'=>'樂','樓'=>'樓','檨'=>'檨','櫓'=>'櫓','櫛'=>'櫛','欄'=>'欄','⽋'=>'欠','次'=>'次','歔'=>'歔','⽌'=>'止','歲'=>'歲','歷'=>'歷','歹'=>'歹','⽍'=>'歹','殟'=>'殟','殮'=>'殮','⽎'=>'殳','殺'=>'殺','殺'=>'殺','殺'=>'殺','殻'=>'殻','⽏'=>'毋','⺟'=>'母','⽐'=>'比','⽑'=>'毛','⽒'=>'氏','⽓'=>'气','⽔'=>'水','汎'=>'汎','汧'=>'汧','沈'=>'沈','沿'=>'沿','泌'=>'泌','泍'=>'泍','泥'=>'泥','洖'=>'洖','洛'=>'洛','洞'=>'洞','洴'=>'洴','派'=>'派','流'=>'流','流'=>'流','流'=>'流','浩'=>'浩','浪'=>'浪','海'=>'海','海'=>'海','浸'=>'浸','涅'=>'涅','淋'=>'淋','淚'=>'淚','淪'=>'淪','淹'=>'淹','渚'=>'渚','港'=>'港','湮'=>'湮','潙'=>'溈','溜'=>'溜','溺'=>'溺','滇'=>'滇','滋'=>'滋','滋'=>'滋','滑'=>'滑','滛'=>'滛','漏'=>'漏','漢'=>'漢','漢'=>'漢','漣'=>'漣','潮'=>'潮','濆'=>'濆','濫'=>'濫','濾'=>'濾','瀛'=>'瀛','瀞'=>'瀞','瀞'=>'瀞','瀹'=>'瀹','灊'=>'灊','⽕'=>'火','灰'=>'灰','灷'=>'灷','災'=>'災','炙'=>'炙','炭'=>'炭','烈'=>'烈','烙'=>'烙','煅'=>'煅','煉'=>'煉','煮'=>'煮','煮'=>'煮','熜'=>'熜','燎'=>'燎','燐'=>'燐','爐'=>'爐','爛'=>'爛','爨'=>'爨','⽖'=>'爪','爫'=>'爫','⺤'=>'爫','爵'=>'爵','爵'=>'爵','⽗'=>'父','⽘'=>'爻','⽙'=>'爿','⽚'=>'片','牐'=>'牐','⽛'=>'牙','⽜'=>'牛','牢'=>'牢','犀'=>'犀','犕'=>'犕','⽝'=>'犬','犯'=>'犯','狀'=>'狀','狼'=>'狼','猪'=>'猪','猪'=>'猪','獵'=>'獵','獺'=>'獺','⽞'=>'玄','率'=>'率','率'=>'率','⽟'=>'玉','王'=>'王','玥'=>'玥','玲'=>'玲','珞'=>'珞','理'=>'理','琉'=>'琉','琢'=>'琢','瑇'=>'瑇','瑜'=>'瑜','瑩'=>'瑩','瑱'=>'瑱','瑱'=>'瑱','璅'=>'璅','璉'=>'璉','璘'=>'璘','瓊'=>'瓊','⽠'=>'瓜','⽡'=>'瓦','甆'=>'甆','⽢'=>'甘','⽣'=>'生','甤'=>'甤','⽤'=>'用','⽥'=>'田','画'=>'画','甾'=>'甾','留'=>'留','略'=>'略','異'=>'異','異'=>'異','⽦'=>'疋','⽧'=>'疒','痢'=>'痢','瘐'=>'瘐','瘝'=>'瘝','瘟'=>'瘟','療'=>'療','癩'=>'癩','⽨'=>'癶','⽩'=>'白','⽪'=>'皮','⽫'=>'皿','益'=>'益','益'=>'益','盛'=>'盛','盧'=>'盧','⽬'=>'目','直'=>'直','直'=>'直','省'=>'省','眞'=>'眞','真'=>'真','真'=>'真','着'=>'着','睊'=>'睊','睊'=>'睊','瞋'=>'瞋','瞧'=>'瞧','⽭'=>'矛','⽮'=>'矢','⽯'=>'石','硏'=>'研','硎'=>'硎','硫'=>'硫','碌'=>'碌','碌'=>'碌','碑'=>'碑','磊'=>'磊','磌'=>'磌','磌'=>'磌','磻'=>'磻','礪'=>'礪','⽰'=>'示','礼'=>'礼','社'=>'社','祈'=>'祈','祉'=>'祉','祐'=>'祐','祖'=>'祖','祖'=>'祖','祝'=>'祝','神'=>'神','祥'=>'祥','祿'=>'祿','禍'=>'禍','禎'=>'禎','福'=>'福','福'=>'福','禮'=>'禮','⽱'=>'禸','⽲'=>'禾','秊'=>'秊','秫'=>'秫','稜'=>'稜','穀'=>'穀','穀'=>'穀','穊'=>'穊','穏'=>'穏','⽳'=>'穴','突'=>'突','窱'=>'窱','立'=>'立','⽴'=>'立','竮'=>'竮','⽵'=>'竹','笠'=>'笠','節'=>'節','節'=>'節','篆'=>'篆','築'=>'築','簾'=>'簾','籠'=>'籠','⽶'=>'米','类'=>'类','粒'=>'粒','精'=>'精','糒'=>'糒','糖'=>'糖','糣'=>'糣','糧'=>'糧','糨'=>'糨','⽷'=>'糸','紀'=>'紀','紐'=>'紐','索'=>'索','累'=>'累','絶'=>'絕','絛'=>'絛','絣'=>'絣','綠'=>'綠','綾'=>'綾','緇'=>'緇','練'=>'練','練'=>'練','練'=>'練','縂'=>'縂','縉'=>'縉','縷'=>'縷','繁'=>'繁','繅'=>'繅','⽸'=>'缶','缾'=>'缾','⽹'=>'网','⺫'=>'罒','署'=>'署','罹'=>'罹','罺'=>'罺','羅'=>'羅','⽺'=>'羊','羕'=>'羕','羚'=>'羚','羽'=>'羽','⽻'=>'羽','翺'=>'翺','老'=>'老','⽼'=>'老','者'=>'者','者'=>'者','者'=>'者','⽽'=>'而','⽾'=>'耒','⽿'=>'耳','聆'=>'聆','聠'=>'聠','聯'=>'聯','聰'=>'聰','聾'=>'聾','⾀'=>'聿','⾁'=>'肉','肋'=>'肋','肭'=>'肭','育'=>'育','㬵'=>'胶','腁'=>'胼','脃'=>'脃','脾'=>'脾','臘'=>'臘','⾂'=>'臣','臨'=>'臨','⾃'=>'自','臭'=>'臭','⾄'=>'至','⾅'=>'臼','舁'=>'舁','舁'=>'舁','舄'=>'舄','⾆'=>'舌','⾇'=>'舛','⾈'=>'舟','⾉'=>'艮','良'=>'良','⾊'=>'色','⾋'=>'艸','艹'=>'艹','艹'=>'艹','芋'=>'芋','芑'=>'芑','芝'=>'芝','花'=>'花','芳'=>'芳','芽'=>'芽','若'=>'若','若'=>'若','苦'=>'苦','茝'=>'茝','茣'=>'茣','茶'=>'茶','荒'=>'荒','荓'=>'荓','荣'=>'荣','莭'=>'莭','莽'=>'莽','菉'=>'菉','菊'=>'菊','菌'=>'菌','菜'=>'菜','菧'=>'菧','華'=>'華','菱'=>'菱','落'=>'落','葉'=>'葉','著'=>'著','著'=>'著','蔿'=>'蒍','蓮'=>'蓮','蓱'=>'蓱','蓳'=>'蓳','蓼'=>'蓼','蔖'=>'蔖','蕤'=>'蕤','藍'=>'藍','藺'=>'藺','蘆'=>'蘆','蘒'=>'蘒','蘭'=>'蘭','虁'=>'蘷','蘿'=>'蘿','⾌'=>'虍','虐'=>'虐','虜'=>'虜','虜'=>'虜','虧'=>'虧','虩'=>'虩','⾍'=>'虫','蚈'=>'蚈','蚩'=>'蚩','蛢'=>'蛢','蜎'=>'蜎','蜨'=>'蜨','蝫'=>'蝫','蝹'=>'蝹','蝹'=>'蝹','螆'=>'螆','螺'=>'螺','蟡'=>'蟡','蠁'=>'蠁','蠟'=>'蠟','⾎'=>'血','行'=>'行','⾏'=>'行','衠'=>'衠','衣'=>'衣','⾐'=>'衣','裂'=>'裂','裏'=>'裏','裗'=>'裗','裞'=>'裞','裡'=>'裡','裸'=>'裸','裺'=>'裺','褐'=>'褐','襁'=>'襁','襤'=>'襤','⾑'=>'襾','覆'=>'覆','見'=>'見','⾒'=>'見','視'=>'視','視'=>'視','⾓'=>'角','⾔'=>'言','䚶'=>'訞','詽'=>'訮','誠'=>'誠','說'=>'說','說'=>'說','調'=>'調','請'=>'請','諒'=>'諒','論'=>'論','諭'=>'諭','諭'=>'諭','諸'=>'諸','諸'=>'諸','諾'=>'諾','諾'=>'諾','謁'=>'謁','謁'=>'謁','謹'=>'謹','謹'=>'謹','識'=>'識','讀'=>'讀','讏'=>'讆','變'=>'變','變'=>'變','⾕'=>'谷','⾖'=>'豆','豈'=>'豈','豕'=>'豕','⾗'=>'豕','⾘'=>'豸','⾙'=>'貝','貫'=>'貫','賁'=>'賁','賂'=>'賂','賈'=>'賈','賓'=>'賓','贈'=>'贈','贈'=>'贈','贛'=>'贛','⾚'=>'赤','⾛'=>'走','起'=>'起','趆'=>'赿','⾜'=>'足','趼'=>'趼','跋'=>'跋','跺'=>'跥','路'=>'路','跰'=>'跰','躛'=>'躗','⾝'=>'身','車'=>'車','⾞'=>'車','軔'=>'軔','輧'=>'軿','輦'=>'輦','輪'=>'輪','輸'=>'輸','輸'=>'輸','輻'=>'輻','轢'=>'轢','⾟'=>'辛','辞'=>'辞','辰'=>'辰','⾠'=>'辰','⾡'=>'辵','辶'=>'辶','⻌'=>'辶','連'=>'連','逸'=>'逸','逸'=>'逸','遲'=>'遲','遼'=>'遼','邏'=>'邏','⾢'=>'邑','邔'=>'邔','郎'=>'郎','郱'=>'郱','都'=>'都','鄑'=>'鄑','鄛'=>'鄛','⾣'=>'酉','酪'=>'酪','醙'=>'醙','醴'=>'醴','⾤'=>'釆','里'=>'里','⾥'=>'里','量'=>'量','金'=>'金','⾦'=>'金','鈴'=>'鈴','鈸'=>'鈸','鉶'=>'鉶','鉼'=>'鉼','鋗'=>'鋗','鋘'=>'鋘','錄'=>'錄','鍊'=>'鍊','鎮'=>'鎭','鏹'=>'鏹','鐕'=>'鐕','⾧'=>'長','⾨'=>'門','開'=>'開','閭'=>'閭','閷'=>'閷','⾩'=>'阜','阮'=>'阮','陋'=>'陋','降'=>'降','陵'=>'陵','陸'=>'陸','陼'=>'陼','隆'=>'隆','隣'=>'隣','⾪'=>'隶','隸'=>'隸','⾫'=>'隹','雃'=>'雃','離'=>'離','難'=>'難','難'=>'難','⾬'=>'雨','零'=>'零','雷'=>'雷','霣'=>'霣','露'=>'露','靈'=>'靈','⾭'=>'靑','靖'=>'靖','靖'=>'靖','⾮'=>'非','⾯'=>'面','⾰'=>'革','⾱'=>'韋','韛'=>'韛','韠'=>'韠','⾲'=>'韭','⾳'=>'音','響'=>'響','響'=>'響','⾴'=>'頁','頋'=>'頋','頋'=>'頋','頋'=>'頋','領'=>'領','頩'=>'頩','頻'=>'頻','頻'=>'頻','類'=>'類','⾵'=>'風','⾶'=>'飛','⻝'=>'食','⾷'=>'食','飢'=>'飢','飯'=>'飯','飼'=>'飼','館'=>'館','餩'=>'餩','⾸'=>'首','⾹'=>'香','馧'=>'馧','⾺'=>'馬','駂'=>'駂','駱'=>'駱','駾'=>'駾','驪'=>'驪','⾻'=>'骨','⾼'=>'高','⾽'=>'髟','鬒'=>'鬒','鬒'=>'鬒','⾾'=>'鬥','⾿'=>'鬯','⿀'=>'鬲','⿁'=>'鬼','⿂'=>'魚','魯'=>'魯','鱀'=>'鱀','鱗'=>'鱗','⿃'=>'鳥','鳽'=>'鳽','鵧'=>'鵧','鶴'=>'鶴','鷺'=>'鷺','鸞'=>'鸞','鹃'=>'鹂','⿄'=>'鹵','鹿'=>'鹿','⿅'=>'鹿','麗'=>'麗','麟'=>'麟','⿆'=>'麥','麻'=>'麻','⿇'=>'麻','⿈'=>'黃','⿉'=>'黍','黎'=>'黎','⿊'=>'黑','黹'=>'黹','⿋'=>'黹','⿌'=>'黽','黾'=>'黾','鼅'=>'鼅','⿍'=>'鼎','鼏'=>'鼏','⿎'=>'鼓','鼖'=>'鼖','⿏'=>'鼠','鼻'=>'鼻','⿐'=>'鼻','齃'=>'齃','⿑'=>'齊','⿒'=>'齒','龍'=>'龍','⿓'=>'龍','龎'=>'龎','龜'=>'龜','龜'=>'龜','龜'=>'龜','⿔'=>'龜','⻳'=>'龟','⿕'=>'龠','㒞'=>'㒞','㒹'=>'㒹','㒻'=>'㒻','㓟'=>'㓟','㔕'=>'㔕','䎛'=>'㖈','㛮'=>'㛮','㛼'=>'㛼','㞁'=>'㞁','㠯'=>'㠯','㡢'=>'㡢','㡼'=>'㡼','㣇'=>'㣇','㣣'=>'㣣','㤜'=>'㤜','㤺'=>'㤺','㨮'=>'㨮','㩬'=>'㩬','㫤'=>'㫤','㬈'=>'㬈','㬙'=>'㬙','䐠'=>'㬻','㭉'=>'㭉','㮝'=>'㮝','㮝'=>'㮝','㰘'=>'㰘','㱎'=>'㱎','㴳'=>'㴳','㶖'=>'㶖','㺬'=>'㺬','㺸'=>'㺸','㺸'=>'㺸','㼛'=>'㼛','㿼'=>'㿼','䀈'=>'䀈','䀘'=>'䀘','䀹'=>'䀹','䀹'=>'䀹','䁆'=>'䁆','䂖'=>'䂖','䃣'=>'䃣','䄯'=>'䄯','䈂'=>'䈂','䈧'=>'䈧','䊠'=>'䊠','䌁'=>'䌁','䌴'=>'䌴','䍙'=>'䍙','䏕'=>'䏕','䏙'=>'䏙','䐋'=>'䐋','䑫'=>'䑫','䔫'=>'䔫','䕝'=>'䕝','䕡'=>'䕡','䕫'=>'䕫','䗗'=>'䗗','䗹'=>'䗹','䘵'=>'䘵','䚾'=>'䚾','䛇'=>'䛇','䦕'=>'䦕','䧦'=>'䧦','䩮'=>'䩮','䩶'=>'䩶','䪲'=>'䪲','䬳'=>'䬳','䯎'=>'䯎','䳎'=>'䳎','䳭'=>'䳭','䳸'=>'䳸','䵖'=>'䵖','𠄢'=>'𠄢','𠔜'=>'𠔜','𠔥'=>'𠔥','𠕋'=>'𠕋','𠘺'=>'𠘺','𠠄'=>'𠠄','𠣞'=>'𠣞','𠨬'=>'𠨬','𠭣'=>'𠭣','𡓤'=>'𡓤','𡚨'=>'𡚨','𡛪'=>'𡛪','𡧈'=>'𡧈','𡬘'=>'𡬘','𡴋'=>'𡴋','𡷤'=>'𡷤','𡷦'=>'𡷦','𢆃'=>'𢆃','𢆟'=>'𢆟','𢌱'=>'𢌱','𢌱'=>'𢌱','𢛔'=>'𢛔','𢡄'=>'𢡄','𢡊'=>'𢡊','𢬌'=>'𢬌','𢯱'=>'𢯱','𣀊'=>'𣀊','𣊸'=>'𣊸','𣍟'=>'𣍟','𣎓'=>'𣎓','𣎜'=>'𣎜','𣏃'=>'𣏃','𣏕'=>'𣏕','𣑭'=>'𣑭','𣚣'=>'𣚣','𣢧'=>'𣢧','𣪍'=>'𣪍','𣫺'=>'𣫺','𣲼'=>'𣲼','𣴞'=>'𣴞','𣻑'=>'𣻑','𣽞'=>'𣽞','𣾎'=>'𣾎','𤉣'=>'𤉣','𤎫'=>'𤎫','𤘈'=>'𤘈','𤜵'=>'𤜵','𤠔'=>'𤠔','𤰶'=>'𤰶','𤲒'=>'𤲒','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'𥁄','𥃲'=>'𥃲','𥃳'=>'𥃳','𥄙'=>'𥄙','𥄳'=>'𥄳','𥉉'=>'𥉉','𥐝'=>'𥐝','𥘦'=>'𥘦','𥚚'=>'𥚚','𥛅'=>'𥛅','𥥼'=>'𥥼','𥪧'=>'𥪧','𥪧'=>'𥪧','𥮫'=>'𥮫','𥲀'=>'𥲀','𥳐'=>'𥳐','𥾆'=>'𥾆','𦇚'=>'𦇚','𦈨'=>'𦈨','𦉇'=>'𦉇','𦋙'=>'𦋙','𦌾'=>'𦌾','𦓚'=>'𦓚','𦔣'=>'𦔣','𦖨'=>'𦖨','𦞧'=>'𦞧','𦞵'=>'𦞵','𦬼'=>'𦬼','𦰶'=>'𦰶','𦳕'=>'𦳕','𦵫'=>'𦵫','𦼬'=>'𦼬','𦾱'=>'𦾱','𧃒'=>'𧃒','𧏊'=>'𧏊','𧙧'=>'𧙧','𧢮'=>'𧢮','𧥦'=>'𧥦','𧲨'=>'𧲨','𧻓'=>'𧻓','𧼯'=>'𧼯','𨗒'=>'𨗒','𨗭'=>'𨗭','𨜮'=>'𨜮','𨯺'=>'𨯺','𨵷'=>'𨵷','𩅅'=>'𩅅','𩇟'=>'𩇟','𩈚'=>'𩈚','𩐊'=>'𩐊','𩒖'=>'𩒖','𩖶'=>'𩖶','𩬰'=>'𩬰','𪃎'=>'𪃎','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','𪎒'=>'𪎒','𪘀'=>'𪘀','℃'=>'°C','℉'=>'°F','ℇ'=>'Ɛ','℻'=>'FAX','ℕ'=>'N','№'=>'No','ℚ'=>'Q','₨'=>'Rs','𝐓'=>'T','℡'=>'TEL','𝐔'=>'U','𝐖'=>'W','₩'=>'W̵','𝐗'=>'X','¥'=>'Y̵','𝚲'=>'Λ','𝚵'=>'Ξ','ℿ'=>'Π','ϲ'=>'c','ϒ'=>'Y','𝚽'=>'Φ','𝚿'=>'Ψ','ѣ'=>'Ь̵','ਃ'=>'ঃ','ಃ'=>'ః','່'=>'่','់'=>'่','້'=>'้','໊'=>'๊','໋'=>'๋','៕'=>'๚','៚'=>'๛','ъ'=>'ˉb','៙'=>'๏','೧'=>'౧','૨'=>'२','೨'=>'౨','૩'=>'३','૪'=>'४','૮'=>'८','೯'=>'౯','а'=>'a','Ꮟ'=>'b','ᖯ'=>'b','с'=>'c','ԁ'=>'d','ᑯ'=>'d','е'=>'e','ә'=>'ǝ','ε'=>'ɛ','є'=>'ɛ','ք'=>'f','ց'=>'g','һ'=>'h','հ'=>'h','Ꮒ'=>'h','Ᏺ'=>'h̔','ι'=>'i','і'=>'i','Ꭵ'=>'i','ј'=>'j','յ'=>'j','ᗰ'=>'m','ո'=>'n','η'=>'n̩','ం'=>'o','ಂ'=>'o','ം'=>'o','०'=>'o','੦'=>'o','૦'=>'o','๐'=>'o','໐'=>'o','ο'=>'o','о'=>'o','օ'=>'o','ဝ'=>'o','ρ'=>'p','р'=>'p','ᴩ'=>'ᴘ','գ'=>'q','κ'=>'ĸ','к'=>'ĸ','ᴦ'=>'r','г'=>'r','ѕ'=>'s','υ'=>'u','ս'=>'u','ν'=>'v','ѵ'=>'v','Ꮃ'=>'w','ᗯ'=>'w','х'=>'x','ᕁ'=>'x','у'=>'y','Ꭹ'=>'y','ӡ'=>'ʒ','ჳ'=>'ʒ','ϩ'=>'ƨ','ь'=>'ƅ','ы'=>'ƅi','ɑ'=>'α','ծ'=>'δ','ᕷ'=>'δ','п'=>'π','ɸ'=>'φ','ф'=>'φ','ʙ'=>'в','ɜ'=>'з','ᴍ'=>'м','ʜ'=>'н','ɢ'=>'ԍ','ᴛ'=>'т','ᴙ'=>'я','ઽ'=>'ऽ','ુ'=>'ु','ૂ'=>'ू','ੋ'=>'ॆ','੍'=>'्','્'=>'्','ഉ'=>'உ','ജ'=>'ஐ','ണ'=>'ண','ഴ'=>'ழ','ി'=>'ி','ു'=>'ூ','ಅ'=>'అ','ಆ'=>'ఆ','ಇ'=>'ఇ','ಒ'=>'ఒ','ಓ'=>'ఒౕ','ಜ'=>'జ','ಞ'=>'ఞ','ಣ'=>'ణ','థ'=>'ధּ','ಯ'=>'య','ఠ'=>'రּ','ಱ'=>'ఱ','ಲ'=>'ల','ඌ'=>'ന്ന','ஶ'=>'ശ','ຈ'=>'จ','ບ'=>'บ','ປ'=>'ป','ຝ'=>'ฝ','ພ'=>'พ','ຟ'=>'ฟ','ຍ'=>'ย','។'=>'ฯ','ិ'=>'ิ','ី'=>'ี','ឹ'=>'ึ','ឺ'=>'ื','ຸ'=>'ุ','ູ'=>'ู','ᗅ'=>'A','ᒍ'=>'J','ᕼ'=>'H','ᐯ'=>'V','ᑭ'=>'P','ᗷ'=>'B','ヘ'=>'へ','𐏑'=>'𐎂','𐏓'=>'𐎓','𒀸'=>'𐎚','ᅳ'=>'一','ǀ'=>'丨','ᅵ'=>'丨','Ꭺ'=>'A','Ᏼ'=>'B','Ꮯ'=>'C','ᗞ'=>'D','Ꭼ'=>'E','ᖴ'=>'F','Ꮐ'=>'G','Ꮋ'=>'H','Ꭻ'=>'J','Ꮶ'=>'K','Ꮮ'=>'L','Ꮇ'=>'M','Ꮲ'=>'P','ᖇ'=>'R','Ꮥ'=>'S','Ꮩ'=>'V','Ꮓ'=>'Z');
\ No newline at end of file +<?php return array('¡'=>'i','ǃ'=>'!','α'=>'a',' '=>' ',''=>'',''=>'',''=>'','᠆'=>'',''=>'',''=>'',''=>'',''=>'','
'=>'','
'=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'',''=>'','۬'=>'۟','̓'=>'̓','ُ'=>'̓','֜'=>'́','́'=>'́','݇'=>'́','॔'=>'́','̀'=>'̀','॓'=>'̀','̌'=>'̆','̑'=>'̂','֯'=>'̊','ஂ'=>'̊','ํ'=>'̊','ໍ'=>'̊','ံ'=>'̊','ំ'=>'̊','៓'=>'̊','゚'=>'̊','゚'=>'̊','ͦ'=>'̊','͂'=>'̃','ׄ'=>'̇','ֹ'=>'̇','ׂ'=>'̇','ׁ'=>'̇','݁'=>'̇','ं'=>'̇','ਂ'=>'̇','ં'=>'̇','்'=>'̇','̅'=>'̄','〬'=>'̉','̱'=>'̠','॒'=>'̠','̧'=>'̡','̦'=>'̡','̨'=>'̢','़'=>'̣','়'=>'̣','਼'=>'̣','઼'=>'̣','଼'=>'̣','͇'=>'̳','̶'=>'̵','ﱞ'=>'ﹲّ','ﱟ'=>'ﹴّ','ﳲ'=>'ﹷّ','ﱠ'=>'ﹶّ','ﳳ'=>'ﹹّ','ﱡ'=>'ﹸّ','ﳴ'=>'ﹻّ','ﱢ'=>'ﹺّ','ﱣ'=>'ﹼٰ','ٴ'=>'ٔ','݂'=>'ܼ','౦'=>'o','೦'=>'o','゙'=>'゙',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ','`'=>'`','`'=>'`','῀'=>'˜','^'=>'^','︿'=>'^','_'=>'_','﹍'=>'_','﹎'=>'_','﹏'=>'_','⌇'=>'︴','-'=>'-','‐'=>'-','‑'=>'-','‒'=>'-','–'=>'-','﹘'=>'-','∼'=>'⁓','・'=>'・','•'=>'・',','=>',','‚'=>',','٬'=>'،','、'=>'、',';'=>';',';'=>';',':'=>':','։'=>':','︰'=>':','׃'=>':','⩴'=>'::=','.'=>'.','․'=>'.','܂'=>'.','‥'=>'..','…'=>'...','。'=>'。','·'=>'·','‧'=>'·','∙'=>'·','⋅'=>'·','ᐧ'=>'·','ᔯ'=>'·4','ᐌ'=>'·ᐁ','ᐎ'=>'·ᐃ','ᐐ'=>'·ᐄ','ᐒ'=>'·ᐅ','ᐔ'=>'·ᐆ','ᐗ'=>'·ᐊ','ᐙ'=>'·ᐋ','ᐷ'=>'·ᐳ','ᑀ'=>'·ᐳ','ᑂ'=>'·ᐴ','ᑄ'=>'·ᐸ','ᑆ'=>'·ᐹ','ᑗ'=>'·ᑌ','ᑙ'=>'·ᑎ','ᑛ'=>'·ᑏ','ᑔ'=>'·ᑐ','ᑝ'=>'·ᑐ','ᑟ'=>'·ᑑ','ᑡ'=>'·ᑕ','ᑣ'=>'·ᑖ','ᑴ'=>'·ᑫ','ᑸ'=>'·ᑮ','ᑼ'=>'·ᑰ','ᑾ'=>'·ᑲ','ᒀ'=>'·ᑳ','ᒒ'=>'·ᒉ','ᒔ'=>'·ᒋ','ᒖ'=>'·ᒌ','ᒚ'=>'·ᒎ','ᒜ'=>'·ᒐ','ᒞ'=>'·ᒑ','ᒬ'=>'·ᒣ','ᒮ'=>'·ᒥ','ᒰ'=>'·ᒦ','ᒲ'=>'·ᒧ','ᒴ'=>'·ᒨ','ᒶ'=>'·L','ᒸ'=>'·ᒫ','ᓉ'=>'·ᓀ','ᓋ'=>'·ᓇ','ᓍ'=>'·ᓈ','ᓜ'=>'·ᓓ','ᓞ'=>'·ᓕ','ᓠ'=>'·ᓖ','ᓢ'=>'·ᓗ','ᓤ'=>'·ᓘ','ᓦ'=>'·ᓚ','ᓨ'=>'·ᓛ','ᓶ'=>'·ᓭ','ᓸ'=>'·ᓯ','ᓺ'=>'·ᓰ','ᓼ'=>'·ᓱ','ᓾ'=>'·ᓲ','ᔀ'=>'·ᓴ','ᔂ'=>'·ᓵ','ᔗ'=>'·ᔐ','ᔙ'=>'·ᔑ','ᔛ'=>'·ᔒ','ᔝ'=>'·ᔓ','ᔟ'=>'·ᔔ','ᔡ'=>'·ᔕ','ᔣ'=>'·ᔖ','ᔱ'=>'·ᔨ','ᔳ'=>'·ᔩ','ᔵ'=>'·ᔪ','ᔷ'=>'·ᔫ','ᔹ'=>'·ᔭ','ᔻ'=>'·ᔮ','ᕎ'=>'·ᕌ','ᕛ'=>'·ᕚ','ᕨ'=>'·ᕧ','('=>'(','⑴'=>'(1)','⒧'=>'(l)','⑽'=>'(10)','⑾'=>'(11)','⑿'=>'(12)','⒀'=>'(13)','⒁'=>'(14)','⒂'=>'(15)','⒃'=>'(16)','⒄'=>'(17)','⒅'=>'(18)','⒆'=>'(19)','⑵'=>'(2)','⒇'=>'(20)','⑶'=>'(3)','⑷'=>'(4)','⑸'=>'(5)','⑹'=>'(6)','⑺'=>'(7)','⑻'=>'(8)','⑼'=>'(9)','⒜'=>'(a)','⒝'=>'(b)','⒞'=>'(c)','⒟'=>'(d)','⒠'=>'(e)','⒡'=>'(f)','⒢'=>'(g)','⒣'=>'(h)','⒤'=>'(i)','⒥'=>'(j)','⒦'=>'(k)','⒨'=>'(m)','⒩'=>'(n)','⒪'=>'(o)','⒫'=>'(p)','⒬'=>'(q)','⒭'=>'(r)','⒮'=>'(s)','⒯'=>'(t)','⒰'=>'(u)','⒱'=>'(v)','⒲'=>'(w)','⒳'=>'(x)','⒴'=>'(y)','⒵'=>'(z)','㈀'=>'(ᄀ)','㈎'=>'(가)','㈁'=>'(ᄂ)','㈏'=>'(나)','㈂'=>'(ᄃ)','㈐'=>'(다)','㈃'=>'(ᄅ)','㈑'=>'(라)','㈄'=>'(ᄆ)','㈒'=>'(마)','㈅'=>'(ᄇ)','㈓'=>'(바)','㈆'=>'(ᄉ)','㈔'=>'(사)','㈇'=>'(ᄋ)','㈕'=>'(아)','㈝'=>'(오전)','㈞'=>'(오후)','㈈'=>'(ᄌ)','㈖'=>'(자)','㈜'=>'(주)','㈉'=>'(ᄎ)','㈗'=>'(차)','㈊'=>'(ᄏ)','㈘'=>'(카)','㈋'=>'(ᄐ)','㈙'=>'(타)','㈌'=>'(ᄑ)','㈚'=>'(파)','㈍'=>'(ᄒ)','㈛'=>'(하)','㈠'=>'(一)','㈦'=>'(七)','㈢'=>'(三)','㈨'=>'(九)','㈡'=>'(二)','㈤'=>'(五)','㈹'=>'(代)','㈽'=>'(企)','㉁'=>'(休)','㈧'=>'(八)','㈥'=>'(六)','㈸'=>'(労)','㈩'=>'(十)','㈿'=>'(協)','㈴'=>'(名)','㈺'=>'(呼)','㈣'=>'(四)','㈯'=>'(土)','㈻'=>'(学)','㈰'=>'(日)','㈪'=>'(月)','㈲'=>'(有)','㈭'=>'(木)','㈱'=>'(株)','㈬'=>'(水)','㈫'=>'(火)','㈵'=>'(特)','㈼'=>'(監)','㈳'=>'(社)','㈷'=>'(祝)','㉀'=>'(祭)','㉂'=>'(自)','㉃'=>'(至)','㈶'=>'(財)','㈾'=>'(資)','㈮'=>'(金)',')'=>')','['=>'[','〔'=>'[',']'=>']','〕'=>']','{'=>'{','}'=>'}','⦅'=>'⦅','⦆'=>'⦆','「'=>'「','」'=>'」','@'=>'@','*'=>'*','/'=>'/','⁄'=>'/','∕'=>'/','\'=>'\\','&'=>'&','#'=>'#','%'=>'%','‶'=>'‵‵','‷'=>'‵‵‵','༌'=>'་','´'=>'ʹ','΄'=>'ʹ','´'=>'ʹ','\''=>'ʹ','''=>'ʹ','′'=>'ʹ','׳'=>'ʹ','ʹ'=>'ʹ','ˊ'=>'ʹ','"'=>'ʹʹ','"'=>'ʹʹ','″'=>'ʹʹ','〃'=>'ʹʹ','״'=>'ʹʹ','ʺ'=>'ʹʹ','‴'=>'ʹʹʹ','⁗'=>'ʹʹʹʹ','¯'=>'ˉ',' ̄'=>'ˉ','‾'=>'ˉ','﹉'=>'ˉ','﹊'=>'ˉ','﹋'=>'ˉ','﹌'=>'ˉ','˚'=>'°','௵'=>'௳','←'=>'←','→'=>'→','↑'=>'↑','↓'=>'↓','↵'=>'↲','⨡'=>'↾','𝛛'=>'∂','𝜕'=>'∂','𝝏'=>'∂','𝞉'=>'∂','𝟃'=>'∂','𝛁'=>'∇','𝛻'=>'∇','𝜵'=>'∇','𝝯'=>'∇','𝞩'=>'∇','+'=>'+','﬩'=>'+','‹'=>'<','<'=>'<','='=>'=','⩵'=>'==','⩶'=>'===','›'=>'>','>'=>'>','¬'=>'¬','¦'=>'¦','〜'=>'~','~'=>'~','﹨'=>'∖','⋀'=>'∧','⋁'=>'∨','⋂'=>'∩','⋃'=>'∪','∯'=>'∮∮','∰'=>'∮∮∮','≣'=>'≡','♁'=>'⊕','☉'=>'⊙','⟂'=>'⊥','▷'=>'⊲','⨝'=>'⋈','⨽'=>'⌙','☸'=>'⎈','⎮'=>'⎥','│'=>'│','▐'=>'▌','■'=>'■','☐'=>'□','○'=>'○','⦾'=>'◎','〛'=>'⟧','〈'=>'⟨','〈'=>'⟨','〉'=>'⟩','〉'=>'⟩','⧙'=>'⦚','〶'=>'〒','ー'=>'ー','¢'=>'¢','$'=>'$','£'=>'£','¥'=>'Y̵','₩'=>'W̵','0'=>'0','𝟎'=>'0','𝟘'=>'0','𝟢'=>'0','𝟬'=>'0','𝟶'=>'0','০'=>'0','୦'=>'0','௦'=>'0','᠐'=>'0','〇'=>'0','𝐎'=>'0','𝑂'=>'0','𝑶'=>'0','𝒪'=>'0','𝓞'=>'0','𝔒'=>'0','𝕆'=>'0','𝕺'=>'0','𝖮'=>'0','𝗢'=>'0','𝘖'=>'0','𝙊'=>'0','𝙾'=>'0','𝚶'=>'0','𝛰'=>'0','𝜪'=>'0','𝝤'=>'0','𝞞'=>'0','ⵔ'=>'0','ഠ'=>'0','⊖'=>'0̵','𝚯'=>'0̵','𝚹'=>'0̵','𝛩'=>'0̵','𝛳'=>'0̵','𝜣'=>'0̵','𝜭'=>'0̵','𝝝'=>'0̵','𝝧'=>'0̵','𝞗'=>'0̵','𝞡'=>'0̵','ⴱ'=>'0̵','Ꮎ'=>'0̵','۰'=>'٠','᭜'=>'᭐','㍘'=>'0点','1'=>'1','𝟏'=>'1','𝟙'=>'1','𝟣'=>'1','𝟭'=>'1','𝟷'=>'1','ℐ'=>'1','ℑ'=>'1','𝐈'=>'1','𝐼'=>'1','𝑰'=>'1','𝓘'=>'1','𝕀'=>'1','𝕴'=>'1','𝖨'=>'1','𝗜'=>'1','𝘐'=>'1','𝙄'=>'1','𝙸'=>'1','l'=>'l','l'=>'l','ⅼ'=>'1','ℓ'=>'l','𝐥'=>'l','𝑙'=>'l','𝒍'=>'l','𝓁'=>'l','𝓵'=>'l','𝔩'=>'l','𝕝'=>'l','𝖑'=>'l','𝗅'=>'l','𝗹'=>'l','𝘭'=>'l','𝙡'=>'l','𝚕'=>'l','𝚰'=>'l','𝛪'=>'l','𝜤'=>'l','𝝞'=>'l','𝞘'=>'l','①'=>'➀','ɭ'=>'l̢','ɫ'=>'l̴','ƚ'=>'l̵','ł'=>'l̷','۱'=>'١','⒈'=>'1.','ŀ'=>'l·','ᒷ'=>'1·','⑩'=>'➉','⒑'=>'10.','㏩'=>'10日','㋉'=>'10月','㍢'=>'10点','⒒'=>'11.','㏪'=>'11日','㋊'=>'11月','㍣'=>'11点','⒓'=>'12.','㏫'=>'12日','㋋'=>'12月','㍤'=>'12点','⒔'=>'13.','㏬'=>'13日','㍥'=>'13点','⒕'=>'14.','㏭'=>'14日','㍦'=>'14点','⒖'=>'15.','㏮'=>'15日','㍧'=>'15点','⒗'=>'16.','㏯'=>'16日','㍨'=>'16点','⒘'=>'17.','㏰'=>'17日','㍩'=>'17点','⒙'=>'18.','㏱'=>'18日','㍪'=>'18点','⒚'=>'19.','㏲'=>'19日','㍫'=>'19点','lj'=>'lj','㏠'=>'1日','㋀'=>'1月','㍙'=>'1点','2'=>'2','𝟐'=>'2','𝟚'=>'2','𝟤'=>'2','𝟮'=>'2','𝟸'=>'2','ᒿ'=>'2','②'=>'➁','۲'=>'٢','⒉'=>'2.','⒛'=>'20.','㏳'=>'20日','㍬'=>'20点','㏴'=>'21日','㍭'=>'21点','㏵'=>'22日','㍮'=>'22点','㏶'=>'23日','㍯'=>'23点','㏷'=>'24日','㍰'=>'24点','㏸'=>'25日','㏹'=>'26日','㏺'=>'27日','㏻'=>'28日','㏼'=>'29日','㏡'=>'2日','㋁'=>'2月','㍚'=>'2点','3'=>'3','𝟑'=>'3','𝟛'=>'3','𝟥'=>'3','𝟯'=>'3','𝟹'=>'3','③'=>'➂','۳'=>'٣','⒊'=>'3.','㏽'=>'30日','㏾'=>'31日','㏢'=>'3日','㋂'=>'3月','㍛'=>'3点','4'=>'4','𝟒'=>'4','𝟜'=>'4','𝟦'=>'4','𝟰'=>'4','𝟺'=>'4','Ꮞ'=>'4','④'=>'➃','⒋'=>'4.','ᔰ'=>'4·','㏣'=>'4日','㋃'=>'4月','㍜'=>'4点','5'=>'5','𝟓'=>'5','𝟝'=>'5','𝟧'=>'5','𝟱'=>'5','𝟻'=>'5','⑤'=>'➄','⒌'=>'5.','㏤'=>'5日','㋄'=>'5月','㍝'=>'5点','6'=>'6','𝟔'=>'6','𝟞'=>'6','𝟨'=>'6','𝟲'=>'6','𝟼'=>'6','б'=>'6','⑥'=>'➅','⒍'=>'6.','㏥'=>'6日','㋅'=>'6月','㍞'=>'6点','7'=>'7','𝟕'=>'7','𝟟'=>'7','𝟩'=>'7','𝟳'=>'7','𝟽'=>'7','⑦'=>'➆','۷'=>'٧','⒎'=>'7.','㏦'=>'7日','㋆'=>'7月','㍟'=>'7点','ଃ'=>'8','৪'=>'8','੪'=>'8','8'=>'8','𝟖'=>'8','𝟠'=>'8','𝟪'=>'8','𝟴'=>'8','𝟾'=>'8','ȣ'=>'8','⑧'=>'➇','۸'=>'٨','⒏'=>'8.','㏧'=>'8日','㋇'=>'8月','㍠'=>'8点','੧'=>'9','୨'=>'9','৭'=>'9','9'=>'9','𝟗'=>'9','𝟡'=>'9','𝟫'=>'9','𝟵'=>'9','𝟿'=>'9','⑨'=>'➈','۹'=>'٩','⒐'=>'9.','㏨'=>'9日','㋈'=>'9月','㍡'=>'9点','a'=>'a','𝐚'=>'a','𝑎'=>'a','𝒂'=>'a','𝒶'=>'a','𝓪'=>'a','𝔞'=>'a','𝕒'=>'a','𝖆'=>'a','𝖺'=>'a','𝗮'=>'a','𝘢'=>'a','𝙖'=>'a','𝚊'=>'a','℀'=>'a/c','℁'=>'a/s','æ'=>'ae','b'=>'b','𝐛'=>'b','𝑏'=>'b','𝒃'=>'b','𝒷'=>'b','𝓫'=>'b','𝔟'=>'b','𝕓'=>'b','𝖇'=>'b','𝖻'=>'b','𝗯'=>'b','𝘣'=>'b','𝙗'=>'b','𝚋'=>'b','ɓ'=>'b̔','ƃ'=>'b̄','ƀ'=>'b̵','c'=>'c','ⅽ'=>'c','𝐜'=>'c','𝑐'=>'c','𝒄'=>'c','𝒸'=>'c','𝓬'=>'c','𝔠'=>'c','𝕔'=>'c','𝖈'=>'c','𝖼'=>'c','𝗰'=>'c','𝘤'=>'c','𝙘'=>'c','𝚌'=>'c','𝛓'=>'c','𝜍'=>'c','𝝇'=>'c','𝞁'=>'c','𝞻'=>'c','℅'=>'c/o','℆'=>'c/u','d'=>'d','ⅾ'=>'d','ⅆ'=>'d','𝐝'=>'d','𝑑'=>'d','𝒅'=>'d','𝒹'=>'d','𝓭'=>'d','𝔡'=>'d','𝕕'=>'d','𝖉'=>'d','𝖽'=>'d','𝗱'=>'d','𝘥'=>'d','𝙙'=>'d','𝚍'=>'d','ɗ'=>'d̔','ƌ'=>'d̄','ɖ'=>'d̢','đ'=>'d̵','dz'=>'dz','dž'=>'dž','e'=>'e','ℯ'=>'e','ⅇ'=>'e','𝐞'=>'e','𝑒'=>'e','𝒆'=>'e','𝓮'=>'e','𝔢'=>'e','𝕖'=>'e','𝖊'=>'e','𝖾'=>'e','𝗲'=>'e','𝘦'=>'e','𝙚'=>'e','𝚎'=>'e','ⴹ'=>'E','ə'=>'ǝ','ɚ'=>'ǝ˞','⋴'=>'ɛ','𝛆'=>'ɛ','𝛜'=>'ɛ','𝜀'=>'ɛ','𝜖'=>'ɛ','𝜺'=>'ɛ','𝝐'=>'ɛ','𝝴'=>'ɛ','𝞊'=>'ɛ','𝞮'=>'ɛ','𝟄'=>'ɛ','f'=>'f','𝐟'=>'f','𝑓'=>'f','𝒇'=>'f','𝒻'=>'f','𝓯'=>'f','𝔣'=>'f','𝕗'=>'f','𝖋'=>'f','𝖿'=>'f','𝗳'=>'f','𝘧'=>'f','𝙛'=>'f','𝚏'=>'f','ƒ'=>'f̡','g'=>'g','ℊ'=>'g','𝐠'=>'g','𝑔'=>'g','𝒈'=>'g','𝓰'=>'g','𝔤'=>'g','𝕘'=>'g','𝖌'=>'g','𝗀'=>'g','𝗴'=>'g','𝘨'=>'g','𝙜'=>'g','𝚐'=>'g','ɡ'=>'g','ɠ'=>'g̔','ǥ'=>'g̵','h'=>'h','ℎ'=>'h','𝐡'=>'h','𝒉'=>'h','𝒽'=>'h','𝓱'=>'h','𝔥'=>'h','𝕙'=>'h','𝖍'=>'h','𝗁'=>'h','𝗵'=>'h','𝘩'=>'h','𝙝'=>'h','𝚑'=>'h','ɦ'=>'h̔','ħ'=>'h̵','ℏ'=>'h̵','῾'=>'ʻ','‘'=>'ʻ','‛'=>'ʻ','ʽ'=>'ʻ','⍳'=>'i','i'=>'i','ⅰ'=>'i','ℹ'=>'i','ⅈ'=>'i','𝐢'=>'i','𝑖'=>'i','𝒊'=>'i','𝒾'=>'i','𝓲'=>'i','𝔦'=>'i','𝕚'=>'i','𝖎'=>'i','𝗂'=>'i','𝗶'=>'i','𝘪'=>'i','𝙞'=>'i','𝚒'=>'i','ı'=>'i','𝚤'=>'i','ɪ'=>'i','ɩ'=>'i','𝛊'=>'i','𝜄'=>'i','𝜾'=>'i','𝝸'=>'i','𝞲'=>'i','ɨ'=>'i̵','ⅱ'=>'ii','ⅲ'=>'iii','ij'=>'ij','ⅳ'=>'iv','ⅸ'=>'ix','j'=>'j','ⅉ'=>'j','𝐣'=>'j','𝑗'=>'j','𝒋'=>'j','𝒿'=>'j','𝓳'=>'j','𝔧'=>'j','𝕛'=>'j','𝖏'=>'j','𝗃'=>'j','𝗷'=>'j','𝘫'=>'j','𝙟'=>'j','𝚓'=>'j','ϳ'=>'j','𝚥'=>'ȷ','k'=>'k','𝐤'=>'k','𝑘'=>'k','𝒌'=>'k','𝓀'=>'k','𝓴'=>'k','𝔨'=>'k','𝕜'=>'k','𝖐'=>'k','𝗄'=>'k','𝗸'=>'k','𝘬'=>'k','𝙠'=>'k','𝚔'=>'k','ƙ'=>'k̔','m'=>'m','ⅿ'=>'m','𝐦'=>'m','𝑚'=>'m','𝒎'=>'m','𝓂'=>'m','𝓶'=>'m','𝔪'=>'m','𝕞'=>'m','𝖒'=>'m','𝗆'=>'m','𝗺'=>'m','𝘮'=>'m','𝙢'=>'m','𝚖'=>'m','ɱ'=>'m̡','n'=>'n','𝐧'=>'n','𝑛'=>'n','𝒏'=>'n','𝓃'=>'n','𝓷'=>'n','𝔫'=>'n','𝕟'=>'n','𝖓'=>'n','𝗇'=>'n','𝗻'=>'n','𝘯'=>'n','𝙣'=>'n','𝚗'=>'n','𝐍'=>'N','𝑁'=>'N','𝑵'=>'N','𝒩'=>'N','𝓝'=>'N','𝔑'=>'N','𝕹'=>'N','𝖭'=>'N','𝗡'=>'N','𝘕'=>'N','𝙉'=>'N','𝙽'=>'N','𝚴'=>'N','𝛮'=>'N','𝜨'=>'N','𝝢'=>'N','𝞜'=>'N','ɲ'=>'ņ','ɳ'=>'n̢','ƞ'=>'n̩','𝛈'=>'n̩','𝜂'=>'n̩','𝜼'=>'n̩','𝝶'=>'n̩','𝞰'=>'n̩','nj'=>'nj','o'=>'o','ℴ'=>'o','𝐨'=>'o','𝑜'=>'o','𝒐'=>'o','𝓸'=>'o','𝔬'=>'o','𝕠'=>'o','𝖔'=>'o','𝗈'=>'o','𝗼'=>'o','𝘰'=>'o','𝙤'=>'o','𝚘'=>'o','ᴏ'=>'o','𝛐'=>'o','𝜊'=>'o','𝝄'=>'o','𝝾'=>'o','𝞸'=>'o','ɵ'=>'o̵','ǿ'=>'ó̵','ø'=>'o̷','œ'=>'oe','ơ'=>'oʼ','⍴'=>'p','p'=>'p','𝐩'=>'p','𝑝'=>'p','𝒑'=>'p','𝓅'=>'p','𝓹'=>'p','𝔭'=>'p','𝕡'=>'p','𝖕'=>'p','𝗉'=>'p','𝗽'=>'p','𝘱'=>'p','𝙥'=>'p','𝚙'=>'p','𝛒'=>'p','𝛠'=>'p','𝜌'=>'p','𝜚'=>'p','𝝆'=>'p','𝝔'=>'p','𝞀'=>'p','𝞎'=>'p','𝞺'=>'p','𝟈'=>'p','ƥ'=>'p̔','q'=>'q','𝐪'=>'q','𝑞'=>'q','𝒒'=>'q','𝓆'=>'q','𝓺'=>'q','𝔮'=>'q','𝕢'=>'q','𝖖'=>'q','𝗊'=>'q','𝗾'=>'q','𝘲'=>'q','𝙦'=>'q','𝚚'=>'q','𝐐'=>'Q','𝑄'=>'Q','𝑸'=>'Q','𝒬'=>'Q','𝓠'=>'Q','𝔔'=>'Q','𝕼'=>'Q','𝖰'=>'Q','𝗤'=>'Q','𝘘'=>'Q','𝙌'=>'Q','𝚀'=>'Q','ʠ'=>'q̔','𝛋'=>'ĸ','𝛞'=>'ĸ','𝜅'=>'ĸ','𝜘'=>'ĸ','𝜿'=>'ĸ','𝝒'=>'ĸ','𝝹'=>'ĸ','𝞌'=>'ĸ','𝞳'=>'ĸ','𝟆'=>'ĸ','r'=>'r','𝐫'=>'r','𝑟'=>'r','𝒓'=>'r','𝓇'=>'r','𝓻'=>'r','𝔯'=>'r','𝕣'=>'r','𝖗'=>'r','𝗋'=>'r','𝗿'=>'r','𝘳'=>'r','𝙧'=>'r','𝚛'=>'r','ɽ'=>'r̢','ɼ'=>'r̩','s'=>'s','𝐬'=>'s','𝑠'=>'s','𝒔'=>'s','𝓈'=>'s','𝓼'=>'s','𝔰'=>'s','𝕤'=>'s','𝖘'=>'s','𝗌'=>'s','𝘀'=>'s','𝘴'=>'s','𝙨'=>'s','𝚜'=>'s','ƽ'=>'s','ʂ'=>'s̢','∫'=>'ʃ','∬'=>'ʃʃ','∭'=>'ʃʃʃ','⨌'=>'ʃʃʃʃ','t'=>'t','𝐭'=>'t','𝑡'=>'t','𝒕'=>'t','𝓉'=>'t','𝓽'=>'t','𝔱'=>'t','𝕥'=>'t','𝖙'=>'t','𝗍'=>'t','𝘁'=>'t','𝘵'=>'t','𝙩'=>'t','𝚝'=>'t','𝑇'=>'T','𝑻'=>'T','𝒯'=>'T','𝓣'=>'T','𝔗'=>'T','𝕋'=>'T','𝕿'=>'T','𝖳'=>'T','𝗧'=>'T','𝘛'=>'T','𝙏'=>'T','𝚃'=>'T','𝚻'=>'T','𝛵'=>'T','𝜯'=>'T','𝝩'=>'T','𝞣'=>'T','ƭ'=>'t̔','ț'=>'ţ','ƫ'=>'ţ','ŧ'=>'t̵','u'=>'u','𝐮'=>'u','𝑢'=>'u','𝒖'=>'u','𝓊'=>'u','𝓾'=>'u','𝔲'=>'u','𝕦'=>'u','𝖚'=>'u','𝗎'=>'u','𝘂'=>'u','𝘶'=>'u','𝙪'=>'u','𝚞'=>'u','ʊ'=>'u','ʋ'=>'u','𝛖'=>'u','𝜐'=>'u','𝝊'=>'u','𝞄'=>'u','𝞾'=>'u','𝑈'=>'U','𝑼'=>'U','𝒰'=>'U','𝓤'=>'U','𝔘'=>'U','𝕌'=>'U','𝖀'=>'U','𝖴'=>'U','𝗨'=>'U','𝘜'=>'U','𝙐'=>'U','𝚄'=>'U','v'=>'v','ⅴ'=>'v','𝐯'=>'v','𝑣'=>'v','𝒗'=>'v','𝓋'=>'v','𝓿'=>'v','𝔳'=>'v','𝕧'=>'v','𝖛'=>'v','𝗏'=>'v','𝘃'=>'v','𝘷'=>'v','𝙫'=>'v','𝚟'=>'v','𝛎'=>'v','𝜈'=>'v','𝝂'=>'v','𝝼'=>'v','𝞶'=>'v','ⅵ'=>'vi','ⅶ'=>'vii','ⅷ'=>'viii','ɯ'=>'w','w'=>'w','𝐰'=>'w','𝑤'=>'w','𝒘'=>'w','𝓌'=>'w','𝔀'=>'w','𝔴'=>'w','𝕨'=>'w','𝖜'=>'w','𝗐'=>'w','𝘄'=>'w','𝘸'=>'w','𝙬'=>'w','𝚠'=>'w','𝑊'=>'W','𝑾'=>'W','𝒲'=>'W','𝓦'=>'W','𝔚'=>'W','𝕎'=>'W','𝖂'=>'W','𝖶'=>'W','𝗪'=>'W','𝘞'=>'W','𝙒'=>'W','𝚆'=>'W','×'=>'x','x'=>'x','ⅹ'=>'x','𝐱'=>'x','𝑥'=>'x','𝒙'=>'x','𝓍'=>'x','𝔁'=>'x','𝔵'=>'x','𝕩'=>'x','𝖝'=>'x','𝗑'=>'x','𝘅'=>'x','𝘹'=>'x','𝙭'=>'x','𝚡'=>'x','᙭'=>'X','𝑋'=>'X','𝑿'=>'X','𝒳'=>'X','𝓧'=>'X','𝔛'=>'X','𝕏'=>'X','𝖃'=>'X','𝖷'=>'X','𝗫'=>'X','𝘟'=>'X','𝙓'=>'X','𝚇'=>'X','𝚾'=>'X','𝛸'=>'X','𝜲'=>'X','𝝬'=>'X','𝞦'=>'X','ⅺ'=>'xi','ⅻ'=>'xii','y'=>'y','𝐲'=>'y','𝑦'=>'y','𝒚'=>'y','𝓎'=>'y','𝔂'=>'y','𝔶'=>'y','𝕪'=>'y','𝖞'=>'y','𝗒'=>'y','𝘆'=>'y','𝘺'=>'y','𝙮'=>'y','𝚢'=>'y','ƴ'=>'y̔','z'=>'z','𝐳'=>'z','𝑧'=>'z','𝒛'=>'z','𝓏'=>'z','𝔃'=>'z','𝔷'=>'z','𝕫'=>'z','𝖟'=>'z','𝗓'=>'z','𝘇'=>'z','𝘻'=>'z','𝙯'=>'z','𝚣'=>'z','ȥ'=>'z̡','ʐ'=>'z̢','ƶ'=>'z̵','ȝ'=>'ʒ','?'=>'ʔ','?'=>'ʔ','⁇'=>'ʔʔ','⁈'=>'ʔǃ','᾽'=>'ʼ','᾿'=>'ʼ','’'=>'ʼ','ʾ'=>'ʼ','!'=>'ǃ','!'=>'ǃ','⁉'=>'ǃʔ','‼'=>'ǃǃ','⍺'=>'α','𝛂'=>'α','𝛼'=>'α','𝜶'=>'α','𝝰'=>'α','𝞪'=>'α','𝛃'=>'β','𝛽'=>'β','𝜷'=>'β','𝝱'=>'β','𝞫'=>'β','ℽ'=>'γ','𝛄'=>'γ','𝛾'=>'γ','𝜸'=>'γ','𝝲'=>'γ','𝞬'=>'γ','𝛅'=>'δ','𝛿'=>'δ','𝜹'=>'δ','𝝳'=>'δ','𝞭'=>'δ','𝟋'=>'ϝ','𝛇'=>'ζ','𝜁'=>'ζ','𝜻'=>'ζ','𝝵'=>'ζ','𝞯'=>'ζ','⍬'=>'θ','𝛉'=>'θ','𝛝'=>'θ','𝜃'=>'θ','𝜗'=>'θ','𝜽'=>'θ','𝝑'=>'θ','𝝷'=>'θ','𝞋'=>'θ','𝞱'=>'θ','𝟅'=>'θ','𝛌'=>'λ','𝜆'=>'λ','𝝀'=>'λ','𝝺'=>'λ','𝞴'=>'λ','𝛬'=>'Λ','𝜦'=>'Λ','𝝠'=>'Λ','𝞚'=>'Λ','𝛍'=>'μ','𝜇'=>'μ','𝝁'=>'μ','𝝻'=>'μ','𝞵'=>'μ','𝛏'=>'ξ','𝜉'=>'ξ','𝝃'=>'ξ','𝝽'=>'ξ','𝞷'=>'ξ','𝛯'=>'Ξ','𝜩'=>'Ξ','𝝣'=>'Ξ','𝞝'=>'Ξ','ℼ'=>'π','𝛑'=>'π','𝛡'=>'π','𝜋'=>'π','𝜛'=>'π','𝝅'=>'π','𝝕'=>'π','𝝿'=>'π','𝞏'=>'π','𝞹'=>'π','𝟉'=>'π','ᴨ'=>'π','∏'=>'Π','𝚷'=>'Π','𝛱'=>'Π','𝜫'=>'Π','𝝥'=>'Π','𝞟'=>'Π','𝛔'=>'σ','𝜎'=>'σ','𝝈'=>'σ','𝞂'=>'σ','𝞼'=>'σ','𝛕'=>'τ','𝜏'=>'τ','𝝉'=>'τ','𝞃'=>'τ','𝞽'=>'τ','𝐘'=>'Y','𝑌'=>'Y','𝒀'=>'Y','𝒴'=>'Y','𝓨'=>'Y','𝔜'=>'Y','𝕐'=>'Y','𝖄'=>'Y','𝖸'=>'Y','𝗬'=>'Y','𝘠'=>'Y','𝙔'=>'Y','𝚈'=>'Y','𝚼'=>'Y','𝛶'=>'Y','𝜰'=>'Y','𝝪'=>'Y','𝞤'=>'Y','𝛗'=>'φ','𝛟'=>'φ','𝜑'=>'φ','𝜙'=>'φ','𝝋'=>'φ','𝝓'=>'φ','𝞅'=>'φ','𝞍'=>'φ','𝞿'=>'φ','𝟇'=>'φ','𝛷'=>'Φ','𝜱'=>'Φ','𝝫'=>'Φ','𝞥'=>'Φ','𝛘'=>'χ','𝜒'=>'χ','𝝌'=>'χ','𝞆'=>'χ','𝟀'=>'χ','𝛙'=>'ψ','𝜓'=>'ψ','𝝍'=>'ψ','𝞇'=>'ψ','𝟁'=>'ψ','𝛹'=>'Ψ','𝜳'=>'Ψ','𝝭'=>'Ψ','𝞧'=>'Ψ','⍵'=>'ω','𝛚'=>'ω','𝜔'=>'ω','𝝎'=>'ω','𝞈'=>'ω','𝟂'=>'ω','ӕ'=>'ae','ғ'=>'r̵','ґ'=>'rᑊ','җ'=>'ж̩','ҙ'=>'з̡','ӏ'=>'i','ҋ'=>'й̡','қ'=>'ĸ̩','ҟ'=>'ĸ̵','ᴫ'=>'л','ӆ'=>'л̡','ӎ'=>'м̡','ӊ'=>'н̡','ӈ'=>'н̡','ң'=>'н̩','ө'=>'o̵','ѳ'=>'o̵','ҫ'=>'c̡','ҭ'=>'т̩','ү'=>'y','ұ'=>'y̵','ћ'=>'h̵','ѽ'=>'ѡ҃','ӌ'=>'ҷ','ҿ'=>'ҽ̢','ҍ'=>'Ь̵','զ'=>'q','ռ'=>'n','ℵ'=>'א','ﬡ'=>'א','אָ'=>'אַ','אּ'=>'אַ','ﭏ'=>'אל','ℶ'=>'ב','ℷ'=>'ג','ℸ'=>'ד','ﬢ'=>'ד','ﬣ'=>'ה','ﬤ'=>'כ','ﬥ'=>'ל','ﬦ'=>'ם','ﬠ'=>'ע','ﬧ'=>'ר','ﬨ'=>'ת','ﺀ'=>'ء','ﺂ'=>'آ','ﺁ'=>'آ','ﺄ'=>'أ','ﺃ'=>'أ','ٵ'=>'أ','ﭑ'=>'ٱ','ﭐ'=>'ٱ','ﺆ'=>'ؤ','ﺅ'=>'ؤ','ٶ'=>'ؤ','ﺈ'=>'إ','ﺇ'=>'إ','ﺋ'=>'ئ','ﺌ'=>'ئ','ﺊ'=>'ئ','ﺉ'=>'ئ','ﯫ'=>'ئا','ﯪ'=>'ئا','ﯸ'=>'ئٻ','ﯷ'=>'ئٻ','ﯶ'=>'ئٻ','ﲗ'=>'ئج','ﰀ'=>'ئج','ﲘ'=>'ئح','ﰁ'=>'ئح','ﲙ'=>'ئخ','ﱤ'=>'ئر','ﱥ'=>'ئز','ﲚ'=>'ئم','ﳟ'=>'ئم','ﱦ'=>'ئم','ﰂ'=>'ئم','ﱧ'=>'ئن','ﲛ'=>'ئه','ﳠ'=>'ئه','ﯭ'=>'ئه','ﯬ'=>'ئه','ﯯ'=>'ئو','ﯮ'=>'ئو','ﯳ'=>'ئۆ','ﯲ'=>'ئۆ','ﯱ'=>'ئۇ','ﯰ'=>'ئۇ','ﯵ'=>'ئۈ','ﯴ'=>'ئۈ','ﯻ'=>'ئى','ﯺ'=>'ئى','ﱨ'=>'ئى','ﯹ'=>'ئى','ﰃ'=>'ئى','ﱩ'=>'ئى','ﰄ'=>'ئى','ﺎ'=>'ا','ﺍ'=>'ا','ﴼ'=>'اً','ﴽ'=>'اً','ﷳ'=>'اكبر','ﷲ'=>'الله','ﺑ'=>'ب','ﺒ'=>'ب','ﺐ'=>'ب','ﺏ'=>'ب','ﲜ'=>'بج','ﰅ'=>'بج','ﲝ'=>'بح','ﰆ'=>'بح','ﷂ'=>'بحى','ﲞ'=>'بخ','ﰇ'=>'بخ','ﶞ'=>'بخى','ﱪ'=>'بر','ﱫ'=>'بز','ﲟ'=>'بم','ﳡ'=>'بم','ﱬ'=>'بم','ﰈ'=>'بم','ﱭ'=>'بن','ﲠ'=>'به','ﳢ'=>'به','ﱮ'=>'بى','ﰉ'=>'بى','ﱯ'=>'بى','ﰊ'=>'بى','ﭔ'=>'ٻ','ﭕ'=>'ٻ','ﭓ'=>'ٻ','ﭒ'=>'ٻ','ې'=>'ٻ','ﯦ'=>'ٻ','ﯧ'=>'ٻ','ﯥ'=>'ٻ','ﯤ'=>'ٻ','ﭘ'=>'پ','ﭙ'=>'پ','ﭗ'=>'پ','ﭖ'=>'پ','ﭜ'=>'ڀ','ﭝ'=>'ڀ','ﭛ'=>'ڀ','ﭚ'=>'ڀ','ﺔ'=>'ة','ﺓ'=>'ة','ﺗ'=>'ت','ﺘ'=>'ت','ﺖ'=>'ت','ﺕ'=>'ت','ﲡ'=>'تج','ﰋ'=>'تج','ﵐ'=>'تجم','ﶠ'=>'تجى','ﶟ'=>'تجى','ﲢ'=>'تح','ﰌ'=>'تح','ﵒ'=>'تحج','ﵑ'=>'تحج','ﵓ'=>'تحم','ﲣ'=>'تخ','ﰍ'=>'تخ','ﵔ'=>'تخم','ﶢ'=>'تخى','ﶡ'=>'تخى','ﱰ'=>'تر','ﱱ'=>'تز','ﲤ'=>'تم','ﳣ'=>'تم','ﱲ'=>'تم','ﰎ'=>'تم','ﵕ'=>'تمج','ﵖ'=>'تمح','ﵗ'=>'تمخ','ﶤ'=>'تمى','ﶣ'=>'تمى','ﱳ'=>'تن','ﲥ'=>'ته','ﳤ'=>'ته','ﱴ'=>'تى','ﰏ'=>'تى','ﱵ'=>'تى','ﰐ'=>'تى','ﺛ'=>'ث','ﺜ'=>'ث','ﺚ'=>'ث','ﺙ'=>'ث','ﰑ'=>'ثج','ﱶ'=>'ثر','ﱷ'=>'ثز','ﲦ'=>'ثم','ﳥ'=>'ثم','ﱸ'=>'ثم','ﰒ'=>'ثم','ﱹ'=>'ثن','ﳦ'=>'ثه','ﱺ'=>'ثى','ﰓ'=>'ثى','ﱻ'=>'ثى','ﰔ'=>'ثى','ﭨ'=>'ٹ','ﭩ'=>'ٹ','ﭧ'=>'ٹ','ﭦ'=>'ٹ','ڻ'=>'ٹ','ﮢ'=>'ٹ','ﮣ'=>'ٹ','ﮡ'=>'ٹ','ﮠ'=>'ٹ','ﭠ'=>'ٺ','ﭡ'=>'ٺ','ﭟ'=>'ٺ','ﭞ'=>'ٺ','ﭤ'=>'ٿ','ﭥ'=>'ٿ','ﭣ'=>'ٿ','ﭢ'=>'ٿ','ﺟ'=>'ج','ﺠ'=>'ج','ﺞ'=>'ج','ﺝ'=>'ج','ﲧ'=>'جح','ﰕ'=>'جح','ﶦ'=>'جحى','ﶾ'=>'جحى','ﷻ'=>'جل جلاله','ﲨ'=>'جم','ﰖ'=>'جم','ﵙ'=>'جمح','ﵘ'=>'جمح','ﶧ'=>'جمى','ﶥ'=>'جمى','ﴝ'=>'جى','ﴁ'=>'جى','ﴞ'=>'جى','ﴂ'=>'جى','ﭸ'=>'ڃ','ﭹ'=>'ڃ','ﭷ'=>'ڃ','ﭶ'=>'ڃ','ﭴ'=>'ڄ','ﭵ'=>'ڄ','ﭳ'=>'ڄ','ﭲ'=>'ڄ','ﭼ'=>'چ','ﭽ'=>'چ','ﭻ'=>'چ','ﭺ'=>'چ','ﮀ'=>'ڇ','ﮁ'=>'ڇ','ﭿ'=>'ڇ','ﭾ'=>'ڇ','ﺣ'=>'ح','ﺤ'=>'ح','ﺢ'=>'ح','ﺡ'=>'ح','ﲩ'=>'حج','ﰗ'=>'حج','ﶿ'=>'حجى','ﲪ'=>'حم','ﰘ'=>'حم','ﵛ'=>'حمى','ﵚ'=>'حمى','ﴛ'=>'حى','ﳿ'=>'حى','ﴜ'=>'حى','ﴀ'=>'حى','ﺧ'=>'خ','ﺨ'=>'خ','ﺦ'=>'خ','ﺥ'=>'خ','ﲫ'=>'خج','ﰙ'=>'خج','ﰚ'=>'خح','ﲬ'=>'خم','ﰛ'=>'خم','ﴟ'=>'خى','ﴃ'=>'خى','ﴠ'=>'خى','ﴄ'=>'خى','ﺪ'=>'د','ﺩ'=>'د','ﺬ'=>'ذ','ﺫ'=>'ذ','ﱛ'=>'ذٰ','ﮉ'=>'ڈ','ﮈ'=>'ڈ','ﮅ'=>'ڌ','ﮄ'=>'ڌ','ﮃ'=>'ڍ','ﮂ'=>'ڍ','ﮇ'=>'ڎ','ﮆ'=>'ڎ','ﺮ'=>'ر','ﺭ'=>'ر','ﱜ'=>'رٰ','ﷶ'=>'رسول','﷼'=>'رىال','ﺰ'=>'ز','ﺯ'=>'ز','ﮍ'=>'ڑ','ﮌ'=>'ڑ','ﮋ'=>'ژ','ﮊ'=>'ژ','ﺳ'=>'س','ﺴ'=>'س','ﺲ'=>'س','ﺱ'=>'س','ﲭ'=>'سج','ﴴ'=>'سج','ﰜ'=>'سج','ﵝ'=>'سجح','ﵞ'=>'سجى','ﲮ'=>'سح','ﴵ'=>'سح','ﰝ'=>'سح','ﵜ'=>'سحج','ﲯ'=>'سخ','ﴶ'=>'سخ','ﰞ'=>'سخ','ﶨ'=>'سخى','ﷆ'=>'سخى','ﴪ'=>'سر','ﴎ'=>'سر','ﲰ'=>'سم','ﳧ'=>'سم','ﰟ'=>'سم','ﵡ'=>'سمج','ﵠ'=>'سمح','ﵟ'=>'سمح','ﵣ'=>'سمم','ﵢ'=>'سمم','ﴱ'=>'سه','ﳨ'=>'سه','ﴗ'=>'سى','ﳻ'=>'سى','ﴘ'=>'سى','ﳼ'=>'سى','ﺷ'=>'ش','ﺸ'=>'ش','ﺶ'=>'ش','ﺵ'=>'ش','ﴭ'=>'شج','ﴷ'=>'شج','ﴥ'=>'شج','ﴉ'=>'شج','ﵩ'=>'شجى','ﴮ'=>'شح','ﴸ'=>'شح','ﴦ'=>'شح','ﴊ'=>'شح','ﵨ'=>'شحم','ﵧ'=>'شحم','ﶪ'=>'شحى','ﴯ'=>'شخ','ﴹ'=>'شخ','ﴧ'=>'شخ','ﴋ'=>'شخ','ﴩ'=>'شر','ﴍ'=>'شر','ﴰ'=>'شم','ﳩ'=>'شم','ﴨ'=>'شم','ﴌ'=>'شم','ﵫ'=>'شمخ','ﵪ'=>'شمخ','ﵭ'=>'شمم','ﵬ'=>'شمم','ﴲ'=>'شه','ﳪ'=>'شه','ﴙ'=>'شى','ﳽ'=>'شى','ﴚ'=>'شى','ﳾ'=>'شى','ﺻ'=>'ص','ﺼ'=>'ص','ﺺ'=>'ص','ﺹ'=>'ص','ﲱ'=>'صح','ﰠ'=>'صح','ﵥ'=>'صحح','ﵤ'=>'صحح','ﶩ'=>'صحى','ﲲ'=>'صخ','ﴫ'=>'صر','ﴏ'=>'صر','ﷵ'=>'صلعم','ﷹ'=>'صلى','ﷺ'=>'صلى الله علىه وسلم','ﷰ'=>'صلے','ﲳ'=>'صم','ﰡ'=>'صم','ﷅ'=>'صمم','ﵦ'=>'صمم','ﴡ'=>'صى','ﴅ'=>'صى','ﴢ'=>'صى','ﴆ'=>'صى','ﺿ'=>'ض','ﻀ'=>'ض','ﺾ'=>'ض','ﺽ'=>'ض','ﲴ'=>'ضج','ﰢ'=>'ضج','ﲵ'=>'ضح','ﰣ'=>'ضح','ﵮ'=>'ضحى','ﶫ'=>'ضحى','ﲶ'=>'ضخ','ﰤ'=>'ضخ','ﵰ'=>'ضخم','ﵯ'=>'ضخم','ﴬ'=>'ضر','ﴐ'=>'ضر','ﲷ'=>'ضم','ﰥ'=>'ضم','ﴣ'=>'ضى','ﴇ'=>'ضى','ﴤ'=>'ضى','ﴈ'=>'ضى','ﻃ'=>'ط','ﻄ'=>'ط','ﻂ'=>'ط','ﻁ'=>'ط','ﲸ'=>'طح','ﰦ'=>'طح','ﴳ'=>'طم','ﴺ'=>'طم','ﰧ'=>'طم','ﵲ'=>'طمح','ﵱ'=>'طمح','ﵳ'=>'طمم','ﵴ'=>'طمى','ﴑ'=>'طى','ﳵ'=>'طى','ﴒ'=>'طى','ﳶ'=>'طى','ﻇ'=>'ظ','ﻈ'=>'ظ','ﻆ'=>'ظ','ﻅ'=>'ظ','ﲹ'=>'ظم','ﴻ'=>'ظم','ﰨ'=>'ظم','ﻋ'=>'ع','ﻌ'=>'ع','ﻊ'=>'ع','ﻉ'=>'ع','ﲺ'=>'عج','ﰩ'=>'عج','ﷄ'=>'عجم','ﵵ'=>'عجم','ﷷ'=>'علىه','ﲻ'=>'عم','ﰪ'=>'عم','ﵷ'=>'عمم','ﵶ'=>'عمم','ﵸ'=>'عمى','ﶶ'=>'عمى','ﴓ'=>'عى','ﳷ'=>'عى','ﴔ'=>'عى','ﳸ'=>'عى','ﻏ'=>'غ','ﻐ'=>'غ','ﻎ'=>'غ','ﻍ'=>'غ','ﲼ'=>'غج','ﰫ'=>'غج','ﲽ'=>'غم','ﰬ'=>'غم','ﵹ'=>'غمم','ﵻ'=>'غمى','ﵺ'=>'غمى','ﴕ'=>'غى','ﳹ'=>'غى','ﴖ'=>'غى','ﳺ'=>'غى','ﻓ'=>'ف','ﻔ'=>'ف','ﻒ'=>'ف','ﻑ'=>'ف','ﲾ'=>'فج','ﰭ'=>'فج','ﲿ'=>'فح','ﰮ'=>'فح','ﳀ'=>'فخ','ﰯ'=>'فخ','ﵽ'=>'فخم','ﵼ'=>'فخم','ﳁ'=>'فم','ﰰ'=>'فم','ﷁ'=>'فمى','ﱼ'=>'فى','ﰱ'=>'فى','ﱽ'=>'فى','ﰲ'=>'فى','ﭬ'=>'ڤ','ﭭ'=>'ڤ','ﭫ'=>'ڤ','ﭪ'=>'ڤ','ﭰ'=>'ڦ','ﭱ'=>'ڦ','ﭯ'=>'ڦ','ﭮ'=>'ڦ','ﻗ'=>'ق','ﻘ'=>'ق','ﻖ'=>'ق','ﻕ'=>'ق','ﳂ'=>'قح','ﰳ'=>'قح','ﷱ'=>'قلے','ﳃ'=>'قم','ﰴ'=>'قم','ﶴ'=>'قمح','ﵾ'=>'قمح','ﵿ'=>'قمم','ﶲ'=>'قمى','ﱾ'=>'قى','ﰵ'=>'قى','ﱿ'=>'قى','ﰶ'=>'قى','ﻛ'=>'ك','ﻜ'=>'ك','ﻚ'=>'ك','ﻙ'=>'ك','ک'=>'ك','ﮐ'=>'ك','ﮑ'=>'ك','ﮏ'=>'ك','ﮎ'=>'ك','ﲀ'=>'كا','ﰷ'=>'كا','ﳄ'=>'كج','ﰸ'=>'كج','ﳅ'=>'كح','ﰹ'=>'كح','ﳆ'=>'كخ','ﰺ'=>'كخ','ﳇ'=>'كل','ﳫ'=>'كل','ﲁ'=>'كل','ﰻ'=>'كل','ﳈ'=>'كم','ﳬ'=>'كم','ﲂ'=>'كم','ﰼ'=>'كم','ﷃ'=>'كمم','ﶻ'=>'كمم','ﶷ'=>'كمى','ﲃ'=>'كى','ﰽ'=>'كى','ﲄ'=>'كى','ﰾ'=>'كى','ﯕ'=>'ڭ','ﯖ'=>'ڭ','ﯔ'=>'ڭ','ﯓ'=>'ڭ','ﮔ'=>'گ','ﮕ'=>'گ','ﮓ'=>'گ','ﮒ'=>'گ','ﮜ'=>'ڱ','ﮝ'=>'ڱ','ﮛ'=>'ڱ','ﮚ'=>'ڱ','ﮘ'=>'ڳ','ﮙ'=>'ڳ','ﮗ'=>'ڳ','ﮖ'=>'ڳ','ﻟ'=>'ل','ﻠ'=>'ل','ﻞ'=>'ل','ﻝ'=>'ل','ﻶ'=>'لآ','ﻵ'=>'لآ','ﻸ'=>'لأ','ﻷ'=>'لأ','ﻺ'=>'لإ','ﻹ'=>'لإ','ﻼ'=>'لا','ﻻ'=>'لا','ﳉ'=>'لج','ﰿ'=>'لج','ﶃ'=>'لجج','ﶄ'=>'لجج','ﶺ'=>'لجم','ﶼ'=>'لجم','ﶬ'=>'لجى','ﳊ'=>'لح','ﱀ'=>'لح','ﶵ'=>'لحم','ﶀ'=>'لحم','ﶂ'=>'لحى','ﶁ'=>'لحى','ﳋ'=>'لخ','ﱁ'=>'لخ','ﶆ'=>'لخم','ﶅ'=>'لخم','ﳌ'=>'لم','ﳭ'=>'لم','ﲅ'=>'لم','ﱂ'=>'لم','ﶈ'=>'لمح','ﶇ'=>'لمح','ﶭ'=>'لمى','ﳍ'=>'له','ﲆ'=>'لى','ﱃ'=>'لى','ﲇ'=>'لى','ﱄ'=>'لى','ﻣ'=>'م','ﻤ'=>'م','ﻢ'=>'م','ﻡ'=>'م','ﲈ'=>'ما','ﳎ'=>'مج','ﱅ'=>'مج','ﶌ'=>'مجح','ﶒ'=>'مجخ','ﶍ'=>'مجم','ﷀ'=>'مجى','ﳏ'=>'مح','ﱆ'=>'مح','ﶉ'=>'محج','ﶊ'=>'محم','ﷴ'=>'محمد','ﶋ'=>'محى','ﳐ'=>'مخ','ﱇ'=>'مخ','ﶎ'=>'مخج','ﶏ'=>'مخم','ﶹ'=>'مخى','ﳑ'=>'مم','ﲉ'=>'مم','ﱈ'=>'مم','ﶱ'=>'ممى','ﱉ'=>'مى','ﱊ'=>'مى','ﻧ'=>'ن','ﻨ'=>'ن','ﻦ'=>'ن','ﻥ'=>'ن','ﳒ'=>'نج','ﱋ'=>'نج','ﶸ'=>'نجح','ﶽ'=>'نجح','ﶘ'=>'نجم','ﶗ'=>'نجم','ﶙ'=>'نجى','ﷇ'=>'نجى','ﳓ'=>'نح','ﱌ'=>'نح','ﶕ'=>'نحم','ﶖ'=>'نحى','ﶳ'=>'نحى','ﳔ'=>'نخ','ﱍ'=>'نخ','ﲊ'=>'نر','ﲋ'=>'نز','ﳕ'=>'نم','ﳮ'=>'نم','ﲌ'=>'نم','ﱎ'=>'نم','ﶛ'=>'نمى','ﶚ'=>'نمى','ﲍ'=>'نن','ﳖ'=>'نه','ﳯ'=>'نه','ﲎ'=>'نى','ﱏ'=>'نى','ﲏ'=>'نى','ﱐ'=>'نى','ﮟ'=>'ں','ﮞ'=>'ں','ﻫ'=>'ه','ﻬ'=>'ه','ﻪ'=>'ه','ﻩ'=>'ه','ھ'=>'ه','ﮬ'=>'ه','ﮭ'=>'ه','ﮫ'=>'ه','ﮪ'=>'ه','ہ'=>'ه','ﮨ'=>'ه','ﮩ'=>'ه','ﮧ'=>'ه','ﮦ'=>'ه','ە'=>'ه','ﳙ'=>'هٰ','ﳗ'=>'هج','ﱑ'=>'هج','ﳘ'=>'هم','ﱒ'=>'هم','ﶓ'=>'همج','ﶔ'=>'همم','ﱓ'=>'هى','ﱔ'=>'هى','ﮥ'=>'ۀ','ﮤ'=>'ۀ','ﻮ'=>'و','ﻭ'=>'و','ﷸ'=>'وسلم','ﯡ'=>'ۅ','ﯠ'=>'ۅ','ﯚ'=>'ۆ','ﯙ'=>'ۆ','ﯘ'=>'ۇ','ﯗ'=>'ۇ','ٷ'=>'ۇٔ','ﯝ'=>'ۇٔ','ﯜ'=>'ۈ','ﯛ'=>'ۈ','ﯣ'=>'ۉ','ﯢ'=>'ۉ','ﯟ'=>'ۋ','ﯞ'=>'ۋ','ﯨ'=>'ى','ﯩ'=>'ى','ﻰ'=>'ى','ﻯ'=>'ى','ي'=>'ى','ﻳ'=>'ى','ﻴ'=>'ى','ﻲ'=>'ى','ﻱ'=>'ى','ی'=>'ى','ﯾ'=>'ى','ﯿ'=>'ى','ﯽ'=>'ى','ﯼ'=>'ى','ٸ'=>'ىٔ','ﲐ'=>'ىٰ','ﱝ'=>'ىٰ','ﳚ'=>'ىج','ﱕ'=>'ىج','ﶯ'=>'ىجى','ﳛ'=>'ىح','ﱖ'=>'ىح','ﶮ'=>'ىحى','ﳜ'=>'ىخ','ﱗ'=>'ىخ','ﲑ'=>'ىر','ﲒ'=>'ىز','ﳝ'=>'ىم','ﳰ'=>'ىم','ﲓ'=>'ىم','ﱘ'=>'ىم','ﶝ'=>'ىمم','ﶜ'=>'ىمم','ﶰ'=>'ىمى','ﲔ'=>'ىن','ﳞ'=>'ىه','ﳱ'=>'ىه','ﲕ'=>'ىى','ﱙ'=>'ىى','ﲖ'=>'ىى','ﱚ'=>'ىى','ۧ'=>'ۦ','ﮯ'=>'ے','ﮮ'=>'ے','ﮱ'=>'ۓ','ﮰ'=>'ۓ','∃'=>'ⴺ','आ'=>'अा','ऒ'=>'अाॆ','ओ'=>'अाे','औ'=>'अाै','ऄ'=>'अॆ','ऑ'=>'अॉ','ऍ'=>'एॅ','ऎ'=>'एॆ','ऐ'=>'एे','ई'=>'र्इ','আ'=>'অা','ৠ'=>'ঋৃ','ৡ'=>'ঌৢ','ਉ'=>'ੳੁ','ਊ'=>'ੳੂ','ਆ'=>'ਅਾ','ਐ'=>'ਅੈ','ਔ'=>'ਅੌ','ਇ'=>'ੲਿ','ਈ'=>'ੲੀ','ਏ'=>'ੲੇ','આ'=>'અા','ઑ'=>'અાૅ','ઓ'=>'અાે','ઔ'=>'અાૈ','ઍ'=>'અૅ','એ'=>'અે','ઐ'=>'અૈ','ଆ'=>'ଅା','௮'=>'அ','ர'=>'ஈ','ா'=>'ஈ','௫'=>'ஈு','௨'=>'உ','ஊ'=>'உள','௭'=>'எ','௷'=>'எவ','ஜ'=>'ஐ','௧'=>'க','௪'=>'ச','௬'=>'சு','௲'=>'சூ','௺'=>'நீ','ை'=>'ன','௴'=>'மீ','௰'=>'ய','ௗ'=>'ள','௸'=>'ஷ','ொ'=>'ெஈ','ௌ'=>'ெள','ோ'=>'ேஈ','ౠ'=>'ఋా','ౡ'=>'ఌా','ఔ'=>'ఒౌ','ఓ'=>'ఒౕ','ఢ'=>'డ̣','భ'=>'బ̣','ష'=>'వ̣','హ'=>'వా','మ'=>'వు','ూ'=>'ుా','ౄ'=>'ృా','ೡ'=>'ಌಾ','ಔ'=>'ఒౌ','ഈ'=>'ഇൗ','ഊ'=>'உൗ','ഐ'=>'എെ','ഓ'=>'ഒാ','ഔ'=>'ഒൗ','ൡ'=>'ഞ','൫'=>'ദ്ര','ഌ'=>'നூ','ങ'=>'നூ','൯'=>'ന്','റ'=>'ര','൪'=>'ര്','൮'=>'വ്','ീ'=>'ி','ൂ'=>'ூ','ൃ'=>'ூ','ൈ'=>'െെ','ฃ'=>'ข','ด'=>'ค','ต'=>'ค','ม'=>'ฆ','ซ'=>'ช','ฏ'=>'ฎ','ท'=>'ฑ','ๅ'=>'า','ำ'=>'̊า','แ'=>'เเ','ໜ'=>'ຫນ','ໝ'=>'ຫມ','ຳ'=>'̊າ','ཷ'=>'ྲཱྀ','ཹ'=>'ླཱྀ','၀'=>'o','ឣ'=>'អ','᧐'=>'ᦞ','᭒'=>'ᬍ','᭓'=>'ᬑ','᭘'=>'ᬨ','ᢖ'=>'ᡜ','ᡕ'=>'ᠵ','Ꮢ'=>'Ꭱ','Ꮍ'=>'y','𝐀'=>'A','𝐴'=>'A','𝑨'=>'A','𝒜'=>'A','𝓐'=>'A','𝔄'=>'A','𝔸'=>'A','𝕬'=>'A','𝖠'=>'A','𝗔'=>'A','𝘈'=>'A','𝘼'=>'A','𝙰'=>'A','𝚨'=>'A','𝛢'=>'A','𝜜'=>'A','𝝖'=>'A','𝞐'=>'A','𝐉'=>'J','𝐽'=>'J','𝑱'=>'J','𝒥'=>'J','𝓙'=>'J','𝔍'=>'J','𝕁'=>'J','𝕵'=>'J','𝖩'=>'J','𝗝'=>'J','𝘑'=>'J','𝙅'=>'J','𝙹'=>'J','Ꮷ'=>'J','⋿'=>'E','ℰ'=>'E','𝐄'=>'E','𝐸'=>'E','𝑬'=>'E','𝓔'=>'E','𝔈'=>'E','𝔼'=>'E','𝕰'=>'E','𝖤'=>'E','𝗘'=>'E','𝘌'=>'E','𝙀'=>'E','𝙴'=>'E','𝚬'=>'E','𝛦'=>'E','𝜠'=>'E','𝝚'=>'E','𝞔'=>'E','ℾ'=>'Ꮁ','𝚪'=>'Ꮁ','𝛤'=>'Ꮁ','𝜞'=>'Ꮁ','𝝘'=>'Ꮁ','𝞒'=>'Ꮁ','Ꮤ'=>'w','ℳ'=>'M','𝐌'=>'M','𝑀'=>'M','𝑴'=>'M','𝓜'=>'M','𝔐'=>'M','𝕄'=>'M','𝕸'=>'M','𝖬'=>'M','𝗠'=>'M','𝘔'=>'M','𝙈'=>'M','𝙼'=>'M','𝚳'=>'M','𝛭'=>'M','𝜧'=>'M','𝝡'=>'M','𝞛'=>'M','ℋ'=>'H','ℌ'=>'H','ℍ'=>'H','𝐇'=>'H','𝐻'=>'H','𝑯'=>'H','𝓗'=>'H','𝕳'=>'H','𝖧'=>'H','𝗛'=>'H','𝘏'=>'H','𝙃'=>'H','𝙷'=>'H','𝚮'=>'H','𝛨'=>'H','𝜢'=>'H','𝝜'=>'H','𝞖'=>'H','𝐆'=>'G','𝐺'=>'G','𝑮'=>'G','𝒢'=>'G','𝓖'=>'G','𝔊'=>'G','𝔾'=>'G','𝕲'=>'G','𝖦'=>'G','𝗚'=>'G','𝘎'=>'G','𝙂'=>'G','𝙶'=>'G','Ᏻ'=>'G','ℤ'=>'Z','ℨ'=>'Z','𝐙'=>'Z','𝑍'=>'Z','𝒁'=>'Z','𝒵'=>'Z','𝓩'=>'Z','𝖅'=>'Z','𝖹'=>'Z','𝗭'=>'Z','𝘡'=>'Z','𝙕'=>'Z','𝚉'=>'Z','𝚭'=>'Z','𝛧'=>'Z','𝜡'=>'Z','𝝛'=>'Z','𝞕'=>'Z','𝐒'=>'S','𝑆'=>'S','𝑺'=>'S','𝒮'=>'S','𝓢'=>'S','𝔖'=>'S','𝕊'=>'S','𝕾'=>'S','𝖲'=>'S','𝗦'=>'S','𝘚'=>'S','𝙎'=>'S','𝚂'=>'S','Ꮪ'=>'S','𝐕'=>'V','𝑉'=>'V','𝑽'=>'V','𝒱'=>'V','𝓥'=>'V','𝔙'=>'V','𝕍'=>'V','𝖁'=>'V','𝖵'=>'V','𝗩'=>'V','𝘝'=>'V','𝙑'=>'V','𝚅'=>'V','ℒ'=>'L','𝐋'=>'L','𝐿'=>'L','𝑳'=>'L','𝓛'=>'L','𝔏'=>'L','𝕃'=>'L','𝕷'=>'L','𝖫'=>'L','𝗟'=>'L','𝘓'=>'L','𝙇'=>'L','𝙻'=>'L','∑'=>'C','⅀'=>'C','ℂ'=>'C','ℭ'=>'C','𝐂'=>'C','𝐶'=>'C','𝑪'=>'C','𝒞'=>'C','𝓒'=>'C','𝕮'=>'C','𝖢'=>'C','𝗖'=>'C','𝘊'=>'C','𝘾'=>'C','𝙲'=>'C','𝚺'=>'C','𝛴'=>'C','𝜮'=>'C','𝝨'=>'C','𝞢'=>'C','ℙ'=>'P','𝐏'=>'P','𝑃'=>'P','𝑷'=>'P','𝒫'=>'P','𝓟'=>'P','𝔓'=>'P','𝕻'=>'P','𝖯'=>'P','𝗣'=>'P','𝘗'=>'P','𝙋'=>'P','𝙿'=>'P','𝚸'=>'P','𝛲'=>'P','𝜬'=>'P','𝝦'=>'P','𝞠'=>'P','𝐊'=>'K','𝐾'=>'K','𝑲'=>'K','𝒦'=>'K','𝓚'=>'K','𝔎'=>'K','𝕂'=>'K','𝕶'=>'K','𝖪'=>'K','𝗞'=>'K','𝘒'=>'K','𝙆'=>'K','𝙺'=>'K','𝚱'=>'K','𝛫'=>'K','𝜥'=>'K','𝝟'=>'K','𝞙'=>'K','ℬ'=>'B','𝐁'=>'B','𝐵'=>'B','𝑩'=>'B','𝓑'=>'B','𝔅'=>'B','𝔹'=>'B','𝕭'=>'B','𝖡'=>'B','𝗕'=>'B','𝘉'=>'B','𝘽'=>'B','𝙱'=>'B','𝚩'=>'B','𝛣'=>'B','𝜝'=>'B','𝝗'=>'B','𝞑'=>'B','ᐍ'=>'ᐁ·','∆'=>'ᐃ','𝚫'=>'ᐃ','𝛥'=>'ᐃ','𝜟'=>'ᐃ','𝝙'=>'ᐃ','𝞓'=>'ᐃ','ᐏ'=>'ᐃ·','ᐑ'=>'ᐄ·','ᐓ'=>'ᐅ·','ᐕ'=>'ᐆ·','ᐘ'=>'ᐊ·','ᐚ'=>'ᐋ·','ᓑ'=>'ᐡ','ᑶ'=>'·P','ᑺ'=>'·d','ᒘ'=>'·J','ᑁ'=>'ᐳ·','ᑃ'=>'ᐴ·','ᑅ'=>'ᐸ·','ᑇ'=>'ᐹ·','ˈ'=>'ᑊ','ᑘ'=>'ᑌ·','ᑧ'=>'ᑌᑊ','ᑚ'=>'ᑎ·','ᑨ'=>'ᑎᑊ','ᑜ'=>'ᑏ·','ᑞ'=>'ᑐ·','ᑩ'=>'ᑐᑊ','ᑠ'=>'ᑑ·','ᑢ'=>'ᑕ·','ᑪ'=>'ᑕᑊ','ᑤ'=>'ᑖ·','ᑵ'=>'ᑫ·','ᒅ'=>'ᑫᑊ','ᑷ'=>'P·','ᒆ'=>'Pᑊ','ᑹ'=>'ᑮ·','ᑻ'=>'d·','ᒇ'=>'dᑊ','ᑽ'=>'ᑰ·','ᑿ'=>'ᑲ·','ᒈ'=>'ᑲᑊ','ᒁ'=>'ᑳ·','ᘃ'=>'ᒉ','ᒓ'=>'ᒉ·','ᒕ'=>'ᒋ·','ᒗ'=>'ᒌ·','ᒙ'=>'J·','ᒛ'=>'ᒎ·','ᘂ'=>'ᒐ','ᒝ'=>'ᒐ·','ᒟ'=>'ᒑ·','ᒭ'=>'ᒣ·','ᒯ'=>'ᒥ·','ᒱ'=>'ᒦ·','ᒳ'=>'ᒧ·','ᒵ'=>'ᒨ·','ᒹ'=>'ᒫ·','ᓊ'=>'ᓀ·','ᓌ'=>'ᓇ·','ᓎ'=>'ᓈᒫ','ᘄ'=>'ᓓ','ᓝ'=>'ᓓ·','ᓟ'=>'ᓕ·','ᓡ'=>'ᓖ·','ᓣ'=>'ᓗ·','ᓥ'=>'ᓘ·','ᘇ'=>'ᓚ','ᓧ'=>'ᓚ·','ᓩ'=>'ᓛ·','ᓷ'=>'ᓭ·','ᓹ'=>'ᓯ·','ᓻ'=>'ᓰ·','ᓽ'=>'ᓱ·','ᓿ'=>'ᓲ·','ᔁ'=>'ᓴ·','ᔃ'=>'ᓵ·','ᔌ'=>'ᔋᐸ','ᔍ'=>'ᔋᑕ','ᔎ'=>'ᔋᑲ','ᔏ'=>'ᔋᒐ','ᔘ'=>'ᔐ·','ᔚ'=>'ᔑ·','ᔜ'=>'ᔒ·','ᔞ'=>'ᔓ·','ᔠ'=>'ᔔ·','ᔢ'=>'ᔕ·','ᔤ'=>'ᔖ·','ᔲ'=>'ᔨ·','ᔴ'=>'ᔩ·','ᔶ'=>'ᔪ·','ᔸ'=>'ᔫ·','ᔺ'=>'ᔭ·','ᔼ'=>'ᔮ·','᙮'=>'x','ᕽ'=>'x','ᘢ'=>'ᕃ','ᘣ'=>'ᕆ','ᘤ'=>'ᕊ','ᕏ'=>'ᕌ·','ᙯ'=>'ᕐᑫ','ᕾ'=>'ᕐᑬ','ᕿ'=>'ᕐP','ᖀ'=>'ᕐᑮ','ᖁ'=>'ᕐd','ᖂ'=>'ᕐᑰ','ᖃ'=>'ᕐᑲ','ᖄ'=>'ᕐᑳ','ᖅ'=>'ᕐᒃ','ᕜ'=>'ᕚ·','ᕩ'=>'ᕧ·','ℛ'=>'R','ℜ'=>'R','ℝ'=>'R','𝐑'=>'R','𝑅'=>'R','𝑹'=>'R','𝓡'=>'R','𝕽'=>'R','𝖱'=>'R','𝗥'=>'R','𝘙'=>'R','𝙍'=>'R','𝚁'=>'R','ᙰ'=>'ᖕᒉ','ᖎ'=>'ᖕᒊ','ᖏ'=>'ᖕᒋ','ᖐ'=>'ᖕᒌ','ᖑ'=>'ᖕJ','ᖒ'=>'ᖕᒎ','ᖓ'=>'ᖕᒐ','ᖔ'=>'ᖕᒑ','ᙱ'=>'ᖖᒋ','ᙲ'=>'ᖖᒌ','ᙳ'=>'ᖖJ','ᙴ'=>'ᖖᒎ','ᙵ'=>'ᖖᒐ','ᙶ'=>'ᖖᒑ','ℱ'=>'F','𝐅'=>'F','𝐹'=>'F','𝑭'=>'F','𝓕'=>'F','𝔉'=>'F','𝔽'=>'F','𝕱'=>'F','𝖥'=>'F','𝗙'=>'F','𝘍'=>'F','𝙁'=>'F','𝙵'=>'F','𝟊'=>'F','ⅅ'=>'D','𝐃'=>'D','𝐷'=>'D','𝑫'=>'D','𝒟'=>'D','𝓓'=>'D','𝔇'=>'D','𝔻'=>'D','𝕯'=>'D','𝖣'=>'D','𝗗'=>'D','𝘋'=>'D','𝘿'=>'D','𝙳'=>'D','ᗪ'=>'D','℧'=>'ᘮ','ᘴ'=>'ᘮ','𝛀'=>'ᘯ','𝛺'=>'ᘯ','𝜴'=>'ᘯ','𝝮'=>'ᘯ','𝞨'=>'ᘯ','ᘵ'=>'ᘯ','ㄱ'=>'ᄀ','ᄀ'=>'ᄀ','ᆨ'=>'ᄀ','ㄲ'=>'ᄁ','ᄁ'=>'ᄁ','ᆩ'=>'ᄁ','ㄴ'=>'ᄂ','ᄂ'=>'ᄂ','ᆫ'=>'ᄂ','ㄷ'=>'ᄃ','ᄃ'=>'ᄃ','ᆮ'=>'ᄃ','ㄸ'=>'ᄄ','ᄄ'=>'ᄄ','ㄹ'=>'ᄅ','ᄅ'=>'ᄅ','ᆯ'=>'ᄅ','ㅁ'=>'ᄆ','ᄆ'=>'ᄆ','ᆷ'=>'ᄆ','ㅂ'=>'ᄇ','ᄇ'=>'ᄇ','ᆸ'=>'ᄇ','ㅃ'=>'ᄈ','ᄈ'=>'ᄈ','ㅅ'=>'ᄉ','ᄉ'=>'ᄉ','ᆺ'=>'ᄉ','ㅆ'=>'ᄊ','ᄊ'=>'ᄊ','ᆻ'=>'ᄊ','ㅇ'=>'ᄋ','ᄋ'=>'ᄋ','ᆼ'=>'ᄋ','ㅈ'=>'ᄌ','ᄌ'=>'ᄌ','ᆽ'=>'ᄌ','ㅉ'=>'ᄍ','ᄍ'=>'ᄍ','ㅊ'=>'ᄎ','ᄎ'=>'ᄎ','ᆾ'=>'ᄎ','ㅋ'=>'ᄏ','ᄏ'=>'ᄏ','ᆿ'=>'ᄏ','ㅌ'=>'ᄐ','ᄐ'=>'ᄐ','ᇀ'=>'ᄐ','ㅍ'=>'ᄑ','ᄑ'=>'ᄑ','ᇁ'=>'ᄑ','ㅎ'=>'ᄒ','ᄒ'=>'ᄒ','ᇂ'=>'ᄒ','ᇅ'=>'ᄓ','ㅥ'=>'ᄔ','ㅦ'=>'ᄕ','ᇆ'=>'ᄕ','ᇊ'=>'ᄗ','ᇍ'=>'ᄘ','ᇐ'=>'ᄙ','ㅀ'=>'ᄚ','ᄚ'=>'ᄚ','ᄻ'=>'ᄚ','ᆶ'=>'ᄚ','ㅮ'=>'ᄜ','ᇜ'=>'ᄜ','ㅱ'=>'ᄝ','ᇢ'=>'ᄝ','ㅲ'=>'ᄞ','ㅳ'=>'ᄠ','ㅄ'=>'ᄡ','ᄡ'=>'ᄡ','ᆹ'=>'ᄡ','ㅴ'=>'ᄢ','ㅵ'=>'ᄣ','ㅶ'=>'ᄧ','ㅷ'=>'ᄩ','ㅸ'=>'ᄫ','ᇦ'=>'ᄫ','ㅹ'=>'ᄬ','ㅺ'=>'ᄭ','ᇧ'=>'ᄭ','ㅻ'=>'ᄮ','ㅼ'=>'ᄯ','ᇨ'=>'ᄯ','ᇩ'=>'ᄰ','ㅽ'=>'ᄲ','ᇪ'=>'ᄲ','ㅾ'=>'ᄶ','ㅿ'=>'ᅀ','ᇫ'=>'ᅀ','ᇬ'=>'ᅁ','ᇱ'=>'ᅅ','ㆂ'=>'ᅅ','ᇲ'=>'ᅆ','ㆃ'=>'ᅆ','ㆀ'=>'ᅇ','ᇮ'=>'ᅇ','ㆁ'=>'ᅌ','ᇰ'=>'ᅌ','ᇳ'=>'ᅖ','ㆄ'=>'ᅗ','ᇴ'=>'ᅗ','ㆅ'=>'ᅘ','ㆆ'=>'ᅙ','ᇹ'=>'ᅙ','ㅤ'=>'ᅠ','ᅠ'=>'ᅠ','ㅏ'=>'ᅡ','ᅡ'=>'ᅡ','ㅐ'=>'ᅢ','ᅢ'=>'ᅢ','ㅑ'=>'ᅣ','ᅣ'=>'ᅣ','ㅒ'=>'ᅤ','ᅤ'=>'ᅤ','ㅓ'=>'ᅥ','ᅥ'=>'ᅥ','ㅔ'=>'ᅦ','ᅦ'=>'ᅦ','ㅕ'=>'ᅧ','ᅧ'=>'ᅧ','ㅖ'=>'ᅨ','ᅨ'=>'ᅨ','ㅗ'=>'ᅩ','ᅩ'=>'ᅩ','ㅘ'=>'ᅪ','ᅪ'=>'ᅪ','ㅙ'=>'ᅫ','ᅫ'=>'ᅫ','ㅚ'=>'ᅬ','ᅬ'=>'ᅬ','ㅛ'=>'ᅭ','ᅭ'=>'ᅭ','ㅜ'=>'ᅮ','ᅮ'=>'ᅮ','ㅝ'=>'ᅯ','ᅯ'=>'ᅯ','ㅞ'=>'ᅰ','ᅰ'=>'ᅰ','ㅟ'=>'ᅱ','ᅱ'=>'ᅱ','ㅠ'=>'ᅲ','ᅲ'=>'ᅲ','ㅡ'=>'一','ᅳ'=>'一','ㅢ'=>'ᅴ','ᅴ'=>'ᅴ','ㅣ'=>'丨','ᅵ'=>'丨','ㆇ'=>'ᆄ','ᆆ'=>'ᆄ','ㆈ'=>'ᆅ','ㆉ'=>'ᆈ','ㆊ'=>'ᆑ','ㆋ'=>'ᆒ','ㆌ'=>'ᆔ','ㆍ'=>'ᆞ','ㆎ'=>'ᆡ','ㄳ'=>'ᆪ','ᆪ'=>'ᆪ','ㄵ'=>'ᆬ','ᆬ'=>'ᆬ','ㄶ'=>'ᆭ','ᆭ'=>'ᆭ','ㄺ'=>'ᆰ','ᆰ'=>'ᆰ','ㄻ'=>'ᆱ','ᆱ'=>'ᆱ','ㄼ'=>'ᆲ','ᆲ'=>'ᆲ','ㄽ'=>'ᆳ','ᆳ'=>'ᆳ','ㄾ'=>'ᆴ','ᆴ'=>'ᆴ','ㄿ'=>'ᆵ','ᆵ'=>'ᆵ','ㅧ'=>'ᇇ','ㅨ'=>'ᇈ','ㅩ'=>'ᇌ','ㅪ'=>'ᇎ','ㅫ'=>'ᇓ','ㅬ'=>'ᇗ','ㅭ'=>'ᇙ','ㅯ'=>'ᇝ','ㅰ'=>'ᇟ','ァ'=>'ァ','ア'=>'ア','ィ'=>'ィ','イ'=>'イ','ゥ'=>'ゥ','ウ'=>'ウ','ェ'=>'ェ','エ'=>'エ','ォ'=>'ォ','オ'=>'オ','カ'=>'カ','キ'=>'キ','ク'=>'ク','ケ'=>'ケ','コ'=>'コ','サ'=>'サ','シ'=>'シ','ス'=>'ス','セ'=>'セ','ソ'=>'ソ','タ'=>'タ','チ'=>'チ','ッ'=>'ッ','ツ'=>'ツ','テ'=>'テ','ト'=>'ト','ナ'=>'ナ','ニ'=>'ニ','ヌ'=>'ヌ','ネ'=>'ネ','ノ'=>'ノ','ハ'=>'ハ','ヒ'=>'ヒ','フ'=>'フ','ヘ'=>'へ','ホ'=>'ホ','マ'=>'マ','⧄'=>'〼','ミ'=>'ミ','ム'=>'ム','メ'=>'メ','モ'=>'モ','ャ'=>'ャ','ヤ'=>'ヤ','ュ'=>'ュ','ユ'=>'ユ','ョ'=>'ョ','ヨ'=>'ヨ','ラ'=>'ラ','リ'=>'リ','ル'=>'ル','レ'=>'レ','ロ'=>'ロ','ワ'=>'ワ','ヲ'=>'ヲ','ン'=>'ン','꒞'=>'ꁊ','꒬'=>'ꁐ','꒜'=>'ꃀ','꒿'=>'ꉙ','꒾'=>'ꊱ','꓀'=>'ꎫ','꓂'=>'ꎵ','꒺'=>'ꎿ','꒰'=>'ꏂ','𐒠'=>'𐒆','—'=>'一','―'=>'一','−'=>'一','─'=>'一','⼀'=>'一','不'=>'不','並'=>'並','|'=>'丨','|'=>'丨','∣'=>'丨','⼁'=>'丨','‖'=>'丨丨','∥'=>'丨丨','串'=>'串','⼂'=>'丶','丸'=>'丸','丹'=>'丹','丽'=>'丽','⼃'=>'丿','乁'=>'乁','⼄'=>'乙','亂'=>'亂','⼅'=>'亅','了'=>'了','⼆'=>'二','⼇'=>'亠','亮'=>'亮','⼈'=>'人','什'=>'什','仌'=>'仌','令'=>'令','你'=>'你','倂'=>'併','倂'=>'併','侀'=>'侀','來'=>'來','例'=>'例','侮'=>'侮','侮'=>'侮','侻'=>'侻','便'=>'便','值'=>'値','倫'=>'倫','偺'=>'偺','備'=>'備','像'=>'像','僚'=>'僚','僧'=>'僧','僧'=>'僧','⼉'=>'儿','兀'=>'兀','充'=>'充','免'=>'免','免'=>'免','兔'=>'兔','兤'=>'兤','⼊'=>'入','內'=>'內','全'=>'全','兩'=>'兩','⼋'=>'八','六'=>'六','具'=>'具','冀'=>'冀','⼌'=>'冂','再'=>'再','冒'=>'冒','冕'=>'冕','⼍'=>'冖','冗'=>'冗','冤'=>'冤','⼎'=>'冫','冬'=>'冬','况'=>'况','况'=>'况','冷'=>'冷','凉'=>'凉','凌'=>'凌','凜'=>'凜','凞'=>'凞','⼏'=>'几','凵'=>'凵','⼐'=>'凵','⼑'=>'刀','刃'=>'刃','切'=>'切','切'=>'切','列'=>'列','利'=>'利','刺'=>'刺','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','劉'=>'劉','力'=>'力','⼒'=>'力','劣'=>'劣','劳'=>'劳','勇'=>'勇','勇'=>'勇','勉'=>'勉','勉'=>'勉','勒'=>'勒','勞'=>'勞','勤'=>'勤','勤'=>'勤','勵'=>'勵','⼓'=>'勹','勺'=>'勺','勺'=>'勺','包'=>'包','匆'=>'匆','⼔'=>'匕','北'=>'北','北'=>'北','⼕'=>'匚','⼖'=>'匸','匿'=>'匿','⼗'=>'十','〸'=>'十','〹'=>'卄','〺'=>'卅','卉'=>'卉','卑'=>'卑','卑'=>'卑','博'=>'博','⼘'=>'卜','⼙'=>'卩','即'=>'即','卵'=>'卵','卽'=>'卽','卿'=>'卿','卿'=>'卿','卿'=>'卿','⼚'=>'厂','⼛'=>'厶','參'=>'參','⼜'=>'又','及'=>'及','叟'=>'叟','⼝'=>'口','句'=>'句','叫'=>'叫','叱'=>'叱','吆'=>'吆','吏'=>'吏','吝'=>'吝','吸'=>'吸','呂'=>'呂','呈'=>'呈','周'=>'周','咞'=>'咞','咢'=>'咢','咽'=>'咽','哶'=>'哶','唐'=>'唐','啓'=>'啓','啟'=>'啓','啕'=>'啕','啣'=>'啣','善'=>'善','善'=>'善','喇'=>'喇','喙'=>'喙','喙'=>'喙','喝'=>'喝','喝'=>'喝','喫'=>'喫','喳'=>'喳','嗀'=>'嗀','嗂'=>'嗂','嗢'=>'嗢','嘆'=>'嘆','嘆'=>'嘆','噑'=>'噑','器'=>'器','噴'=>'噴','⼞'=>'囗','囹'=>'囹','圖'=>'圖','圗'=>'圗','⼟'=>'土','型'=>'型','城'=>'城','埴'=>'埴','堍'=>'堍','報'=>'報','堲'=>'堲','塀'=>'塀','塚'=>'塚','塚'=>'塚','塞'=>'塞','填'=>'塡','墨'=>'墨','壿'=>'墫','墬'=>'墬','墳'=>'墳','壘'=>'壘','壟'=>'壟','⼠'=>'士','壮'=>'壮','売'=>'売','壷'=>'壷','⼡'=>'夂','夆'=>'夆','⼢'=>'夊','⼣'=>'夕','多'=>'多','夢'=>'夢','⼤'=>'大','奄'=>'奄','奈'=>'奈','契'=>'契','奔'=>'奔','奢'=>'奢','女'=>'女','⼥'=>'女','姘'=>'姘','姬'=>'姬','娛'=>'娛','娧'=>'娧','婢'=>'婢','婦'=>'婦','嬀'=>'媯','媵'=>'媵','嬈'=>'嬈','嬨'=>'嬨','嬾'=>'嬾','嬾'=>'嬾','⼦'=>'子','⼧'=>'宀','宅'=>'宅','寃'=>'寃','寘'=>'寘','寧'=>'寧','寧'=>'寧','寧'=>'寧','寮'=>'寮','寳'=>'寳','⼨'=>'寸','寿'=>'寿','将'=>'将','⼩'=>'小','尢'=>'尢','⼪'=>'尢','⼫'=>'尸','尿'=>'尿','屠'=>'屠','屢'=>'屢','層'=>'層','履'=>'履','屮'=>'屮','屮'=>'屮','⼬'=>'屮','⼭'=>'山','岍'=>'岍','峀'=>'峀','崙'=>'崙','嵃'=>'嵃','嵐'=>'嵐','嵫'=>'嵫','嵮'=>'嵮','嵼'=>'嵼','嶲'=>'嶲','嶺'=>'嶺','⼮'=>'巛','巡'=>'巡','巢'=>'巢','⼯'=>'工','⼰'=>'己','巽'=>'巽','⼱'=>'巾','帲'=>'帡','帨'=>'帨','帽'=>'帽','幩'=>'幩','⼲'=>'干','年'=>'年','⼳'=>'幺','⼴'=>'广','度'=>'度','庰'=>'庰','庳'=>'庳','庶'=>'庶','廉'=>'廉','廊'=>'廊','廊'=>'廊','廒'=>'廒','廓'=>'廓','廙'=>'廙','廬'=>'廬','⼵'=>'廴','廾'=>'廾','⼶'=>'廾','弄'=>'弄','⼷'=>'弋','⼸'=>'弓','弢'=>'弢','弢'=>'弢','⼹'=>'彐','当'=>'当','⼺'=>'彡','形'=>'形','彩'=>'彩','彫'=>'彫','⼻'=>'彳','律'=>'律','徚'=>'徚','復'=>'復','徭'=>'徭','⼼'=>'心','忍'=>'忍','志'=>'志','念'=>'念','忹'=>'忹','怒'=>'怒','怜'=>'怜','悁'=>'悁','悔'=>'悔','悔'=>'悔','惇'=>'惇','惘'=>'惘','惡'=>'惡','愈'=>'愈','慄'=>'慄','慈'=>'慈','慌'=>'慌','慌'=>'慌','慎'=>'慎','慎'=>'慎','慠'=>'慠','慨'=>'慨','慺'=>'慺','憎'=>'憎','憎'=>'憎','憎'=>'憎','憐'=>'憐','憤'=>'憤','憯'=>'憯','憲'=>'憲','懞'=>'懞','懲'=>'懲','懲'=>'懲','懲'=>'懲','懶'=>'懶','懶'=>'懶','戀'=>'戀','⼽'=>'戈','成'=>'成','戛'=>'戛','戮'=>'戮','戴'=>'戴','⼾'=>'戶','⼿'=>'手','扝'=>'扝','抱'=>'抱','拉'=>'拉','拏'=>'拏','拓'=>'拓','拔'=>'拔','拼'=>'拼','拾'=>'拾','挽'=>'挽','捐'=>'捐','捨'=>'捨','捻'=>'捻','掃'=>'掃','掠'=>'掠','掩'=>'掩','揄'=>'揄','揅'=>'揅','揤'=>'揤','㩁'=>'搉','搜'=>'搜','搢'=>'搢','摒'=>'摒','摩'=>'摩','摷'=>'摷','摾'=>'摾','撚'=>'撚','撝'=>'撝','擄'=>'擄','⽀'=>'支','⽁'=>'攴','敏'=>'敏','敏'=>'敏','敖'=>'敖','敬'=>'敬','數'=>'數','⽂'=>'文','⽃'=>'斗','料'=>'料','⽄'=>'斤','⽅'=>'方','旅'=>'旅','⽆'=>'无','既'=>'既','旣'=>'旣','⽇'=>'日','易'=>'易','晉'=>'晉','晩'=>'晚','䀿'=>'晣','晴'=>'晴','晴'=>'晴','暈'=>'暈','暑'=>'暑','暑'=>'暑','暜'=>'暜','暴'=>'暴','曆'=>'曆','⽈'=>'曰','更'=>'更','㫚'=>'曶','書'=>'書','最'=>'最','⽉'=>'月','肦'=>'朌','胐'=>'朏','胊'=>'朐','脁'=>'朓','朗'=>'朗','朗'=>'朗','朗'=>'朗','脧'=>'朘','望'=>'望','望'=>'望','朡'=>'朡','膧'=>'朣','⽊'=>'木','李'=>'李','杓'=>'杓','杖'=>'杖','杞'=>'杞','柿'=>'杮','杻'=>'杻','枅'=>'枅','林'=>'林','柳'=>'柳','柺'=>'柺','栗'=>'栗','栟'=>'栟','桒'=>'桒','梁'=>'梁','梅'=>'梅','梅'=>'梅','梎'=>'梎','梨'=>'梨','椔'=>'椔','楂'=>'楂','樧'=>'榝','榣'=>'榣','槪'=>'槪','樂'=>'樂','樂'=>'樂','樂'=>'樂','樓'=>'樓','檨'=>'檨','櫓'=>'櫓','櫛'=>'櫛','欄'=>'欄','⽋'=>'欠','次'=>'次','歔'=>'歔','⽌'=>'止','歲'=>'歲','歷'=>'歷','歹'=>'歹','⽍'=>'歹','殟'=>'殟','殮'=>'殮','⽎'=>'殳','殺'=>'殺','殺'=>'殺','殺'=>'殺','殻'=>'殻','⽏'=>'毋','⺟'=>'母','⽐'=>'比','⽑'=>'毛','⽒'=>'氏','⽓'=>'气','⽔'=>'水','汎'=>'汎','汧'=>'汧','沈'=>'沈','沿'=>'沿','泌'=>'泌','泍'=>'泍','泥'=>'泥','洖'=>'洖','洛'=>'洛','洞'=>'洞','洴'=>'洴','派'=>'派','流'=>'流','流'=>'流','流'=>'流','浩'=>'浩','浪'=>'浪','海'=>'海','海'=>'海','浸'=>'浸','涅'=>'涅','淋'=>'淋','淚'=>'淚','淪'=>'淪','淹'=>'淹','渚'=>'渚','港'=>'港','湮'=>'湮','潙'=>'溈','溜'=>'溜','溺'=>'溺','滇'=>'滇','滋'=>'滋','滋'=>'滋','滑'=>'滑','滛'=>'滛','漏'=>'漏','漢'=>'漢','漢'=>'漢','漣'=>'漣','潮'=>'潮','濆'=>'濆','濫'=>'濫','濾'=>'濾','瀛'=>'瀛','瀞'=>'瀞','瀞'=>'瀞','瀹'=>'瀹','灊'=>'灊','⽕'=>'火','灰'=>'灰','灷'=>'灷','災'=>'災','炙'=>'炙','炭'=>'炭','烈'=>'烈','烙'=>'烙','煅'=>'煅','煉'=>'煉','煮'=>'煮','煮'=>'煮','熜'=>'熜','燎'=>'燎','燐'=>'燐','爐'=>'爐','爛'=>'爛','爨'=>'爨','⽖'=>'爪','爫'=>'爫','⺤'=>'爫','爵'=>'爵','爵'=>'爵','⽗'=>'父','⽘'=>'爻','⽙'=>'爿','⽚'=>'片','牐'=>'牐','⽛'=>'牙','⽜'=>'牛','牢'=>'牢','犀'=>'犀','犕'=>'犕','⽝'=>'犬','犯'=>'犯','狀'=>'狀','狼'=>'狼','猪'=>'猪','猪'=>'猪','獵'=>'獵','獺'=>'獺','⽞'=>'玄','率'=>'率','率'=>'率','⽟'=>'玉','王'=>'王','玥'=>'玥','玲'=>'玲','珞'=>'珞','理'=>'理','琉'=>'琉','琢'=>'琢','瑇'=>'瑇','瑜'=>'瑜','瑩'=>'瑩','瑱'=>'瑱','瑱'=>'瑱','璅'=>'璅','璉'=>'璉','璘'=>'璘','瓊'=>'瓊','⽠'=>'瓜','⽡'=>'瓦','甆'=>'甆','⽢'=>'甘','⽣'=>'生','甤'=>'甤','⽤'=>'用','⽥'=>'田','画'=>'画','甾'=>'甾','留'=>'留','略'=>'略','異'=>'異','異'=>'異','⽦'=>'疋','⽧'=>'疒','痢'=>'痢','瘐'=>'瘐','瘝'=>'瘝','瘟'=>'瘟','療'=>'療','癩'=>'癩','⽨'=>'癶','⽩'=>'白','⽪'=>'皮','⽫'=>'皿','益'=>'益','益'=>'益','盛'=>'盛','盧'=>'盧','⽬'=>'目','直'=>'直','直'=>'直','省'=>'省','眞'=>'眞','真'=>'真','真'=>'真','着'=>'着','睊'=>'睊','睊'=>'睊','瞋'=>'瞋','瞧'=>'瞧','⽭'=>'矛','⽮'=>'矢','⽯'=>'石','硏'=>'研','硎'=>'硎','硫'=>'硫','碌'=>'碌','碌'=>'碌','碑'=>'碑','磊'=>'磊','磌'=>'磌','磌'=>'磌','磻'=>'磻','礪'=>'礪','⽰'=>'示','礼'=>'礼','社'=>'社','祈'=>'祈','祉'=>'祉','祐'=>'祐','祖'=>'祖','祖'=>'祖','祝'=>'祝','神'=>'神','祥'=>'祥','祿'=>'祿','禍'=>'禍','禎'=>'禎','福'=>'福','福'=>'福','禮'=>'禮','⽱'=>'禸','⽲'=>'禾','秊'=>'秊','秫'=>'秫','稜'=>'稜','穀'=>'穀','穀'=>'穀','穊'=>'穊','穏'=>'穏','⽳'=>'穴','突'=>'突','窱'=>'窱','立'=>'立','⽴'=>'立','竮'=>'竮','⽵'=>'竹','笠'=>'笠','節'=>'節','節'=>'節','篆'=>'篆','築'=>'築','簾'=>'簾','籠'=>'籠','⽶'=>'米','类'=>'类','粒'=>'粒','精'=>'精','糒'=>'糒','糖'=>'糖','糣'=>'糣','糧'=>'糧','糨'=>'糨','⽷'=>'糸','紀'=>'紀','紐'=>'紐','索'=>'索','累'=>'累','絶'=>'絕','絛'=>'絛','絣'=>'絣','綠'=>'綠','綾'=>'綾','緇'=>'緇','練'=>'練','練'=>'練','練'=>'練','縂'=>'縂','縉'=>'縉','縷'=>'縷','繁'=>'繁','繅'=>'繅','⽸'=>'缶','缾'=>'缾','⽹'=>'网','⺫'=>'罒','署'=>'署','罹'=>'罹','罺'=>'罺','羅'=>'羅','⽺'=>'羊','羕'=>'羕','羚'=>'羚','羽'=>'羽','⽻'=>'羽','翺'=>'翺','老'=>'老','⽼'=>'老','者'=>'者','者'=>'者','者'=>'者','⽽'=>'而','⽾'=>'耒','⽿'=>'耳','聆'=>'聆','聠'=>'聠','聯'=>'聯','聰'=>'聰','聾'=>'聾','⾀'=>'聿','⾁'=>'肉','肋'=>'肋','肭'=>'肭','育'=>'育','㬵'=>'胶','腁'=>'胼','脃'=>'脃','脾'=>'脾','臘'=>'臘','⾂'=>'臣','臨'=>'臨','⾃'=>'自','臭'=>'臭','⾄'=>'至','⾅'=>'臼','舁'=>'舁','舁'=>'舁','舄'=>'舄','⾆'=>'舌','⾇'=>'舛','⾈'=>'舟','⾉'=>'艮','良'=>'良','⾊'=>'色','⾋'=>'艸','艹'=>'艹','艹'=>'艹','芋'=>'芋','芑'=>'芑','芝'=>'芝','花'=>'花','芳'=>'芳','芽'=>'芽','若'=>'若','若'=>'若','苦'=>'苦','茝'=>'茝','茣'=>'茣','茶'=>'茶','荒'=>'荒','荓'=>'荓','荣'=>'荣','莭'=>'莭','莽'=>'莽','菉'=>'菉','菊'=>'菊','菌'=>'菌','菜'=>'菜','菧'=>'菧','華'=>'華','菱'=>'菱','落'=>'落','葉'=>'葉','著'=>'著','著'=>'著','蔿'=>'蒍','蓮'=>'蓮','蓱'=>'蓱','蓳'=>'蓳','蓼'=>'蓼','蔖'=>'蔖','蕤'=>'蕤','藍'=>'藍','藺'=>'藺','蘆'=>'蘆','蘒'=>'蘒','蘭'=>'蘭','虁'=>'蘷','蘿'=>'蘿','⾌'=>'虍','虐'=>'虐','虜'=>'虜','虜'=>'虜','虧'=>'虧','虩'=>'虩','⾍'=>'虫','蚈'=>'蚈','蚩'=>'蚩','蛢'=>'蛢','蜎'=>'蜎','蜨'=>'蜨','蝫'=>'蝫','蝹'=>'蝹','蝹'=>'蝹','螆'=>'螆','螺'=>'螺','蟡'=>'蟡','蠁'=>'蠁','蠟'=>'蠟','⾎'=>'血','行'=>'行','⾏'=>'行','衠'=>'衠','衣'=>'衣','⾐'=>'衣','裂'=>'裂','裏'=>'裏','裗'=>'裗','裞'=>'裞','裡'=>'裡','裸'=>'裸','裺'=>'裺','褐'=>'褐','襁'=>'襁','襤'=>'襤','⾑'=>'襾','覆'=>'覆','見'=>'見','⾒'=>'見','視'=>'視','視'=>'視','⾓'=>'角','⾔'=>'言','䚶'=>'訞','詽'=>'訮','誠'=>'誠','說'=>'說','說'=>'說','調'=>'調','請'=>'請','諒'=>'諒','論'=>'論','諭'=>'諭','諭'=>'諭','諸'=>'諸','諸'=>'諸','諾'=>'諾','諾'=>'諾','謁'=>'謁','謁'=>'謁','謹'=>'謹','謹'=>'謹','識'=>'識','讀'=>'讀','讏'=>'讆','變'=>'變','變'=>'變','⾕'=>'谷','⾖'=>'豆','豈'=>'豈','豕'=>'豕','⾗'=>'豕','⾘'=>'豸','⾙'=>'貝','貫'=>'貫','賁'=>'賁','賂'=>'賂','賈'=>'賈','賓'=>'賓','贈'=>'贈','贈'=>'贈','贛'=>'贛','⾚'=>'赤','⾛'=>'走','起'=>'起','趆'=>'赿','⾜'=>'足','趼'=>'趼','跋'=>'跋','跺'=>'跥','路'=>'路','跰'=>'跰','躛'=>'躗','⾝'=>'身','車'=>'車','⾞'=>'車','軔'=>'軔','輧'=>'軿','輦'=>'輦','輪'=>'輪','輸'=>'輸','輸'=>'輸','輻'=>'輻','轢'=>'轢','⾟'=>'辛','辞'=>'辞','辰'=>'辰','⾠'=>'辰','⾡'=>'辵','辶'=>'辶','⻌'=>'辶','連'=>'連','逸'=>'逸','逸'=>'逸','遲'=>'遲','遼'=>'遼','邏'=>'邏','⾢'=>'邑','邔'=>'邔','郎'=>'郎','郱'=>'郱','都'=>'都','鄑'=>'鄑','鄛'=>'鄛','⾣'=>'酉','酪'=>'酪','醙'=>'醙','醴'=>'醴','⾤'=>'釆','里'=>'里','⾥'=>'里','量'=>'量','金'=>'金','⾦'=>'金','鈴'=>'鈴','鈸'=>'鈸','鉶'=>'鉶','鉼'=>'鉼','鋗'=>'鋗','鋘'=>'鋘','錄'=>'錄','鍊'=>'鍊','鎮'=>'鎭','鏹'=>'鏹','鐕'=>'鐕','⾧'=>'長','⾨'=>'門','開'=>'開','閭'=>'閭','閷'=>'閷','⾩'=>'阜','阮'=>'阮','陋'=>'陋','降'=>'降','陵'=>'陵','陸'=>'陸','陼'=>'陼','隆'=>'隆','隣'=>'隣','⾪'=>'隶','隸'=>'隸','⾫'=>'隹','雃'=>'雃','離'=>'離','難'=>'難','難'=>'難','⾬'=>'雨','零'=>'零','雷'=>'雷','霣'=>'霣','露'=>'露','靈'=>'靈','⾭'=>'靑','靖'=>'靖','靖'=>'靖','⾮'=>'非','⾯'=>'面','⾰'=>'革','⾱'=>'韋','韛'=>'韛','韠'=>'韠','⾲'=>'韭','⾳'=>'音','響'=>'響','響'=>'響','⾴'=>'頁','頋'=>'頋','頋'=>'頋','頋'=>'頋','領'=>'領','頩'=>'頩','頻'=>'頻','頻'=>'頻','類'=>'類','⾵'=>'風','⾶'=>'飛','⻝'=>'食','⾷'=>'食','飢'=>'飢','飯'=>'飯','飼'=>'飼','館'=>'館','餩'=>'餩','⾸'=>'首','⾹'=>'香','馧'=>'馧','⾺'=>'馬','駂'=>'駂','駱'=>'駱','駾'=>'駾','驪'=>'驪','⾻'=>'骨','⾼'=>'高','⾽'=>'髟','鬒'=>'鬒','鬒'=>'鬒','⾾'=>'鬥','⾿'=>'鬯','⿀'=>'鬲','⿁'=>'鬼','⿂'=>'魚','魯'=>'魯','鱀'=>'鱀','鱗'=>'鱗','⿃'=>'鳥','鳽'=>'鳽','鵧'=>'鵧','鶴'=>'鶴','鷺'=>'鷺','鸞'=>'鸞','鹃'=>'鹂','⿄'=>'鹵','鹿'=>'鹿','⿅'=>'鹿','麗'=>'麗','麟'=>'麟','⿆'=>'麥','麻'=>'麻','⿇'=>'麻','⿈'=>'黃','⿉'=>'黍','黎'=>'黎','⿊'=>'黑','黹'=>'黹','⿋'=>'黹','⿌'=>'黽','黾'=>'黾','鼅'=>'鼅','⿍'=>'鼎','鼏'=>'鼏','⿎'=>'鼓','鼖'=>'鼖','⿏'=>'鼠','鼻'=>'鼻','⿐'=>'鼻','齃'=>'齃','⿑'=>'齊','⿒'=>'齒','龍'=>'龍','⿓'=>'龍','龎'=>'龎','龜'=>'龜','龜'=>'龜','龜'=>'龜','⿔'=>'龜','⻳'=>'龟','⿕'=>'龠','㒞'=>'㒞','㒹'=>'㒹','㒻'=>'㒻','㓟'=>'㓟','㔕'=>'㔕','䎛'=>'㖈','㛮'=>'㛮','㛼'=>'㛼','㞁'=>'㞁','㠯'=>'㠯','㡢'=>'㡢','㡼'=>'㡼','㣇'=>'㣇','㣣'=>'㣣','㤜'=>'㤜','㤺'=>'㤺','㨮'=>'㨮','㩬'=>'㩬','㫤'=>'㫤','㬈'=>'㬈','㬙'=>'㬙','䐠'=>'㬻','㭉'=>'㭉','㮝'=>'㮝','㮝'=>'㮝','㰘'=>'㰘','㱎'=>'㱎','㴳'=>'㴳','㶖'=>'㶖','㺬'=>'㺬','㺸'=>'㺸','㺸'=>'㺸','㼛'=>'㼛','㿼'=>'㿼','䀈'=>'䀈','䀘'=>'䀘','䀹'=>'䀹','䀹'=>'䀹','䁆'=>'䁆','䂖'=>'䂖','䃣'=>'䃣','䄯'=>'䄯','䈂'=>'䈂','䈧'=>'䈧','䊠'=>'䊠','䌁'=>'䌁','䌴'=>'䌴','䍙'=>'䍙','䏕'=>'䏕','䏙'=>'䏙','䐋'=>'䐋','䑫'=>'䑫','䔫'=>'䔫','䕝'=>'䕝','䕡'=>'䕡','䕫'=>'䕫','䗗'=>'䗗','䗹'=>'䗹','䘵'=>'䘵','䚾'=>'䚾','䛇'=>'䛇','䦕'=>'䦕','䧦'=>'䧦','䩮'=>'䩮','䩶'=>'䩶','䪲'=>'䪲','䬳'=>'䬳','䯎'=>'䯎','䳎'=>'䳎','䳭'=>'䳭','䳸'=>'䳸','䵖'=>'䵖','𠄢'=>'𠄢','𠔜'=>'𠔜','𠔥'=>'𠔥','𠕋'=>'𠕋','𠘺'=>'𠘺','𠠄'=>'𠠄','𠣞'=>'𠣞','𠨬'=>'𠨬','𠭣'=>'𠭣','𡓤'=>'𡓤','𡚨'=>'𡚨','𡛪'=>'𡛪','𡧈'=>'𡧈','𡬘'=>'𡬘','𡴋'=>'𡴋','𡷤'=>'𡷤','𡷦'=>'𡷦','𢆃'=>'𢆃','𢆟'=>'𢆟','𢌱'=>'𢌱','𢌱'=>'𢌱','𢛔'=>'𢛔','𢡄'=>'𢡄','𢡊'=>'𢡊','𢬌'=>'𢬌','𢯱'=>'𢯱','𣀊'=>'𣀊','𣊸'=>'𣊸','𣍟'=>'𣍟','𣎓'=>'𣎓','𣎜'=>'𣎜','𣏃'=>'𣏃','𣏕'=>'𣏕','𣑭'=>'𣑭','𣚣'=>'𣚣','𣢧'=>'𣢧','𣪍'=>'𣪍','𣫺'=>'𣫺','𣲼'=>'𣲼','𣴞'=>'𣴞','𣻑'=>'𣻑','𣽞'=>'𣽞','𣾎'=>'𣾎','𤉣'=>'𤉣','𤎫'=>'𤎫','𤘈'=>'𤘈','𤜵'=>'𤜵','𤠔'=>'𤠔','𤰶'=>'𤰶','𤲒'=>'𤲒','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'𥁄','𥃲'=>'𥃲','𥃳'=>'𥃳','𥄙'=>'𥄙','𥄳'=>'𥄳','𥉉'=>'𥉉','𥐝'=>'𥐝','𥘦'=>'𥘦','𥚚'=>'𥚚','𥛅'=>'𥛅','𥥼'=>'𥥼','𥪧'=>'𥪧','𥪧'=>'𥪧','𥮫'=>'𥮫','𥲀'=>'𥲀','𥳐'=>'𥳐','𥾆'=>'𥾆','𦇚'=>'𦇚','𦈨'=>'𦈨','𦉇'=>'𦉇','𦋙'=>'𦋙','𦌾'=>'𦌾','𦓚'=>'𦓚','𦔣'=>'𦔣','𦖨'=>'𦖨','𦞧'=>'𦞧','𦞵'=>'𦞵','𦬼'=>'𦬼','𦰶'=>'𦰶','𦳕'=>'𦳕','𦵫'=>'𦵫','𦼬'=>'𦼬','𦾱'=>'𦾱','𧃒'=>'𧃒','𧏊'=>'𧏊','𧙧'=>'𧙧','𧢮'=>'𧢮','𧥦'=>'𧥦','𧲨'=>'𧲨','𧻓'=>'𧻓','𧼯'=>'𧼯','𨗒'=>'𨗒','𨗭'=>'𨗭','𨜮'=>'𨜮','𨯺'=>'𨯺','𨵷'=>'𨵷','𩅅'=>'𩅅','𩇟'=>'𩇟','𩈚'=>'𩈚','𩐊'=>'𩐊','𩒖'=>'𩒖','𩖶'=>'𩖶','𩬰'=>'𩬰','𪃎'=>'𪃎','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','𪎒'=>'𪎒','𪘀'=>'𪘀','℃'=>'°C','℉'=>'°F','ℇ'=>'Ɛ','℻'=>'FAX','ℕ'=>'N','№'=>'No','ℚ'=>'Q','₨'=>'Rs','𝐓'=>'T','℡'=>'TEL','𝐔'=>'U','𝐖'=>'W','₩'=>'W̵','𝐗'=>'X','¥'=>'Y̵','𝚲'=>'Λ','𝚵'=>'Ξ','ℿ'=>'Π','ϲ'=>'c','ϒ'=>'Y','𝚽'=>'Φ','𝚿'=>'Ψ','ѣ'=>'Ь̵','ਃ'=>'ঃ','ಃ'=>'ః','່'=>'่','់'=>'่','້'=>'้','໊'=>'๊','໋'=>'๋','៕'=>'๚','៚'=>'๛','ъ'=>'ˉb','៙'=>'๏','೧'=>'౧','૨'=>'२','೨'=>'౨','૩'=>'३','૪'=>'४','૮'=>'८','೯'=>'౯','а'=>'a','Ꮟ'=>'b','ᖯ'=>'b','с'=>'c','ԁ'=>'d','ᑯ'=>'d','е'=>'e','ә'=>'ǝ','ε'=>'ɛ','є'=>'ɛ','ք'=>'f','ց'=>'g','һ'=>'h','հ'=>'h','Ꮒ'=>'h','Ᏺ'=>'h̔','ι'=>'i','і'=>'i','Ꭵ'=>'i','ј'=>'j','յ'=>'j','ᗰ'=>'m','ո'=>'n','η'=>'n̩','ం'=>'o','ಂ'=>'o','ം'=>'o','०'=>'o','੦'=>'o','૦'=>'o','๐'=>'o','໐'=>'o','ο'=>'o','о'=>'o','օ'=>'o','ဝ'=>'o','ρ'=>'p','р'=>'p','ᴩ'=>'ᴘ','գ'=>'q','κ'=>'ĸ','к'=>'ĸ','ᴦ'=>'r','г'=>'r','ѕ'=>'s','υ'=>'u','ս'=>'u','ν'=>'v','ѵ'=>'v','Ꮃ'=>'w','ᗯ'=>'w','х'=>'x','ᕁ'=>'x','у'=>'y','Ꭹ'=>'y','ӡ'=>'ʒ','ჳ'=>'ʒ','ϩ'=>'ƨ','ь'=>'ƅ','ы'=>'ƅi','ɑ'=>'α','ծ'=>'δ','ᕷ'=>'δ','п'=>'π','ɸ'=>'φ','ф'=>'φ','ʙ'=>'в','ɜ'=>'з','ᴍ'=>'м','ʜ'=>'н','ɢ'=>'ԍ','ᴛ'=>'т','ᴙ'=>'я','ઽ'=>'ऽ','ુ'=>'ु','ૂ'=>'ू','ੋ'=>'ॆ','੍'=>'्','્'=>'्','ഉ'=>'உ','ജ'=>'ஐ','ണ'=>'ண','ഴ'=>'ழ','ി'=>'ி','ു'=>'ூ','ಅ'=>'అ','ಆ'=>'ఆ','ಇ'=>'ఇ','ಒ'=>'ఒ','ಓ'=>'ఒౕ','ಜ'=>'జ','ಞ'=>'ఞ','ಣ'=>'ణ','థ'=>'ధּ','ಯ'=>'య','ఠ'=>'రּ','ಱ'=>'ఱ','ಲ'=>'ల','ඌ'=>'ന്ന','ஶ'=>'ശ','ຈ'=>'จ','ບ'=>'บ','ປ'=>'ป','ຝ'=>'ฝ','ພ'=>'พ','ຟ'=>'ฟ','ຍ'=>'ย','។'=>'ฯ','ិ'=>'ิ','ី'=>'ี','ឹ'=>'ึ','ឺ'=>'ื','ຸ'=>'ุ','ູ'=>'ู','ᗅ'=>'A','ᒍ'=>'J','ᕼ'=>'H','ᐯ'=>'V','ᑭ'=>'P','ᗷ'=>'B','ヘ'=>'へ','𐏑'=>'𐎂','𐏓'=>'𐎓','𒀸'=>'𐎚','ᅳ'=>'一','ǀ'=>'丨','ᅵ'=>'丨','Ꭺ'=>'A','Ᏼ'=>'B','Ꮯ'=>'C','ᗞ'=>'D','Ꭼ'=>'E','ᖴ'=>'F','Ꮐ'=>'G','Ꮋ'=>'H','Ꭻ'=>'J','Ꮶ'=>'K','Ꮮ'=>'L','Ꮇ'=>'M','Ꮲ'=>'P','ᖇ'=>'R','Ꮥ'=>'S','Ꮩ'=>'V','Ꮓ'=>'Z'); diff --git a/phpBB/includes/utf/data/recode_basic.php b/phpBB/includes/utf/data/recode_basic.php index 02e44d3e0d..8a9dc544e6 100644 --- a/phpBB/includes/utf/data/recode_basic.php +++ b/phpBB/includes/utf/data/recode_basic.php @@ -1539,5 +1539,3 @@ function utf8_to_cp1252($string) ); return strtr($string, $transform); } - -?>
\ No newline at end of file diff --git a/phpBB/includes/utf/data/recode_cjk.php b/phpBB/includes/utf/data/recode_cjk.php index f3f9a256d7..8c65274af0 100644 --- a/phpBB/includes/utf/data/recode_cjk.php +++ b/phpBB/includes/utf/data/recode_cjk.php @@ -45175,5 +45175,3 @@ function big5($string) ); return strtr($string, $transform); } - -?>
\ No newline at end of file diff --git a/phpBB/includes/utf/data/search_indexer_0.php b/phpBB/includes/utf/data/search_indexer_0.php index 3304b18cdd..e8a087c0bc 100644 --- a/phpBB/includes/utf/data/search_indexer_0.php +++ b/phpBB/includes/utf/data/search_indexer_0.php @@ -1 +1 @@ -<?php return array(0=>'0',1=>'1',2=>'2',3=>'3',4=>'4',5=>'5',6=>'6',7=>'7',8=>'8',9=>'9','A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','a'=>'a','b'=>'b','c'=>'c','d'=>'d','e'=>'e','f'=>'f','g'=>'g','h'=>'h','i'=>'i','j'=>'j','k'=>'k','l'=>'l','m'=>'m','n'=>'n','o'=>'o','p'=>'p','q'=>'q','r'=>'r','s'=>'s','t'=>'t','u'=>'u','v'=>'v','w'=>'w','x'=>'x','y'=>'y','z'=>'z','ª'=>'ª','²'=>'2','³'=>'3','µ'=>'µ','¹'=>'1','º'=>'º','¼'=>'1/4','½'=>'1/2','¾'=>'3/4','À'=>'à','Á'=>'á','Â'=>'â','Ã'=>'ã','Ä'=>'ae','Å'=>'å','Æ'=>'ae','Ç'=>'ç','È'=>'è','É'=>'é','Ê'=>'ê','Ë'=>'ë','Ì'=>'ì','Í'=>'í','Î'=>'î','Ï'=>'ï','Ð'=>'ð','Ñ'=>'ñ','Ò'=>'ò','Ó'=>'ó','Ô'=>'ô','Õ'=>'õ','Ö'=>'oe','Ø'=>'ø','Ù'=>'ù','Ú'=>'ú','Û'=>'û','Ü'=>'ü','Ý'=>'ý','Þ'=>'þ','ß'=>'ss','à'=>'à','á'=>'á','â'=>'â','ã'=>'ã','ä'=>'ae','å'=>'å','æ'=>'ae','ç'=>'ç','è'=>'è','é'=>'é','ê'=>'ê','ë'=>'ë','ì'=>'ì','í'=>'í','î'=>'î','ï'=>'ï','ð'=>'ð','ñ'=>'ñ','ò'=>'ò','ó'=>'ó','ô'=>'ô','õ'=>'õ','ö'=>'oe','ø'=>'ø','ù'=>'ù','ú'=>'ú','û'=>'û','ü'=>'ue','ý'=>'ý','þ'=>'þ','ÿ'=>'ÿ','Ā'=>'ā','ā'=>'ā','Ă'=>'ă','ă'=>'ă','Ą'=>'ą','ą'=>'ą','Ć'=>'ć','ć'=>'ć','Ĉ'=>'ĉ','ĉ'=>'ĉ','Ċ'=>'ċ','ċ'=>'ċ','Č'=>'č','č'=>'č','Ď'=>'ď','ď'=>'ď','Đ'=>'đ','đ'=>'đ','Ē'=>'ē','ē'=>'ē','Ĕ'=>'ĕ','ĕ'=>'ĕ','Ė'=>'ė','ė'=>'ė','Ę'=>'ę','ę'=>'ę','Ě'=>'ě','ě'=>'ě','Ĝ'=>'ĝ','ĝ'=>'ĝ','Ğ'=>'ğ','ğ'=>'ğ','Ġ'=>'ġ','ġ'=>'ġ','Ģ'=>'ģ','ģ'=>'ģ','Ĥ'=>'ĥ','ĥ'=>'ĥ','Ħ'=>'ħ','ħ'=>'ħ','Ĩ'=>'ĩ','ĩ'=>'ĩ','Ī'=>'ī','ī'=>'ī','Ĭ'=>'ĭ','ĭ'=>'ĭ','Į'=>'į','į'=>'į','İ'=>'i','ı'=>'ı','IJ'=>'ij','ij'=>'ij','Ĵ'=>'ĵ','ĵ'=>'ĵ','Ķ'=>'ķ','ķ'=>'ķ','ĸ'=>'ĸ','Ĺ'=>'ĺ','ĺ'=>'ĺ','Ļ'=>'ļ','ļ'=>'ļ','Ľ'=>'ľ','ľ'=>'ľ','Ŀ'=>'ŀ','ŀ'=>'ŀ','Ł'=>'ł','ł'=>'ł','Ń'=>'ń','ń'=>'ń','Ņ'=>'ņ','ņ'=>'ņ','Ň'=>'ň','ň'=>'ň','ʼn'=>'ʼn','Ŋ'=>'ŋ','ŋ'=>'ŋ','Ō'=>'ō','ō'=>'ō','Ŏ'=>'ŏ','ŏ'=>'ŏ','Ő'=>'ő','ő'=>'ő','Œ'=>'oe','œ'=>'oe','Ŕ'=>'ŕ','ŕ'=>'ŕ','Ŗ'=>'ŗ','ŗ'=>'ŗ','Ř'=>'ř','ř'=>'ř','Ś'=>'ś','ś'=>'ś','Ŝ'=>'ŝ','ŝ'=>'ŝ','Ş'=>'ş','ş'=>'ş','Š'=>'š','š'=>'š','Ţ'=>'ţ','ţ'=>'ţ','Ť'=>'ť','ť'=>'ť','Ŧ'=>'ŧ','ŧ'=>'ŧ','Ũ'=>'ũ','ũ'=>'ũ','Ū'=>'ū','ū'=>'ū','Ŭ'=>'ŭ','ŭ'=>'ŭ','Ů'=>'ů','ů'=>'ů','Ű'=>'ű','ű'=>'ű','Ų'=>'ų','ų'=>'ų','Ŵ'=>'ŵ','ŵ'=>'ŵ','Ŷ'=>'ŷ','ŷ'=>'ŷ','Ÿ'=>'ÿ','Ź'=>'ź','ź'=>'ź','Ż'=>'ż','ż'=>'ż','Ž'=>'ž','ž'=>'ž','ſ'=>'ſ','ƀ'=>'ƀ','Ɓ'=>'ɓ','Ƃ'=>'ƃ','ƃ'=>'ƃ','Ƅ'=>'ƅ','ƅ'=>'ƅ','Ɔ'=>'ɔ','Ƈ'=>'ƈ','ƈ'=>'ƈ','Ɖ'=>'ɖ','Ɗ'=>'ɗ','Ƌ'=>'ƌ','ƌ'=>'ƌ','ƍ'=>'ƍ','Ǝ'=>'ǝ','Ə'=>'ə','Ɛ'=>'ɛ','Ƒ'=>'ƒ','ƒ'=>'ƒ','Ɠ'=>'ɠ','Ɣ'=>'ɣ','ƕ'=>'hv','Ɩ'=>'ɩ','Ɨ'=>'ɨ','Ƙ'=>'ƙ','ƙ'=>'ƙ','ƚ'=>'ƚ','ƛ'=>'ƛ','Ɯ'=>'ɯ','Ɲ'=>'ɲ','ƞ'=>'ƞ','Ɵ'=>'ɵ','Ơ'=>'ơ','ơ'=>'ơ','Ƣ'=>'oi','ƣ'=>'oi','Ƥ'=>'ƥ','ƥ'=>'ƥ','Ʀ'=>'yr','Ƨ'=>'ƨ','ƨ'=>'ƨ','Ʃ'=>'ʃ','ƪ'=>'ƪ','ƫ'=>'ƫ','Ƭ'=>'ƭ','ƭ'=>'ƭ','Ʈ'=>'ʈ','Ư'=>'ư','ư'=>'ư','Ʊ'=>'ʊ','Ʋ'=>'ʋ','Ƴ'=>'ƴ','ƴ'=>'ƴ','Ƶ'=>'ƶ','ƶ'=>'ƶ','Ʒ'=>'ʒ','Ƹ'=>'ƹ','ƹ'=>'ƹ','ƺ'=>'ƺ','ƻ'=>'ƻ','Ƽ'=>'ƽ','ƽ'=>'ƽ','ƾ'=>'ƾ','ƿ'=>'ƿ','ǀ'=>'ǀ','ǁ'=>'ǁ','ǂ'=>'ǂ','ǃ'=>'ǃ','DŽ'=>'dž','Dž'=>'dž','dž'=>'dž','LJ'=>'lj','Lj'=>'lj','lj'=>'lj','NJ'=>'nj','Nj'=>'nj','nj'=>'nj','Ǎ'=>'ǎ','ǎ'=>'ǎ','Ǐ'=>'ǐ','ǐ'=>'ǐ','Ǒ'=>'ǒ','ǒ'=>'ǒ','Ǔ'=>'ǔ','ǔ'=>'ǔ','Ǖ'=>'ǖ','ǖ'=>'ǖ','Ǘ'=>'ǘ','ǘ'=>'ǘ','Ǚ'=>'ǚ','ǚ'=>'ǚ','Ǜ'=>'ǜ','ǜ'=>'ǜ','ǝ'=>'ǝ','Ǟ'=>'ǟ','ǟ'=>'ǟ','Ǡ'=>'ǡ','ǡ'=>'ǡ','Ǣ'=>'ǣ','ǣ'=>'ǣ','Ǥ'=>'ǥ','ǥ'=>'ǥ','Ǧ'=>'ǧ','ǧ'=>'ǧ','Ǩ'=>'ǩ','ǩ'=>'ǩ','Ǫ'=>'ǫ','ǫ'=>'ǫ','Ǭ'=>'ǭ','ǭ'=>'ǭ','Ǯ'=>'ǯ','ǯ'=>'ǯ','ǰ'=>'ǰ','DZ'=>'dz','Dz'=>'dz','dz'=>'dz','Ǵ'=>'ǵ','ǵ'=>'ǵ','Ƕ'=>'ƕ','Ƿ'=>'ƿ','Ǹ'=>'ǹ','ǹ'=>'ǹ','Ǻ'=>'ǻ','ǻ'=>'ǻ','Ǽ'=>'ǽ','ǽ'=>'ǽ','Ǿ'=>'ǿ','ǿ'=>'ǿ','Ȁ'=>'ȁ','ȁ'=>'ȁ','Ȃ'=>'ȃ','ȃ'=>'ȃ','Ȅ'=>'ȅ','ȅ'=>'ȅ','Ȇ'=>'ȇ','ȇ'=>'ȇ','Ȉ'=>'ȉ','ȉ'=>'ȉ','Ȋ'=>'ȋ','ȋ'=>'ȋ','Ȍ'=>'ȍ','ȍ'=>'ȍ','Ȏ'=>'ȏ','ȏ'=>'ȏ','Ȑ'=>'ȑ','ȑ'=>'ȑ','Ȓ'=>'ȓ','ȓ'=>'ȓ','Ȕ'=>'ȕ','ȕ'=>'ȕ','Ȗ'=>'ȗ','ȗ'=>'ȗ','Ș'=>'ș','ș'=>'ș','Ț'=>'ț','ț'=>'ț','Ȝ'=>'ȝ','ȝ'=>'ȝ','Ȟ'=>'ȟ','ȟ'=>'ȟ','Ƞ'=>'ƞ','ȡ'=>'ȡ','Ȣ'=>'ou','ȣ'=>'ou','Ȥ'=>'ȥ','ȥ'=>'ȥ','Ȧ'=>'ȧ','ȧ'=>'ȧ','Ȩ'=>'ȩ','ȩ'=>'ȩ','Ȫ'=>'ȫ','ȫ'=>'ȫ','Ȭ'=>'ȭ','ȭ'=>'ȭ','Ȯ'=>'ȯ','ȯ'=>'ȯ','Ȱ'=>'ȱ','ȱ'=>'ȱ','Ȳ'=>'ȳ','ȳ'=>'ȳ','ȴ'=>'ȴ','ȵ'=>'ȵ','ȶ'=>'ȶ','ȷ'=>'ȷ','ȸ'=>'ȸ','ȹ'=>'ȹ','Ⱥ'=>'ⱥ','Ȼ'=>'ȼ','ȼ'=>'ȼ','Ƚ'=>'ƚ','Ⱦ'=>'ⱦ','ȿ'=>'ȿ','ɀ'=>'ɀ','Ɂ'=>'ɂ','ɂ'=>'ɂ','Ƀ'=>'ƀ','Ʉ'=>'ʉ','Ʌ'=>'ʌ','Ɇ'=>'ɇ','ɇ'=>'ɇ','Ɉ'=>'ɉ','ɉ'=>'ɉ','Ɋ'=>'ɋ','ɋ'=>'ɋ','Ɍ'=>'ɍ','ɍ'=>'ɍ','Ɏ'=>'ɏ','ɏ'=>'ɏ','ɐ'=>'ɐ','ɑ'=>'ɑ','ɒ'=>'ɒ','ɓ'=>'ɓ','ɔ'=>'ɔ','ɕ'=>'ɕ','ɖ'=>'ɖ','ɗ'=>'ɗ','ɘ'=>'ɘ','ə'=>'ə','ɚ'=>'ɚ','ɛ'=>'ɛ','ɜ'=>'ɜ','ɝ'=>'ɝ','ɞ'=>'ɞ','ɟ'=>'ɟ','ɠ'=>'ɠ','ɡ'=>'ɡ','ɢ'=>'ɢ','ɣ'=>'ɣ','ɤ'=>'ɤ','ɥ'=>'ɥ','ɦ'=>'ɦ','ɧ'=>'ɧ','ɨ'=>'ɨ','ɩ'=>'ɩ','ɪ'=>'ɪ','ɫ'=>'ɫ','ɬ'=>'ɬ','ɭ'=>'ɭ','ɮ'=>'ɮ','ɯ'=>'ɯ','ɰ'=>'ɰ','ɱ'=>'ɱ','ɲ'=>'ɲ','ɳ'=>'ɳ','ɴ'=>'ɴ','ɵ'=>'ɵ','ɶ'=>'ɶ','ɷ'=>'ɷ','ɸ'=>'ɸ','ɹ'=>'ɹ','ɺ'=>'ɺ','ɻ'=>'ɻ','ɼ'=>'ɼ','ɽ'=>'ɽ','ɾ'=>'ɾ','ɿ'=>'ɿ','ʀ'=>'ʀ','ʁ'=>'ʁ','ʂ'=>'ʂ','ʃ'=>'ʃ','ʄ'=>'ʄ','ʅ'=>'ʅ','ʆ'=>'ʆ','ʇ'=>'ʇ','ʈ'=>'ʈ','ʉ'=>'ʉ','ʊ'=>'ʊ','ʋ'=>'ʋ','ʌ'=>'ʌ','ʍ'=>'ʍ','ʎ'=>'ʎ','ʏ'=>'ʏ','ʐ'=>'ʐ','ʑ'=>'ʑ','ʒ'=>'ʒ','ʓ'=>'ʓ','ʔ'=>'ʔ','ʕ'=>'ʕ','ʖ'=>'ʖ','ʗ'=>'ʗ','ʘ'=>'ʘ','ʙ'=>'ʙ','ʚ'=>'ʚ','ʛ'=>'ʛ','ʜ'=>'ʜ','ʝ'=>'ʝ','ʞ'=>'ʞ','ʟ'=>'ʟ','ʠ'=>'ʠ','ʡ'=>'ʡ','ʢ'=>'ʢ','ʣ'=>'ʣ','ʤ'=>'ʤ','ʥ'=>'ʥ','ʦ'=>'ʦ','ʧ'=>'ʧ','ʨ'=>'ʨ','ʩ'=>'ʩ','ʪ'=>'ʪ','ʫ'=>'ʫ','ʬ'=>'ʬ','ʭ'=>'ʭ','ʮ'=>'ʮ','ʯ'=>'ʯ','ʰ'=>'ʰ','ʱ'=>'ʱ','ʲ'=>'ʲ','ʳ'=>'ʳ','ʴ'=>'ʴ','ʵ'=>'ʵ','ʶ'=>'ʶ','ʷ'=>'ʷ','ʸ'=>'ʸ','ʹ'=>'ʹ','ʺ'=>'ʺ','ʻ'=>'ʻ','ʼ'=>'ʼ','ʽ'=>'ʽ','ʾ'=>'ʾ','ʿ'=>'ʿ','ˀ'=>'ˀ','ˁ'=>'ˁ','ˆ'=>'ˆ','ˇ'=>'ˇ','ˈ'=>'ˈ','ˉ'=>'ˉ','ˊ'=>'ˊ','ˋ'=>'ˋ','ˌ'=>'ˌ','ˍ'=>'ˍ','ˎ'=>'ˎ','ˏ'=>'ˏ','ː'=>'ː','ˑ'=>'ˑ','ˠ'=>'ˠ','ˡ'=>'ˡ','ˢ'=>'ˢ','ˣ'=>'ˣ','ˤ'=>'ˤ','ˮ'=>'ˮ','̀'=>'̀','́'=>'́','̂'=>'̂','̃'=>'̃','̄'=>'̄','̅'=>'̅','̆'=>'̆','̇'=>'̇','̈'=>'̈','̉'=>'̉','̊'=>'̊','̋'=>'̋','̌'=>'̌','̍'=>'̍','̎'=>'̎','̏'=>'̏','̐'=>'̐','̑'=>'̑','̒'=>'̒','̓'=>'̓','̔'=>'̔','̕'=>'̕','̖'=>'̖','̗'=>'̗','̘'=>'̘','̙'=>'̙','̚'=>'̚','̛'=>'̛','̜'=>'̜','̝'=>'̝','̞'=>'̞','̟'=>'̟','̠'=>'̠','̡'=>'̡','̢'=>'̢','̣'=>'̣','̤'=>'̤','̥'=>'̥','̦'=>'̦','̧'=>'̧','̨'=>'̨','̩'=>'̩','̪'=>'̪','̫'=>'̫','̬'=>'̬','̭'=>'̭','̮'=>'̮','̯'=>'̯','̰'=>'̰','̱'=>'̱','̲'=>'̲','̳'=>'̳','̴'=>'̴','̵'=>'̵','̶'=>'̶','̷'=>'̷','̸'=>'̸','̹'=>'̹','̺'=>'̺','̻'=>'̻','̼'=>'̼','̽'=>'̽','̾'=>'̾','̿'=>'̿','̀'=>'̀','́'=>'́','͂'=>'͂','̓'=>'̓','̈́'=>'̈́','ͅ'=>'ͅ','͆'=>'͆','͇'=>'͇','͈'=>'͈','͉'=>'͉','͊'=>'͊','͋'=>'͋','͌'=>'͌','͍'=>'͍','͎'=>'͎','͏'=>'͏','͐'=>'͐','͑'=>'͑','͒'=>'͒','͓'=>'͓','͔'=>'͔','͕'=>'͕','͖'=>'͖','͗'=>'͗','͘'=>'͘','͙'=>'͙','͚'=>'͚','͛'=>'͛','͜'=>'͜','͝'=>'͝','͞'=>'͞','͟'=>'͟','͠'=>'͠','͡'=>'͡','͢'=>'͢','ͣ'=>'ͣ','ͤ'=>'ͤ','ͥ'=>'ͥ','ͦ'=>'ͦ','ͧ'=>'ͧ','ͨ'=>'ͨ','ͩ'=>'ͩ','ͪ'=>'ͪ','ͫ'=>'ͫ','ͬ'=>'ͬ','ͭ'=>'ͭ','ͮ'=>'ͮ','ͯ'=>'ͯ','ͺ'=>'ͺ','ͻ'=>'ͻ','ͼ'=>'ͼ','ͽ'=>'ͽ','Ά'=>'ά','Έ'=>'έ','Ή'=>'ή','Ί'=>'ί','Ό'=>'ό','Ύ'=>'ύ','Ώ'=>'ώ','ΐ'=>'ΐ','Α'=>'α','Β'=>'β','Γ'=>'γ','Δ'=>'δ','Ε'=>'ε','Ζ'=>'ζ','Η'=>'η','Θ'=>'θ','Ι'=>'ι','Κ'=>'κ','Λ'=>'λ','Μ'=>'μ','Ν'=>'ν','Ξ'=>'ξ','Ο'=>'ο','Π'=>'π','Ρ'=>'ρ','Σ'=>'σ','Τ'=>'τ','Υ'=>'υ','Φ'=>'φ','Χ'=>'χ','Ψ'=>'ψ','Ω'=>'ω','Ϊ'=>'ϊ','Ϋ'=>'ϋ','ά'=>'ά','έ'=>'έ','ή'=>'ή','ί'=>'ί','ΰ'=>'ΰ','α'=>'α','β'=>'β','γ'=>'γ','δ'=>'δ','ε'=>'ε','ζ'=>'ζ','η'=>'η','θ'=>'θ','ι'=>'ι','κ'=>'κ','λ'=>'λ','μ'=>'μ','ν'=>'ν','ξ'=>'ξ','ο'=>'ο','π'=>'π','ρ'=>'ρ','ς'=>'ς','σ'=>'σ','τ'=>'τ','υ'=>'υ','φ'=>'φ','χ'=>'χ','ψ'=>'ψ','ω'=>'ω','ϊ'=>'ϊ','ϋ'=>'ϋ','ό'=>'ό','ύ'=>'ύ','ώ'=>'ώ','ϐ'=>'ϐ','ϑ'=>'ϑ','ϒ'=>'ϒ','ϓ'=>'ϓ','ϔ'=>'ϔ','ϕ'=>'ϕ','ϖ'=>'ϖ','ϗ'=>'ϗ','Ϙ'=>'ϙ','ϙ'=>'ϙ','Ϛ'=>'ϛ','ϛ'=>'ϛ','Ϝ'=>'ϝ','ϝ'=>'ϝ','Ϟ'=>'ϟ','ϟ'=>'ϟ','Ϡ'=>'ϡ','ϡ'=>'ϡ','Ϣ'=>'ϣ','ϣ'=>'ϣ','Ϥ'=>'ϥ','ϥ'=>'ϥ','Ϧ'=>'ϧ','ϧ'=>'ϧ','Ϩ'=>'ϩ','ϩ'=>'ϩ','Ϫ'=>'ϫ','ϫ'=>'ϫ','Ϭ'=>'ϭ','ϭ'=>'ϭ','Ϯ'=>'ϯ','ϯ'=>'ϯ','ϰ'=>'ϰ','ϱ'=>'ϱ','ϲ'=>'ϲ','ϳ'=>'ϳ','ϴ'=>'θ','ϵ'=>'ϵ','Ϸ'=>'ϸ','ϸ'=>'ϸ','Ϲ'=>'ϲ','Ϻ'=>'ϻ','ϻ'=>'ϻ','ϼ'=>'ϼ','Ͻ'=>'ͻ','Ͼ'=>'ͼ','Ͽ'=>'ͽ','Ѐ'=>'ѐ','Ё'=>'ё','Ђ'=>'ђ','Ѓ'=>'ѓ','Є'=>'є','Ѕ'=>'ѕ','І'=>'і','Ї'=>'ї','Ј'=>'ј','Љ'=>'љ','Њ'=>'њ','Ћ'=>'ћ','Ќ'=>'ќ','Ѝ'=>'ѝ','Ў'=>'ў','Џ'=>'џ','А'=>'а','Б'=>'б','В'=>'в','Г'=>'г','Д'=>'д','Е'=>'е','Ж'=>'ж','З'=>'з','И'=>'и','Й'=>'й','К'=>'к','Л'=>'л','М'=>'м','Н'=>'н','О'=>'о','П'=>'п','Р'=>'р','С'=>'с','Т'=>'т','У'=>'у','Ф'=>'ф','Х'=>'х','Ц'=>'ц','Ч'=>'ч','Ш'=>'ш','Щ'=>'щ','Ъ'=>'ъ','Ы'=>'ы','Ь'=>'ь','Э'=>'э','Ю'=>'ю','Я'=>'я','а'=>'а','б'=>'б','в'=>'в','г'=>'г','д'=>'д','е'=>'е','ж'=>'ж','з'=>'з','и'=>'и','й'=>'й','к'=>'к','л'=>'л','м'=>'м','н'=>'н','о'=>'о','п'=>'п','р'=>'р','с'=>'с','т'=>'т','у'=>'у','ф'=>'ф','х'=>'х','ц'=>'ц','ч'=>'ч','ш'=>'ш','щ'=>'щ','ъ'=>'ъ','ы'=>'ы','ь'=>'ь','э'=>'э','ю'=>'ю','я'=>'я','ѐ'=>'ѐ','ё'=>'ё','ђ'=>'ђ','ѓ'=>'ѓ','є'=>'є','ѕ'=>'ѕ','і'=>'і','ї'=>'ї','ј'=>'ј','љ'=>'љ','њ'=>'њ','ћ'=>'ћ','ќ'=>'ќ','ѝ'=>'ѝ','ў'=>'ў','џ'=>'џ','Ѡ'=>'ѡ','ѡ'=>'ѡ','Ѣ'=>'ѣ','ѣ'=>'ѣ','Ѥ'=>'ѥ','ѥ'=>'ѥ','Ѧ'=>'ѧ','ѧ'=>'ѧ','Ѩ'=>'ѩ','ѩ'=>'ѩ','Ѫ'=>'ѫ','ѫ'=>'ѫ','Ѭ'=>'ѭ','ѭ'=>'ѭ','Ѯ'=>'ѯ','ѯ'=>'ѯ','Ѱ'=>'ѱ','ѱ'=>'ѱ','Ѳ'=>'ѳ','ѳ'=>'ѳ','Ѵ'=>'ѵ','ѵ'=>'ѵ','Ѷ'=>'ѷ','ѷ'=>'ѷ','Ѹ'=>'ѹ','ѹ'=>'ѹ','Ѻ'=>'ѻ','ѻ'=>'ѻ','Ѽ'=>'ѽ','ѽ'=>'ѽ','Ѿ'=>'ѿ','ѿ'=>'ѿ','Ҁ'=>'ҁ','ҁ'=>'ҁ','҃'=>'҃','҄'=>'҄','҅'=>'҅','҆'=>'҆','҈'=>'҈','҉'=>'҉','Ҋ'=>'ҋ','ҋ'=>'ҋ','Ҍ'=>'ҍ','ҍ'=>'ҍ','Ҏ'=>'ҏ','ҏ'=>'ҏ','Ґ'=>'ґ','ґ'=>'ґ','Ғ'=>'ғ','ғ'=>'ғ','Ҕ'=>'ҕ','ҕ'=>'ҕ','Җ'=>'җ','җ'=>'җ','Ҙ'=>'ҙ','ҙ'=>'ҙ','Қ'=>'қ','қ'=>'қ','Ҝ'=>'ҝ','ҝ'=>'ҝ','Ҟ'=>'ҟ','ҟ'=>'ҟ','Ҡ'=>'ҡ','ҡ'=>'ҡ','Ң'=>'ң','ң'=>'ң','Ҥ'=>'ҥ','ҥ'=>'ҥ','Ҧ'=>'ҧ','ҧ'=>'ҧ','Ҩ'=>'ҩ','ҩ'=>'ҩ','Ҫ'=>'ҫ','ҫ'=>'ҫ','Ҭ'=>'ҭ','ҭ'=>'ҭ','Ү'=>'ү','ү'=>'ү','Ұ'=>'ұ','ұ'=>'ұ','Ҳ'=>'ҳ','ҳ'=>'ҳ','Ҵ'=>'ҵ','ҵ'=>'ҵ','Ҷ'=>'ҷ','ҷ'=>'ҷ','Ҹ'=>'ҹ','ҹ'=>'ҹ','Һ'=>'һ','һ'=>'һ','Ҽ'=>'ҽ','ҽ'=>'ҽ','Ҿ'=>'ҿ','ҿ'=>'ҿ','Ӏ'=>'ӏ','Ӂ'=>'ӂ','ӂ'=>'ӂ','Ӄ'=>'ӄ','ӄ'=>'ӄ','Ӆ'=>'ӆ','ӆ'=>'ӆ','Ӈ'=>'ӈ','ӈ'=>'ӈ','Ӊ'=>'ӊ','ӊ'=>'ӊ','Ӌ'=>'ӌ','ӌ'=>'ӌ','Ӎ'=>'ӎ','ӎ'=>'ӎ','ӏ'=>'ӏ','Ӑ'=>'ӑ','ӑ'=>'ӑ','Ӓ'=>'ӓ','ӓ'=>'ӓ','Ӕ'=>'ӕ','ӕ'=>'ӕ','Ӗ'=>'ӗ','ӗ'=>'ӗ','Ә'=>'ә','ә'=>'ә','Ӛ'=>'ӛ','ӛ'=>'ӛ','Ӝ'=>'ӝ','ӝ'=>'ӝ','Ӟ'=>'ӟ','ӟ'=>'ӟ','Ӡ'=>'ӡ','ӡ'=>'ӡ','Ӣ'=>'ӣ','ӣ'=>'ӣ','Ӥ'=>'ӥ','ӥ'=>'ӥ','Ӧ'=>'ӧ','ӧ'=>'ӧ','Ө'=>'ө','ө'=>'ө','Ӫ'=>'ӫ','ӫ'=>'ӫ','Ӭ'=>'ӭ','ӭ'=>'ӭ','Ӯ'=>'ӯ','ӯ'=>'ӯ','Ӱ'=>'ӱ','ӱ'=>'ӱ','Ӳ'=>'ӳ','ӳ'=>'ӳ','Ӵ'=>'ӵ','ӵ'=>'ӵ','Ӷ'=>'ӷ','ӷ'=>'ӷ','Ӹ'=>'ӹ','ӹ'=>'ӹ','Ӻ'=>'ӻ','ӻ'=>'ӻ','Ӽ'=>'ӽ','ӽ'=>'ӽ','Ӿ'=>'ӿ','ӿ'=>'ӿ','Ԁ'=>'ԁ','ԁ'=>'ԁ','Ԃ'=>'ԃ','ԃ'=>'ԃ','Ԅ'=>'ԅ','ԅ'=>'ԅ','Ԇ'=>'ԇ','ԇ'=>'ԇ','Ԉ'=>'ԉ','ԉ'=>'ԉ','Ԋ'=>'ԋ','ԋ'=>'ԋ','Ԍ'=>'ԍ','ԍ'=>'ԍ','Ԏ'=>'ԏ','ԏ'=>'ԏ','Ԑ'=>'ԑ','ԑ'=>'ԑ','Ԓ'=>'ԓ','ԓ'=>'ԓ','Ա'=>'ա','Բ'=>'բ','Գ'=>'գ','Դ'=>'դ','Ե'=>'ե','Զ'=>'զ','Է'=>'է','Ը'=>'ը','Թ'=>'թ','Ժ'=>'ժ','Ի'=>'ի','Լ'=>'լ','Խ'=>'խ','Ծ'=>'ծ','Կ'=>'կ','Հ'=>'հ','Ձ'=>'ձ','Ղ'=>'ղ','Ճ'=>'ճ','Մ'=>'մ','Յ'=>'յ','Ն'=>'ն','Շ'=>'շ','Ո'=>'ո','Չ'=>'չ','Պ'=>'պ','Ջ'=>'ջ','Ռ'=>'ռ','Ս'=>'ս','Վ'=>'վ','Տ'=>'տ','Ր'=>'ր','Ց'=>'ց','Ւ'=>'ւ','Փ'=>'փ','Ք'=>'ք','Օ'=>'օ','Ֆ'=>'ֆ','ՙ'=>'ՙ','ա'=>'ա','բ'=>'բ','գ'=>'գ','դ'=>'դ','ե'=>'ե','զ'=>'զ','է'=>'է','ը'=>'ը','թ'=>'թ','ժ'=>'ժ','ի'=>'ի','լ'=>'լ','խ'=>'խ','ծ'=>'ծ','կ'=>'կ','հ'=>'հ','ձ'=>'ձ','ղ'=>'ղ','ճ'=>'ճ','մ'=>'մ','յ'=>'յ','ն'=>'ն','շ'=>'շ','ո'=>'ո','չ'=>'չ','պ'=>'պ','ջ'=>'ջ','ռ'=>'ռ','ս'=>'ս','վ'=>'վ','տ'=>'տ','ր'=>'ր','ց'=>'ց','ւ'=>'ւ','փ'=>'փ','ք'=>'ք','օ'=>'օ','ֆ'=>'ֆ','և'=>'և','֑'=>'֑','֒'=>'֒','֓'=>'֓','֔'=>'֔','֕'=>'֕','֖'=>'֖','֗'=>'֗','֘'=>'֘','֙'=>'֙','֚'=>'֚','֛'=>'֛','֜'=>'֜','֝'=>'֝','֞'=>'֞','֟'=>'֟','֠'=>'֠','֡'=>'֡','֢'=>'֢','֣'=>'֣','֤'=>'֤','֥'=>'֥','֦'=>'֦','֧'=>'֧','֨'=>'֨','֩'=>'֩','֪'=>'֪','֫'=>'֫','֬'=>'֬','֭'=>'֭','֮'=>'֮','֯'=>'֯','ְ'=>'ְ','ֱ'=>'ֱ','ֲ'=>'ֲ','ֳ'=>'ֳ','ִ'=>'ִ','ֵ'=>'ֵ','ֶ'=>'ֶ','ַ'=>'ַ','ָ'=>'ָ','ֹ'=>'ֹ','ֺ'=>'ֺ','ֻ'=>'ֻ','ּ'=>'ּ','ֽ'=>'ֽ','ֿ'=>'ֿ','ׁ'=>'ׁ','ׂ'=>'ׂ','ׄ'=>'ׄ','ׅ'=>'ׅ','ׇ'=>'ׇ','א'=>'א','ב'=>'ב','ג'=>'ג','ד'=>'ד','ה'=>'ה','ו'=>'ו','ז'=>'ז','ח'=>'ח','ט'=>'ט','י'=>'י','ך'=>'ך','כ'=>'כ','ל'=>'ל','ם'=>'ם','מ'=>'מ','ן'=>'ן','נ'=>'נ','ס'=>'ס','ע'=>'ע','ף'=>'ף','פ'=>'פ','ץ'=>'ץ','צ'=>'צ','ק'=>'ק','ר'=>'ר','ש'=>'ש','ת'=>'ת','װ'=>'װ','ױ'=>'ױ','ײ'=>'ײ','ؐ'=>'ؐ','ؑ'=>'ؑ','ؒ'=>'ؒ','ؓ'=>'ؓ','ؔ'=>'ؔ','ؕ'=>'ؕ','ء'=>'ء','آ'=>'آ','أ'=>'أ','ؤ'=>'ؤ','إ'=>'إ','ئ'=>'ئ','ا'=>'ا','ب'=>'ب','ة'=>'ة','ت'=>'ت','ث'=>'ث','ج'=>'ج','ح'=>'ح','خ'=>'خ','د'=>'د','ذ'=>'ذ','ر'=>'ر','ز'=>'ز','س'=>'س','ش'=>'ش','ص'=>'ص','ض'=>'ض','ط'=>'ط','ظ'=>'ظ','ع'=>'ع','غ'=>'غ','ـ'=>'ـ','ف'=>'ف','ق'=>'ق','ك'=>'ك','ل'=>'ل','م'=>'م','ن'=>'ن','ه'=>'ه','و'=>'و','ى'=>'ى','ي'=>'ي','ً'=>'ً','ٌ'=>'ٌ','ٍ'=>'ٍ','َ'=>'َ','ُ'=>'ُ','ِ'=>'ِ','ّ'=>'ّ','ْ'=>'ْ','ٓ'=>'ٓ','ٔ'=>'ٔ','ٕ'=>'ٕ','ٖ'=>'ٖ','ٗ'=>'ٗ','٘'=>'٘','ٙ'=>'ٙ','ٚ'=>'ٚ','ٛ'=>'ٛ','ٜ'=>'ٜ','ٝ'=>'ٝ','ٞ'=>'ٞ','٠'=>'0','١'=>'1','٢'=>'2','٣'=>'3','٤'=>'4','٥'=>'5','٦'=>'6','٧'=>'7','٨'=>'8','٩'=>'9','ٮ'=>'ٮ','ٯ'=>'ٯ','ٰ'=>'ٰ','ٱ'=>'ٱ','ٲ'=>'ٲ','ٳ'=>'ٳ','ٴ'=>'ٴ','ٵ'=>'ٵ','ٶ'=>'ٶ','ٷ'=>'ٷ','ٸ'=>'ٸ','ٹ'=>'ٹ','ٺ'=>'ٺ','ٻ'=>'ٻ','ټ'=>'ټ','ٽ'=>'ٽ','پ'=>'پ','ٿ'=>'ٿ','ڀ'=>'ڀ','ځ'=>'ځ','ڂ'=>'ڂ','ڃ'=>'ڃ','ڄ'=>'ڄ','څ'=>'څ','چ'=>'چ','ڇ'=>'ڇ','ڈ'=>'ڈ','ډ'=>'ډ','ڊ'=>'ڊ','ڋ'=>'ڋ','ڌ'=>'ڌ','ڍ'=>'ڍ','ڎ'=>'ڎ','ڏ'=>'ڏ','ڐ'=>'ڐ','ڑ'=>'ڑ','ڒ'=>'ڒ','ړ'=>'ړ','ڔ'=>'ڔ','ڕ'=>'ڕ','ږ'=>'ږ','ڗ'=>'ڗ','ژ'=>'ژ','ڙ'=>'ڙ','ښ'=>'ښ','ڛ'=>'ڛ','ڜ'=>'ڜ','ڝ'=>'ڝ','ڞ'=>'ڞ','ڟ'=>'ڟ','ڠ'=>'ڠ','ڡ'=>'ڡ','ڢ'=>'ڢ','ڣ'=>'ڣ','ڤ'=>'ڤ','ڥ'=>'ڥ','ڦ'=>'ڦ','ڧ'=>'ڧ','ڨ'=>'ڨ','ک'=>'ک','ڪ'=>'ڪ','ګ'=>'ګ','ڬ'=>'ڬ','ڭ'=>'ڭ','ڮ'=>'ڮ','گ'=>'گ','ڰ'=>'ڰ','ڱ'=>'ڱ','ڲ'=>'ڲ','ڳ'=>'ڳ','ڴ'=>'ڴ','ڵ'=>'ڵ','ڶ'=>'ڶ','ڷ'=>'ڷ','ڸ'=>'ڸ','ڹ'=>'ڹ','ں'=>'ں','ڻ'=>'ڻ','ڼ'=>'ڼ','ڽ'=>'ڽ','ھ'=>'ھ','ڿ'=>'ڿ','ۀ'=>'ۀ','ہ'=>'ہ','ۂ'=>'ۂ','ۃ'=>'ۃ','ۄ'=>'ۄ','ۅ'=>'ۅ','ۆ'=>'ۆ','ۇ'=>'ۇ','ۈ'=>'ۈ','ۉ'=>'ۉ','ۊ'=>'ۊ','ۋ'=>'ۋ','ی'=>'ی','ۍ'=>'ۍ','ێ'=>'ێ','ۏ'=>'ۏ','ې'=>'ې','ۑ'=>'ۑ','ے'=>'ے','ۓ'=>'ۓ','ە'=>'ە','ۖ'=>'ۖ','ۗ'=>'ۗ','ۘ'=>'ۘ','ۙ'=>'ۙ','ۚ'=>'ۚ','ۛ'=>'ۛ','ۜ'=>'ۜ','۞'=>'۞','۟'=>'۟','۠'=>'۠','ۡ'=>'ۡ','ۢ'=>'ۢ','ۣ'=>'ۣ','ۤ'=>'ۤ','ۥ'=>'ۥ','ۦ'=>'ۦ','ۧ'=>'ۧ','ۨ'=>'ۨ','۪'=>'۪','۫'=>'۫','۬'=>'۬','ۭ'=>'ۭ','ۮ'=>'ۮ','ۯ'=>'ۯ','۰'=>'0','۱'=>'1','۲'=>'2','۳'=>'3','۴'=>'4','۵'=>'5','۶'=>'6','۷'=>'7','۸'=>'8','۹'=>'9','ۺ'=>'ۺ','ۻ'=>'ۻ','ۼ'=>'ۼ','ۿ'=>'ۿ','ܐ'=>'ܐ','ܑ'=>'ܑ','ܒ'=>'ܒ','ܓ'=>'ܓ','ܔ'=>'ܔ','ܕ'=>'ܕ','ܖ'=>'ܖ','ܗ'=>'ܗ','ܘ'=>'ܘ','ܙ'=>'ܙ','ܚ'=>'ܚ','ܛ'=>'ܛ','ܜ'=>'ܜ','ܝ'=>'ܝ','ܞ'=>'ܞ','ܟ'=>'ܟ','ܠ'=>'ܠ','ܡ'=>'ܡ','ܢ'=>'ܢ','ܣ'=>'ܣ','ܤ'=>'ܤ','ܥ'=>'ܥ','ܦ'=>'ܦ','ܧ'=>'ܧ','ܨ'=>'ܨ','ܩ'=>'ܩ','ܪ'=>'ܪ','ܫ'=>'ܫ','ܬ'=>'ܬ','ܭ'=>'ܭ','ܮ'=>'ܮ','ܯ'=>'ܯ','ܰ'=>'ܰ','ܱ'=>'ܱ','ܲ'=>'ܲ','ܳ'=>'ܳ','ܴ'=>'ܴ','ܵ'=>'ܵ','ܶ'=>'ܶ','ܷ'=>'ܷ','ܸ'=>'ܸ','ܹ'=>'ܹ','ܺ'=>'ܺ','ܻ'=>'ܻ','ܼ'=>'ܼ','ܽ'=>'ܽ','ܾ'=>'ܾ','ܿ'=>'ܿ','݀'=>'݀','݁'=>'݁','݂'=>'݂','݃'=>'݃','݄'=>'݄','݅'=>'݅','݆'=>'݆','݇'=>'݇','݈'=>'݈','݉'=>'݉','݊'=>'݊','ݍ'=>'ݍ','ݎ'=>'ݎ','ݏ'=>'ݏ','ݐ'=>'ݐ','ݑ'=>'ݑ','ݒ'=>'ݒ','ݓ'=>'ݓ','ݔ'=>'ݔ','ݕ'=>'ݕ','ݖ'=>'ݖ','ݗ'=>'ݗ','ݘ'=>'ݘ','ݙ'=>'ݙ','ݚ'=>'ݚ','ݛ'=>'ݛ','ݜ'=>'ݜ','ݝ'=>'ݝ','ݞ'=>'ݞ','ݟ'=>'ݟ','ݠ'=>'ݠ','ݡ'=>'ݡ','ݢ'=>'ݢ','ݣ'=>'ݣ','ݤ'=>'ݤ','ݥ'=>'ݥ','ݦ'=>'ݦ','ݧ'=>'ݧ','ݨ'=>'ݨ','ݩ'=>'ݩ','ݪ'=>'ݪ','ݫ'=>'ݫ','ݬ'=>'ݬ','ݭ'=>'ݭ','ހ'=>'ހ','ށ'=>'ށ','ނ'=>'ނ','ރ'=>'ރ','ބ'=>'ބ','ޅ'=>'ޅ','ކ'=>'ކ','އ'=>'އ','ވ'=>'ވ','މ'=>'މ','ފ'=>'ފ','ދ'=>'ދ','ތ'=>'ތ','ލ'=>'ލ','ގ'=>'ގ','ޏ'=>'ޏ','ސ'=>'ސ','ޑ'=>'ޑ','ޒ'=>'ޒ','ޓ'=>'ޓ','ޔ'=>'ޔ','ޕ'=>'ޕ','ޖ'=>'ޖ','ޗ'=>'ޗ','ޘ'=>'ޘ','ޙ'=>'ޙ','ޚ'=>'ޚ','ޛ'=>'ޛ','ޜ'=>'ޜ','ޝ'=>'ޝ','ޞ'=>'ޞ','ޟ'=>'ޟ','ޠ'=>'ޠ','ޡ'=>'ޡ','ޢ'=>'ޢ','ޣ'=>'ޣ','ޤ'=>'ޤ','ޥ'=>'ޥ','ަ'=>'ަ','ާ'=>'ާ','ި'=>'ި','ީ'=>'ީ','ު'=>'ު','ޫ'=>'ޫ','ެ'=>'ެ','ޭ'=>'ޭ','ޮ'=>'ޮ','ޯ'=>'ޯ','ް'=>'ް','ޱ'=>'ޱ','߀'=>'0','߁'=>'1','߂'=>'2','߃'=>'3','߄'=>'4','߅'=>'5','߆'=>'6','߇'=>'7','߈'=>'8','߉'=>'9','ߊ'=>'ߊ','ߋ'=>'ߋ','ߌ'=>'ߌ','ߍ'=>'ߍ','ߎ'=>'ߎ','ߏ'=>'ߏ','ߐ'=>'ߐ','ߑ'=>'ߑ','ߒ'=>'ߒ','ߓ'=>'ߓ','ߔ'=>'ߔ','ߕ'=>'ߕ','ߖ'=>'ߖ','ߗ'=>'ߗ','ߘ'=>'ߘ','ߙ'=>'ߙ','ߚ'=>'ߚ','ߛ'=>'ߛ','ߜ'=>'ߜ','ߝ'=>'ߝ','ߞ'=>'ߞ','ߟ'=>'ߟ','ߠ'=>'ߠ','ߡ'=>'ߡ','ߢ'=>'ߢ','ߣ'=>'ߣ','ߤ'=>'ߤ','ߥ'=>'ߥ','ߦ'=>'ߦ','ߧ'=>'ߧ','ߨ'=>'ߨ','ߩ'=>'ߩ','ߪ'=>'ߪ','߫'=>'߫','߬'=>'߬','߭'=>'߭','߮'=>'߮','߯'=>'߯','߰'=>'߰','߱'=>'߱','߲'=>'߲','߳'=>'߳','ߴ'=>'ߴ','ߵ'=>'ߵ','ߺ'=>'ߺ');
\ No newline at end of file +<?php return array(0=>'0',1=>'1',2=>'2',3=>'3',4=>'4',5=>'5',6=>'6',7=>'7',8=>'8',9=>'9','A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','a'=>'a','b'=>'b','c'=>'c','d'=>'d','e'=>'e','f'=>'f','g'=>'g','h'=>'h','i'=>'i','j'=>'j','k'=>'k','l'=>'l','m'=>'m','n'=>'n','o'=>'o','p'=>'p','q'=>'q','r'=>'r','s'=>'s','t'=>'t','u'=>'u','v'=>'v','w'=>'w','x'=>'x','y'=>'y','z'=>'z','ª'=>'ª','²'=>'2','³'=>'3','µ'=>'µ','¹'=>'1','º'=>'º','¼'=>'1/4','½'=>'1/2','¾'=>'3/4','À'=>'à','Á'=>'á','Â'=>'â','Ã'=>'ã','Ä'=>'ae','Å'=>'å','Æ'=>'ae','Ç'=>'ç','È'=>'è','É'=>'é','Ê'=>'ê','Ë'=>'ë','Ì'=>'ì','Í'=>'í','Î'=>'î','Ï'=>'ï','Ð'=>'ð','Ñ'=>'ñ','Ò'=>'ò','Ó'=>'ó','Ô'=>'ô','Õ'=>'õ','Ö'=>'oe','Ø'=>'ø','Ù'=>'ù','Ú'=>'ú','Û'=>'û','Ü'=>'ü','Ý'=>'ý','Þ'=>'þ','ß'=>'ss','à'=>'à','á'=>'á','â'=>'â','ã'=>'ã','ä'=>'ae','å'=>'å','æ'=>'ae','ç'=>'ç','è'=>'è','é'=>'é','ê'=>'ê','ë'=>'ë','ì'=>'ì','í'=>'í','î'=>'î','ï'=>'ï','ð'=>'ð','ñ'=>'ñ','ò'=>'ò','ó'=>'ó','ô'=>'ô','õ'=>'õ','ö'=>'oe','ø'=>'ø','ù'=>'ù','ú'=>'ú','û'=>'û','ü'=>'ue','ý'=>'ý','þ'=>'þ','ÿ'=>'ÿ','Ā'=>'ā','ā'=>'ā','Ă'=>'ă','ă'=>'ă','Ą'=>'ą','ą'=>'ą','Ć'=>'ć','ć'=>'ć','Ĉ'=>'ĉ','ĉ'=>'ĉ','Ċ'=>'ċ','ċ'=>'ċ','Č'=>'č','č'=>'č','Ď'=>'ď','ď'=>'ď','Đ'=>'đ','đ'=>'đ','Ē'=>'ē','ē'=>'ē','Ĕ'=>'ĕ','ĕ'=>'ĕ','Ė'=>'ė','ė'=>'ė','Ę'=>'ę','ę'=>'ę','Ě'=>'ě','ě'=>'ě','Ĝ'=>'ĝ','ĝ'=>'ĝ','Ğ'=>'ğ','ğ'=>'ğ','Ġ'=>'ġ','ġ'=>'ġ','Ģ'=>'ģ','ģ'=>'ģ','Ĥ'=>'ĥ','ĥ'=>'ĥ','Ħ'=>'ħ','ħ'=>'ħ','Ĩ'=>'ĩ','ĩ'=>'ĩ','Ī'=>'ī','ī'=>'ī','Ĭ'=>'ĭ','ĭ'=>'ĭ','Į'=>'į','į'=>'į','İ'=>'i','ı'=>'ı','IJ'=>'ij','ij'=>'ij','Ĵ'=>'ĵ','ĵ'=>'ĵ','Ķ'=>'ķ','ķ'=>'ķ','ĸ'=>'ĸ','Ĺ'=>'ĺ','ĺ'=>'ĺ','Ļ'=>'ļ','ļ'=>'ļ','Ľ'=>'ľ','ľ'=>'ľ','Ŀ'=>'ŀ','ŀ'=>'ŀ','Ł'=>'ł','ł'=>'ł','Ń'=>'ń','ń'=>'ń','Ņ'=>'ņ','ņ'=>'ņ','Ň'=>'ň','ň'=>'ň','ʼn'=>'ʼn','Ŋ'=>'ŋ','ŋ'=>'ŋ','Ō'=>'ō','ō'=>'ō','Ŏ'=>'ŏ','ŏ'=>'ŏ','Ő'=>'ő','ő'=>'ő','Œ'=>'oe','œ'=>'oe','Ŕ'=>'ŕ','ŕ'=>'ŕ','Ŗ'=>'ŗ','ŗ'=>'ŗ','Ř'=>'ř','ř'=>'ř','Ś'=>'ś','ś'=>'ś','Ŝ'=>'ŝ','ŝ'=>'ŝ','Ş'=>'ş','ş'=>'ş','Š'=>'š','š'=>'š','Ţ'=>'ţ','ţ'=>'ţ','Ť'=>'ť','ť'=>'ť','Ŧ'=>'ŧ','ŧ'=>'ŧ','Ũ'=>'ũ','ũ'=>'ũ','Ū'=>'ū','ū'=>'ū','Ŭ'=>'ŭ','ŭ'=>'ŭ','Ů'=>'ů','ů'=>'ů','Ű'=>'ű','ű'=>'ű','Ų'=>'ų','ų'=>'ų','Ŵ'=>'ŵ','ŵ'=>'ŵ','Ŷ'=>'ŷ','ŷ'=>'ŷ','Ÿ'=>'ÿ','Ź'=>'ź','ź'=>'ź','Ż'=>'ż','ż'=>'ż','Ž'=>'ž','ž'=>'ž','ſ'=>'ſ','ƀ'=>'ƀ','Ɓ'=>'ɓ','Ƃ'=>'ƃ','ƃ'=>'ƃ','Ƅ'=>'ƅ','ƅ'=>'ƅ','Ɔ'=>'ɔ','Ƈ'=>'ƈ','ƈ'=>'ƈ','Ɖ'=>'ɖ','Ɗ'=>'ɗ','Ƌ'=>'ƌ','ƌ'=>'ƌ','ƍ'=>'ƍ','Ǝ'=>'ǝ','Ə'=>'ə','Ɛ'=>'ɛ','Ƒ'=>'ƒ','ƒ'=>'ƒ','Ɠ'=>'ɠ','Ɣ'=>'ɣ','ƕ'=>'hv','Ɩ'=>'ɩ','Ɨ'=>'ɨ','Ƙ'=>'ƙ','ƙ'=>'ƙ','ƚ'=>'ƚ','ƛ'=>'ƛ','Ɯ'=>'ɯ','Ɲ'=>'ɲ','ƞ'=>'ƞ','Ɵ'=>'ɵ','Ơ'=>'ơ','ơ'=>'ơ','Ƣ'=>'oi','ƣ'=>'oi','Ƥ'=>'ƥ','ƥ'=>'ƥ','Ʀ'=>'yr','Ƨ'=>'ƨ','ƨ'=>'ƨ','Ʃ'=>'ʃ','ƪ'=>'ƪ','ƫ'=>'ƫ','Ƭ'=>'ƭ','ƭ'=>'ƭ','Ʈ'=>'ʈ','Ư'=>'ư','ư'=>'ư','Ʊ'=>'ʊ','Ʋ'=>'ʋ','Ƴ'=>'ƴ','ƴ'=>'ƴ','Ƶ'=>'ƶ','ƶ'=>'ƶ','Ʒ'=>'ʒ','Ƹ'=>'ƹ','ƹ'=>'ƹ','ƺ'=>'ƺ','ƻ'=>'ƻ','Ƽ'=>'ƽ','ƽ'=>'ƽ','ƾ'=>'ƾ','ƿ'=>'ƿ','ǀ'=>'ǀ','ǁ'=>'ǁ','ǂ'=>'ǂ','ǃ'=>'ǃ','DŽ'=>'dž','Dž'=>'dž','dž'=>'dž','LJ'=>'lj','Lj'=>'lj','lj'=>'lj','NJ'=>'nj','Nj'=>'nj','nj'=>'nj','Ǎ'=>'ǎ','ǎ'=>'ǎ','Ǐ'=>'ǐ','ǐ'=>'ǐ','Ǒ'=>'ǒ','ǒ'=>'ǒ','Ǔ'=>'ǔ','ǔ'=>'ǔ','Ǖ'=>'ǖ','ǖ'=>'ǖ','Ǘ'=>'ǘ','ǘ'=>'ǘ','Ǚ'=>'ǚ','ǚ'=>'ǚ','Ǜ'=>'ǜ','ǜ'=>'ǜ','ǝ'=>'ǝ','Ǟ'=>'ǟ','ǟ'=>'ǟ','Ǡ'=>'ǡ','ǡ'=>'ǡ','Ǣ'=>'ǣ','ǣ'=>'ǣ','Ǥ'=>'ǥ','ǥ'=>'ǥ','Ǧ'=>'ǧ','ǧ'=>'ǧ','Ǩ'=>'ǩ','ǩ'=>'ǩ','Ǫ'=>'ǫ','ǫ'=>'ǫ','Ǭ'=>'ǭ','ǭ'=>'ǭ','Ǯ'=>'ǯ','ǯ'=>'ǯ','ǰ'=>'ǰ','DZ'=>'dz','Dz'=>'dz','dz'=>'dz','Ǵ'=>'ǵ','ǵ'=>'ǵ','Ƕ'=>'ƕ','Ƿ'=>'ƿ','Ǹ'=>'ǹ','ǹ'=>'ǹ','Ǻ'=>'ǻ','ǻ'=>'ǻ','Ǽ'=>'ǽ','ǽ'=>'ǽ','Ǿ'=>'ǿ','ǿ'=>'ǿ','Ȁ'=>'ȁ','ȁ'=>'ȁ','Ȃ'=>'ȃ','ȃ'=>'ȃ','Ȅ'=>'ȅ','ȅ'=>'ȅ','Ȇ'=>'ȇ','ȇ'=>'ȇ','Ȉ'=>'ȉ','ȉ'=>'ȉ','Ȋ'=>'ȋ','ȋ'=>'ȋ','Ȍ'=>'ȍ','ȍ'=>'ȍ','Ȏ'=>'ȏ','ȏ'=>'ȏ','Ȑ'=>'ȑ','ȑ'=>'ȑ','Ȓ'=>'ȓ','ȓ'=>'ȓ','Ȕ'=>'ȕ','ȕ'=>'ȕ','Ȗ'=>'ȗ','ȗ'=>'ȗ','Ș'=>'ș','ș'=>'ș','Ț'=>'ț','ț'=>'ț','Ȝ'=>'ȝ','ȝ'=>'ȝ','Ȟ'=>'ȟ','ȟ'=>'ȟ','Ƞ'=>'ƞ','ȡ'=>'ȡ','Ȣ'=>'ou','ȣ'=>'ou','Ȥ'=>'ȥ','ȥ'=>'ȥ','Ȧ'=>'ȧ','ȧ'=>'ȧ','Ȩ'=>'ȩ','ȩ'=>'ȩ','Ȫ'=>'ȫ','ȫ'=>'ȫ','Ȭ'=>'ȭ','ȭ'=>'ȭ','Ȯ'=>'ȯ','ȯ'=>'ȯ','Ȱ'=>'ȱ','ȱ'=>'ȱ','Ȳ'=>'ȳ','ȳ'=>'ȳ','ȴ'=>'ȴ','ȵ'=>'ȵ','ȶ'=>'ȶ','ȷ'=>'ȷ','ȸ'=>'ȸ','ȹ'=>'ȹ','Ⱥ'=>'ⱥ','Ȼ'=>'ȼ','ȼ'=>'ȼ','Ƚ'=>'ƚ','Ⱦ'=>'ⱦ','ȿ'=>'ȿ','ɀ'=>'ɀ','Ɂ'=>'ɂ','ɂ'=>'ɂ','Ƀ'=>'ƀ','Ʉ'=>'ʉ','Ʌ'=>'ʌ','Ɇ'=>'ɇ','ɇ'=>'ɇ','Ɉ'=>'ɉ','ɉ'=>'ɉ','Ɋ'=>'ɋ','ɋ'=>'ɋ','Ɍ'=>'ɍ','ɍ'=>'ɍ','Ɏ'=>'ɏ','ɏ'=>'ɏ','ɐ'=>'ɐ','ɑ'=>'ɑ','ɒ'=>'ɒ','ɓ'=>'ɓ','ɔ'=>'ɔ','ɕ'=>'ɕ','ɖ'=>'ɖ','ɗ'=>'ɗ','ɘ'=>'ɘ','ə'=>'ə','ɚ'=>'ɚ','ɛ'=>'ɛ','ɜ'=>'ɜ','ɝ'=>'ɝ','ɞ'=>'ɞ','ɟ'=>'ɟ','ɠ'=>'ɠ','ɡ'=>'ɡ','ɢ'=>'ɢ','ɣ'=>'ɣ','ɤ'=>'ɤ','ɥ'=>'ɥ','ɦ'=>'ɦ','ɧ'=>'ɧ','ɨ'=>'ɨ','ɩ'=>'ɩ','ɪ'=>'ɪ','ɫ'=>'ɫ','ɬ'=>'ɬ','ɭ'=>'ɭ','ɮ'=>'ɮ','ɯ'=>'ɯ','ɰ'=>'ɰ','ɱ'=>'ɱ','ɲ'=>'ɲ','ɳ'=>'ɳ','ɴ'=>'ɴ','ɵ'=>'ɵ','ɶ'=>'ɶ','ɷ'=>'ɷ','ɸ'=>'ɸ','ɹ'=>'ɹ','ɺ'=>'ɺ','ɻ'=>'ɻ','ɼ'=>'ɼ','ɽ'=>'ɽ','ɾ'=>'ɾ','ɿ'=>'ɿ','ʀ'=>'ʀ','ʁ'=>'ʁ','ʂ'=>'ʂ','ʃ'=>'ʃ','ʄ'=>'ʄ','ʅ'=>'ʅ','ʆ'=>'ʆ','ʇ'=>'ʇ','ʈ'=>'ʈ','ʉ'=>'ʉ','ʊ'=>'ʊ','ʋ'=>'ʋ','ʌ'=>'ʌ','ʍ'=>'ʍ','ʎ'=>'ʎ','ʏ'=>'ʏ','ʐ'=>'ʐ','ʑ'=>'ʑ','ʒ'=>'ʒ','ʓ'=>'ʓ','ʔ'=>'ʔ','ʕ'=>'ʕ','ʖ'=>'ʖ','ʗ'=>'ʗ','ʘ'=>'ʘ','ʙ'=>'ʙ','ʚ'=>'ʚ','ʛ'=>'ʛ','ʜ'=>'ʜ','ʝ'=>'ʝ','ʞ'=>'ʞ','ʟ'=>'ʟ','ʠ'=>'ʠ','ʡ'=>'ʡ','ʢ'=>'ʢ','ʣ'=>'ʣ','ʤ'=>'ʤ','ʥ'=>'ʥ','ʦ'=>'ʦ','ʧ'=>'ʧ','ʨ'=>'ʨ','ʩ'=>'ʩ','ʪ'=>'ʪ','ʫ'=>'ʫ','ʬ'=>'ʬ','ʭ'=>'ʭ','ʮ'=>'ʮ','ʯ'=>'ʯ','ʰ'=>'ʰ','ʱ'=>'ʱ','ʲ'=>'ʲ','ʳ'=>'ʳ','ʴ'=>'ʴ','ʵ'=>'ʵ','ʶ'=>'ʶ','ʷ'=>'ʷ','ʸ'=>'ʸ','ʹ'=>'ʹ','ʺ'=>'ʺ','ʻ'=>'ʻ','ʼ'=>'ʼ','ʽ'=>'ʽ','ʾ'=>'ʾ','ʿ'=>'ʿ','ˀ'=>'ˀ','ˁ'=>'ˁ','ˆ'=>'ˆ','ˇ'=>'ˇ','ˈ'=>'ˈ','ˉ'=>'ˉ','ˊ'=>'ˊ','ˋ'=>'ˋ','ˌ'=>'ˌ','ˍ'=>'ˍ','ˎ'=>'ˎ','ˏ'=>'ˏ','ː'=>'ː','ˑ'=>'ˑ','ˠ'=>'ˠ','ˡ'=>'ˡ','ˢ'=>'ˢ','ˣ'=>'ˣ','ˤ'=>'ˤ','ˮ'=>'ˮ','̀'=>'̀','́'=>'́','̂'=>'̂','̃'=>'̃','̄'=>'̄','̅'=>'̅','̆'=>'̆','̇'=>'̇','̈'=>'̈','̉'=>'̉','̊'=>'̊','̋'=>'̋','̌'=>'̌','̍'=>'̍','̎'=>'̎','̏'=>'̏','̐'=>'̐','̑'=>'̑','̒'=>'̒','̓'=>'̓','̔'=>'̔','̕'=>'̕','̖'=>'̖','̗'=>'̗','̘'=>'̘','̙'=>'̙','̚'=>'̚','̛'=>'̛','̜'=>'̜','̝'=>'̝','̞'=>'̞','̟'=>'̟','̠'=>'̠','̡'=>'̡','̢'=>'̢','̣'=>'̣','̤'=>'̤','̥'=>'̥','̦'=>'̦','̧'=>'̧','̨'=>'̨','̩'=>'̩','̪'=>'̪','̫'=>'̫','̬'=>'̬','̭'=>'̭','̮'=>'̮','̯'=>'̯','̰'=>'̰','̱'=>'̱','̲'=>'̲','̳'=>'̳','̴'=>'̴','̵'=>'̵','̶'=>'̶','̷'=>'̷','̸'=>'̸','̹'=>'̹','̺'=>'̺','̻'=>'̻','̼'=>'̼','̽'=>'̽','̾'=>'̾','̿'=>'̿','̀'=>'̀','́'=>'́','͂'=>'͂','̓'=>'̓','̈́'=>'̈́','ͅ'=>'ͅ','͆'=>'͆','͇'=>'͇','͈'=>'͈','͉'=>'͉','͊'=>'͊','͋'=>'͋','͌'=>'͌','͍'=>'͍','͎'=>'͎','͏'=>'͏','͐'=>'͐','͑'=>'͑','͒'=>'͒','͓'=>'͓','͔'=>'͔','͕'=>'͕','͖'=>'͖','͗'=>'͗','͘'=>'͘','͙'=>'͙','͚'=>'͚','͛'=>'͛','͜'=>'͜','͝'=>'͝','͞'=>'͞','͟'=>'͟','͠'=>'͠','͡'=>'͡','͢'=>'͢','ͣ'=>'ͣ','ͤ'=>'ͤ','ͥ'=>'ͥ','ͦ'=>'ͦ','ͧ'=>'ͧ','ͨ'=>'ͨ','ͩ'=>'ͩ','ͪ'=>'ͪ','ͫ'=>'ͫ','ͬ'=>'ͬ','ͭ'=>'ͭ','ͮ'=>'ͮ','ͯ'=>'ͯ','ͺ'=>'ͺ','ͻ'=>'ͻ','ͼ'=>'ͼ','ͽ'=>'ͽ','Ά'=>'ά','Έ'=>'έ','Ή'=>'ή','Ί'=>'ί','Ό'=>'ό','Ύ'=>'ύ','Ώ'=>'ώ','ΐ'=>'ΐ','Α'=>'α','Β'=>'β','Γ'=>'γ','Δ'=>'δ','Ε'=>'ε','Ζ'=>'ζ','Η'=>'η','Θ'=>'θ','Ι'=>'ι','Κ'=>'κ','Λ'=>'λ','Μ'=>'μ','Ν'=>'ν','Ξ'=>'ξ','Ο'=>'ο','Π'=>'π','Ρ'=>'ρ','Σ'=>'σ','Τ'=>'τ','Υ'=>'υ','Φ'=>'φ','Χ'=>'χ','Ψ'=>'ψ','Ω'=>'ω','Ϊ'=>'ϊ','Ϋ'=>'ϋ','ά'=>'ά','έ'=>'έ','ή'=>'ή','ί'=>'ί','ΰ'=>'ΰ','α'=>'α','β'=>'β','γ'=>'γ','δ'=>'δ','ε'=>'ε','ζ'=>'ζ','η'=>'η','θ'=>'θ','ι'=>'ι','κ'=>'κ','λ'=>'λ','μ'=>'μ','ν'=>'ν','ξ'=>'ξ','ο'=>'ο','π'=>'π','ρ'=>'ρ','ς'=>'ς','σ'=>'σ','τ'=>'τ','υ'=>'υ','φ'=>'φ','χ'=>'χ','ψ'=>'ψ','ω'=>'ω','ϊ'=>'ϊ','ϋ'=>'ϋ','ό'=>'ό','ύ'=>'ύ','ώ'=>'ώ','ϐ'=>'ϐ','ϑ'=>'ϑ','ϒ'=>'ϒ','ϓ'=>'ϓ','ϔ'=>'ϔ','ϕ'=>'ϕ','ϖ'=>'ϖ','ϗ'=>'ϗ','Ϙ'=>'ϙ','ϙ'=>'ϙ','Ϛ'=>'ϛ','ϛ'=>'ϛ','Ϝ'=>'ϝ','ϝ'=>'ϝ','Ϟ'=>'ϟ','ϟ'=>'ϟ','Ϡ'=>'ϡ','ϡ'=>'ϡ','Ϣ'=>'ϣ','ϣ'=>'ϣ','Ϥ'=>'ϥ','ϥ'=>'ϥ','Ϧ'=>'ϧ','ϧ'=>'ϧ','Ϩ'=>'ϩ','ϩ'=>'ϩ','Ϫ'=>'ϫ','ϫ'=>'ϫ','Ϭ'=>'ϭ','ϭ'=>'ϭ','Ϯ'=>'ϯ','ϯ'=>'ϯ','ϰ'=>'ϰ','ϱ'=>'ϱ','ϲ'=>'ϲ','ϳ'=>'ϳ','ϴ'=>'θ','ϵ'=>'ϵ','Ϸ'=>'ϸ','ϸ'=>'ϸ','Ϲ'=>'ϲ','Ϻ'=>'ϻ','ϻ'=>'ϻ','ϼ'=>'ϼ','Ͻ'=>'ͻ','Ͼ'=>'ͼ','Ͽ'=>'ͽ','Ѐ'=>'ѐ','Ё'=>'ё','Ђ'=>'ђ','Ѓ'=>'ѓ','Є'=>'є','Ѕ'=>'ѕ','І'=>'і','Ї'=>'ї','Ј'=>'ј','Љ'=>'љ','Њ'=>'њ','Ћ'=>'ћ','Ќ'=>'ќ','Ѝ'=>'ѝ','Ў'=>'ў','Џ'=>'џ','А'=>'а','Б'=>'б','В'=>'в','Г'=>'г','Д'=>'д','Е'=>'е','Ж'=>'ж','З'=>'з','И'=>'и','Й'=>'й','К'=>'к','Л'=>'л','М'=>'м','Н'=>'н','О'=>'о','П'=>'п','Р'=>'р','С'=>'с','Т'=>'т','У'=>'у','Ф'=>'ф','Х'=>'х','Ц'=>'ц','Ч'=>'ч','Ш'=>'ш','Щ'=>'щ','Ъ'=>'ъ','Ы'=>'ы','Ь'=>'ь','Э'=>'э','Ю'=>'ю','Я'=>'я','а'=>'а','б'=>'б','в'=>'в','г'=>'г','д'=>'д','е'=>'е','ж'=>'ж','з'=>'з','и'=>'и','й'=>'й','к'=>'к','л'=>'л','м'=>'м','н'=>'н','о'=>'о','п'=>'п','р'=>'р','с'=>'с','т'=>'т','у'=>'у','ф'=>'ф','х'=>'х','ц'=>'ц','ч'=>'ч','ш'=>'ш','щ'=>'щ','ъ'=>'ъ','ы'=>'ы','ь'=>'ь','э'=>'э','ю'=>'ю','я'=>'я','ѐ'=>'ѐ','ё'=>'ё','ђ'=>'ђ','ѓ'=>'ѓ','є'=>'є','ѕ'=>'ѕ','і'=>'і','ї'=>'ї','ј'=>'ј','љ'=>'љ','њ'=>'њ','ћ'=>'ћ','ќ'=>'ќ','ѝ'=>'ѝ','ў'=>'ў','џ'=>'џ','Ѡ'=>'ѡ','ѡ'=>'ѡ','Ѣ'=>'ѣ','ѣ'=>'ѣ','Ѥ'=>'ѥ','ѥ'=>'ѥ','Ѧ'=>'ѧ','ѧ'=>'ѧ','Ѩ'=>'ѩ','ѩ'=>'ѩ','Ѫ'=>'ѫ','ѫ'=>'ѫ','Ѭ'=>'ѭ','ѭ'=>'ѭ','Ѯ'=>'ѯ','ѯ'=>'ѯ','Ѱ'=>'ѱ','ѱ'=>'ѱ','Ѳ'=>'ѳ','ѳ'=>'ѳ','Ѵ'=>'ѵ','ѵ'=>'ѵ','Ѷ'=>'ѷ','ѷ'=>'ѷ','Ѹ'=>'ѹ','ѹ'=>'ѹ','Ѻ'=>'ѻ','ѻ'=>'ѻ','Ѽ'=>'ѽ','ѽ'=>'ѽ','Ѿ'=>'ѿ','ѿ'=>'ѿ','Ҁ'=>'ҁ','ҁ'=>'ҁ','҃'=>'҃','҄'=>'҄','҅'=>'҅','҆'=>'҆','҈'=>'҈','҉'=>'҉','Ҋ'=>'ҋ','ҋ'=>'ҋ','Ҍ'=>'ҍ','ҍ'=>'ҍ','Ҏ'=>'ҏ','ҏ'=>'ҏ','Ґ'=>'ґ','ґ'=>'ґ','Ғ'=>'ғ','ғ'=>'ғ','Ҕ'=>'ҕ','ҕ'=>'ҕ','Җ'=>'җ','җ'=>'җ','Ҙ'=>'ҙ','ҙ'=>'ҙ','Қ'=>'қ','қ'=>'қ','Ҝ'=>'ҝ','ҝ'=>'ҝ','Ҟ'=>'ҟ','ҟ'=>'ҟ','Ҡ'=>'ҡ','ҡ'=>'ҡ','Ң'=>'ң','ң'=>'ң','Ҥ'=>'ҥ','ҥ'=>'ҥ','Ҧ'=>'ҧ','ҧ'=>'ҧ','Ҩ'=>'ҩ','ҩ'=>'ҩ','Ҫ'=>'ҫ','ҫ'=>'ҫ','Ҭ'=>'ҭ','ҭ'=>'ҭ','Ү'=>'ү','ү'=>'ү','Ұ'=>'ұ','ұ'=>'ұ','Ҳ'=>'ҳ','ҳ'=>'ҳ','Ҵ'=>'ҵ','ҵ'=>'ҵ','Ҷ'=>'ҷ','ҷ'=>'ҷ','Ҹ'=>'ҹ','ҹ'=>'ҹ','Һ'=>'һ','һ'=>'һ','Ҽ'=>'ҽ','ҽ'=>'ҽ','Ҿ'=>'ҿ','ҿ'=>'ҿ','Ӏ'=>'ӏ','Ӂ'=>'ӂ','ӂ'=>'ӂ','Ӄ'=>'ӄ','ӄ'=>'ӄ','Ӆ'=>'ӆ','ӆ'=>'ӆ','Ӈ'=>'ӈ','ӈ'=>'ӈ','Ӊ'=>'ӊ','ӊ'=>'ӊ','Ӌ'=>'ӌ','ӌ'=>'ӌ','Ӎ'=>'ӎ','ӎ'=>'ӎ','ӏ'=>'ӏ','Ӑ'=>'ӑ','ӑ'=>'ӑ','Ӓ'=>'ӓ','ӓ'=>'ӓ','Ӕ'=>'ӕ','ӕ'=>'ӕ','Ӗ'=>'ӗ','ӗ'=>'ӗ','Ә'=>'ә','ә'=>'ә','Ӛ'=>'ӛ','ӛ'=>'ӛ','Ӝ'=>'ӝ','ӝ'=>'ӝ','Ӟ'=>'ӟ','ӟ'=>'ӟ','Ӡ'=>'ӡ','ӡ'=>'ӡ','Ӣ'=>'ӣ','ӣ'=>'ӣ','Ӥ'=>'ӥ','ӥ'=>'ӥ','Ӧ'=>'ӧ','ӧ'=>'ӧ','Ө'=>'ө','ө'=>'ө','Ӫ'=>'ӫ','ӫ'=>'ӫ','Ӭ'=>'ӭ','ӭ'=>'ӭ','Ӯ'=>'ӯ','ӯ'=>'ӯ','Ӱ'=>'ӱ','ӱ'=>'ӱ','Ӳ'=>'ӳ','ӳ'=>'ӳ','Ӵ'=>'ӵ','ӵ'=>'ӵ','Ӷ'=>'ӷ','ӷ'=>'ӷ','Ӹ'=>'ӹ','ӹ'=>'ӹ','Ӻ'=>'ӻ','ӻ'=>'ӻ','Ӽ'=>'ӽ','ӽ'=>'ӽ','Ӿ'=>'ӿ','ӿ'=>'ӿ','Ԁ'=>'ԁ','ԁ'=>'ԁ','Ԃ'=>'ԃ','ԃ'=>'ԃ','Ԅ'=>'ԅ','ԅ'=>'ԅ','Ԇ'=>'ԇ','ԇ'=>'ԇ','Ԉ'=>'ԉ','ԉ'=>'ԉ','Ԋ'=>'ԋ','ԋ'=>'ԋ','Ԍ'=>'ԍ','ԍ'=>'ԍ','Ԏ'=>'ԏ','ԏ'=>'ԏ','Ԑ'=>'ԑ','ԑ'=>'ԑ','Ԓ'=>'ԓ','ԓ'=>'ԓ','Ա'=>'ա','Բ'=>'բ','Գ'=>'գ','Դ'=>'դ','Ե'=>'ե','Զ'=>'զ','Է'=>'է','Ը'=>'ը','Թ'=>'թ','Ժ'=>'ժ','Ի'=>'ի','Լ'=>'լ','Խ'=>'խ','Ծ'=>'ծ','Կ'=>'կ','Հ'=>'հ','Ձ'=>'ձ','Ղ'=>'ղ','Ճ'=>'ճ','Մ'=>'մ','Յ'=>'յ','Ն'=>'ն','Շ'=>'շ','Ո'=>'ո','Չ'=>'չ','Պ'=>'պ','Ջ'=>'ջ','Ռ'=>'ռ','Ս'=>'ս','Վ'=>'վ','Տ'=>'տ','Ր'=>'ր','Ց'=>'ց','Ւ'=>'ւ','Փ'=>'փ','Ք'=>'ք','Օ'=>'օ','Ֆ'=>'ֆ','ՙ'=>'ՙ','ա'=>'ա','բ'=>'բ','գ'=>'գ','դ'=>'դ','ե'=>'ե','զ'=>'զ','է'=>'է','ը'=>'ը','թ'=>'թ','ժ'=>'ժ','ի'=>'ի','լ'=>'լ','խ'=>'խ','ծ'=>'ծ','կ'=>'կ','հ'=>'հ','ձ'=>'ձ','ղ'=>'ղ','ճ'=>'ճ','մ'=>'մ','յ'=>'յ','ն'=>'ն','շ'=>'շ','ո'=>'ո','չ'=>'չ','պ'=>'պ','ջ'=>'ջ','ռ'=>'ռ','ս'=>'ս','վ'=>'վ','տ'=>'տ','ր'=>'ր','ց'=>'ց','ւ'=>'ւ','փ'=>'փ','ք'=>'ք','օ'=>'օ','ֆ'=>'ֆ','և'=>'և','֑'=>'֑','֒'=>'֒','֓'=>'֓','֔'=>'֔','֕'=>'֕','֖'=>'֖','֗'=>'֗','֘'=>'֘','֙'=>'֙','֚'=>'֚','֛'=>'֛','֜'=>'֜','֝'=>'֝','֞'=>'֞','֟'=>'֟','֠'=>'֠','֡'=>'֡','֢'=>'֢','֣'=>'֣','֤'=>'֤','֥'=>'֥','֦'=>'֦','֧'=>'֧','֨'=>'֨','֩'=>'֩','֪'=>'֪','֫'=>'֫','֬'=>'֬','֭'=>'֭','֮'=>'֮','֯'=>'֯','ְ'=>'ְ','ֱ'=>'ֱ','ֲ'=>'ֲ','ֳ'=>'ֳ','ִ'=>'ִ','ֵ'=>'ֵ','ֶ'=>'ֶ','ַ'=>'ַ','ָ'=>'ָ','ֹ'=>'ֹ','ֺ'=>'ֺ','ֻ'=>'ֻ','ּ'=>'ּ','ֽ'=>'ֽ','ֿ'=>'ֿ','ׁ'=>'ׁ','ׂ'=>'ׂ','ׄ'=>'ׄ','ׅ'=>'ׅ','ׇ'=>'ׇ','א'=>'א','ב'=>'ב','ג'=>'ג','ד'=>'ד','ה'=>'ה','ו'=>'ו','ז'=>'ז','ח'=>'ח','ט'=>'ט','י'=>'י','ך'=>'ך','כ'=>'כ','ל'=>'ל','ם'=>'ם','מ'=>'מ','ן'=>'ן','נ'=>'נ','ס'=>'ס','ע'=>'ע','ף'=>'ף','פ'=>'פ','ץ'=>'ץ','צ'=>'צ','ק'=>'ק','ר'=>'ר','ש'=>'ש','ת'=>'ת','װ'=>'װ','ױ'=>'ױ','ײ'=>'ײ','ؐ'=>'ؐ','ؑ'=>'ؑ','ؒ'=>'ؒ','ؓ'=>'ؓ','ؔ'=>'ؔ','ؕ'=>'ؕ','ء'=>'ء','آ'=>'آ','أ'=>'أ','ؤ'=>'ؤ','إ'=>'إ','ئ'=>'ئ','ا'=>'ا','ب'=>'ب','ة'=>'ة','ت'=>'ت','ث'=>'ث','ج'=>'ج','ح'=>'ح','خ'=>'خ','د'=>'د','ذ'=>'ذ','ر'=>'ر','ز'=>'ز','س'=>'س','ش'=>'ش','ص'=>'ص','ض'=>'ض','ط'=>'ط','ظ'=>'ظ','ع'=>'ع','غ'=>'غ','ـ'=>'ـ','ف'=>'ف','ق'=>'ق','ك'=>'ك','ل'=>'ل','م'=>'م','ن'=>'ن','ه'=>'ه','و'=>'و','ى'=>'ى','ي'=>'ي','ً'=>'ً','ٌ'=>'ٌ','ٍ'=>'ٍ','َ'=>'َ','ُ'=>'ُ','ِ'=>'ِ','ّ'=>'ّ','ْ'=>'ْ','ٓ'=>'ٓ','ٔ'=>'ٔ','ٕ'=>'ٕ','ٖ'=>'ٖ','ٗ'=>'ٗ','٘'=>'٘','ٙ'=>'ٙ','ٚ'=>'ٚ','ٛ'=>'ٛ','ٜ'=>'ٜ','ٝ'=>'ٝ','ٞ'=>'ٞ','٠'=>'0','١'=>'1','٢'=>'2','٣'=>'3','٤'=>'4','٥'=>'5','٦'=>'6','٧'=>'7','٨'=>'8','٩'=>'9','ٮ'=>'ٮ','ٯ'=>'ٯ','ٰ'=>'ٰ','ٱ'=>'ٱ','ٲ'=>'ٲ','ٳ'=>'ٳ','ٴ'=>'ٴ','ٵ'=>'ٵ','ٶ'=>'ٶ','ٷ'=>'ٷ','ٸ'=>'ٸ','ٹ'=>'ٹ','ٺ'=>'ٺ','ٻ'=>'ٻ','ټ'=>'ټ','ٽ'=>'ٽ','پ'=>'پ','ٿ'=>'ٿ','ڀ'=>'ڀ','ځ'=>'ځ','ڂ'=>'ڂ','ڃ'=>'ڃ','ڄ'=>'ڄ','څ'=>'څ','چ'=>'چ','ڇ'=>'ڇ','ڈ'=>'ڈ','ډ'=>'ډ','ڊ'=>'ڊ','ڋ'=>'ڋ','ڌ'=>'ڌ','ڍ'=>'ڍ','ڎ'=>'ڎ','ڏ'=>'ڏ','ڐ'=>'ڐ','ڑ'=>'ڑ','ڒ'=>'ڒ','ړ'=>'ړ','ڔ'=>'ڔ','ڕ'=>'ڕ','ږ'=>'ږ','ڗ'=>'ڗ','ژ'=>'ژ','ڙ'=>'ڙ','ښ'=>'ښ','ڛ'=>'ڛ','ڜ'=>'ڜ','ڝ'=>'ڝ','ڞ'=>'ڞ','ڟ'=>'ڟ','ڠ'=>'ڠ','ڡ'=>'ڡ','ڢ'=>'ڢ','ڣ'=>'ڣ','ڤ'=>'ڤ','ڥ'=>'ڥ','ڦ'=>'ڦ','ڧ'=>'ڧ','ڨ'=>'ڨ','ک'=>'ک','ڪ'=>'ڪ','ګ'=>'ګ','ڬ'=>'ڬ','ڭ'=>'ڭ','ڮ'=>'ڮ','گ'=>'گ','ڰ'=>'ڰ','ڱ'=>'ڱ','ڲ'=>'ڲ','ڳ'=>'ڳ','ڴ'=>'ڴ','ڵ'=>'ڵ','ڶ'=>'ڶ','ڷ'=>'ڷ','ڸ'=>'ڸ','ڹ'=>'ڹ','ں'=>'ں','ڻ'=>'ڻ','ڼ'=>'ڼ','ڽ'=>'ڽ','ھ'=>'ھ','ڿ'=>'ڿ','ۀ'=>'ۀ','ہ'=>'ہ','ۂ'=>'ۂ','ۃ'=>'ۃ','ۄ'=>'ۄ','ۅ'=>'ۅ','ۆ'=>'ۆ','ۇ'=>'ۇ','ۈ'=>'ۈ','ۉ'=>'ۉ','ۊ'=>'ۊ','ۋ'=>'ۋ','ی'=>'ی','ۍ'=>'ۍ','ێ'=>'ێ','ۏ'=>'ۏ','ې'=>'ې','ۑ'=>'ۑ','ے'=>'ے','ۓ'=>'ۓ','ە'=>'ە','ۖ'=>'ۖ','ۗ'=>'ۗ','ۘ'=>'ۘ','ۙ'=>'ۙ','ۚ'=>'ۚ','ۛ'=>'ۛ','ۜ'=>'ۜ','۞'=>'۞','۟'=>'۟','۠'=>'۠','ۡ'=>'ۡ','ۢ'=>'ۢ','ۣ'=>'ۣ','ۤ'=>'ۤ','ۥ'=>'ۥ','ۦ'=>'ۦ','ۧ'=>'ۧ','ۨ'=>'ۨ','۪'=>'۪','۫'=>'۫','۬'=>'۬','ۭ'=>'ۭ','ۮ'=>'ۮ','ۯ'=>'ۯ','۰'=>'0','۱'=>'1','۲'=>'2','۳'=>'3','۴'=>'4','۵'=>'5','۶'=>'6','۷'=>'7','۸'=>'8','۹'=>'9','ۺ'=>'ۺ','ۻ'=>'ۻ','ۼ'=>'ۼ','ۿ'=>'ۿ','ܐ'=>'ܐ','ܑ'=>'ܑ','ܒ'=>'ܒ','ܓ'=>'ܓ','ܔ'=>'ܔ','ܕ'=>'ܕ','ܖ'=>'ܖ','ܗ'=>'ܗ','ܘ'=>'ܘ','ܙ'=>'ܙ','ܚ'=>'ܚ','ܛ'=>'ܛ','ܜ'=>'ܜ','ܝ'=>'ܝ','ܞ'=>'ܞ','ܟ'=>'ܟ','ܠ'=>'ܠ','ܡ'=>'ܡ','ܢ'=>'ܢ','ܣ'=>'ܣ','ܤ'=>'ܤ','ܥ'=>'ܥ','ܦ'=>'ܦ','ܧ'=>'ܧ','ܨ'=>'ܨ','ܩ'=>'ܩ','ܪ'=>'ܪ','ܫ'=>'ܫ','ܬ'=>'ܬ','ܭ'=>'ܭ','ܮ'=>'ܮ','ܯ'=>'ܯ','ܰ'=>'ܰ','ܱ'=>'ܱ','ܲ'=>'ܲ','ܳ'=>'ܳ','ܴ'=>'ܴ','ܵ'=>'ܵ','ܶ'=>'ܶ','ܷ'=>'ܷ','ܸ'=>'ܸ','ܹ'=>'ܹ','ܺ'=>'ܺ','ܻ'=>'ܻ','ܼ'=>'ܼ','ܽ'=>'ܽ','ܾ'=>'ܾ','ܿ'=>'ܿ','݀'=>'݀','݁'=>'݁','݂'=>'݂','݃'=>'݃','݄'=>'݄','݅'=>'݅','݆'=>'݆','݇'=>'݇','݈'=>'݈','݉'=>'݉','݊'=>'݊','ݍ'=>'ݍ','ݎ'=>'ݎ','ݏ'=>'ݏ','ݐ'=>'ݐ','ݑ'=>'ݑ','ݒ'=>'ݒ','ݓ'=>'ݓ','ݔ'=>'ݔ','ݕ'=>'ݕ','ݖ'=>'ݖ','ݗ'=>'ݗ','ݘ'=>'ݘ','ݙ'=>'ݙ','ݚ'=>'ݚ','ݛ'=>'ݛ','ݜ'=>'ݜ','ݝ'=>'ݝ','ݞ'=>'ݞ','ݟ'=>'ݟ','ݠ'=>'ݠ','ݡ'=>'ݡ','ݢ'=>'ݢ','ݣ'=>'ݣ','ݤ'=>'ݤ','ݥ'=>'ݥ','ݦ'=>'ݦ','ݧ'=>'ݧ','ݨ'=>'ݨ','ݩ'=>'ݩ','ݪ'=>'ݪ','ݫ'=>'ݫ','ݬ'=>'ݬ','ݭ'=>'ݭ','ހ'=>'ހ','ށ'=>'ށ','ނ'=>'ނ','ރ'=>'ރ','ބ'=>'ބ','ޅ'=>'ޅ','ކ'=>'ކ','އ'=>'އ','ވ'=>'ވ','މ'=>'މ','ފ'=>'ފ','ދ'=>'ދ','ތ'=>'ތ','ލ'=>'ލ','ގ'=>'ގ','ޏ'=>'ޏ','ސ'=>'ސ','ޑ'=>'ޑ','ޒ'=>'ޒ','ޓ'=>'ޓ','ޔ'=>'ޔ','ޕ'=>'ޕ','ޖ'=>'ޖ','ޗ'=>'ޗ','ޘ'=>'ޘ','ޙ'=>'ޙ','ޚ'=>'ޚ','ޛ'=>'ޛ','ޜ'=>'ޜ','ޝ'=>'ޝ','ޞ'=>'ޞ','ޟ'=>'ޟ','ޠ'=>'ޠ','ޡ'=>'ޡ','ޢ'=>'ޢ','ޣ'=>'ޣ','ޤ'=>'ޤ','ޥ'=>'ޥ','ަ'=>'ަ','ާ'=>'ާ','ި'=>'ި','ީ'=>'ީ','ު'=>'ު','ޫ'=>'ޫ','ެ'=>'ެ','ޭ'=>'ޭ','ޮ'=>'ޮ','ޯ'=>'ޯ','ް'=>'ް','ޱ'=>'ޱ','߀'=>'0','߁'=>'1','߂'=>'2','߃'=>'3','߄'=>'4','߅'=>'5','߆'=>'6','߇'=>'7','߈'=>'8','߉'=>'9','ߊ'=>'ߊ','ߋ'=>'ߋ','ߌ'=>'ߌ','ߍ'=>'ߍ','ߎ'=>'ߎ','ߏ'=>'ߏ','ߐ'=>'ߐ','ߑ'=>'ߑ','ߒ'=>'ߒ','ߓ'=>'ߓ','ߔ'=>'ߔ','ߕ'=>'ߕ','ߖ'=>'ߖ','ߗ'=>'ߗ','ߘ'=>'ߘ','ߙ'=>'ߙ','ߚ'=>'ߚ','ߛ'=>'ߛ','ߜ'=>'ߜ','ߝ'=>'ߝ','ߞ'=>'ߞ','ߟ'=>'ߟ','ߠ'=>'ߠ','ߡ'=>'ߡ','ߢ'=>'ߢ','ߣ'=>'ߣ','ߤ'=>'ߤ','ߥ'=>'ߥ','ߦ'=>'ߦ','ߧ'=>'ߧ','ߨ'=>'ߨ','ߩ'=>'ߩ','ߪ'=>'ߪ','߫'=>'߫','߬'=>'߬','߭'=>'߭','߮'=>'߮','߯'=>'߯','߰'=>'߰','߱'=>'߱','߲'=>'߲','߳'=>'߳','ߴ'=>'ߴ','ߵ'=>'ߵ','ߺ'=>'ߺ'); diff --git a/phpBB/includes/utf/data/search_indexer_1.php b/phpBB/includes/utf/data/search_indexer_1.php index 6173117ffc..4dd142bb43 100644 --- a/phpBB/includes/utf/data/search_indexer_1.php +++ b/phpBB/includes/utf/data/search_indexer_1.php @@ -1 +1 @@ -<?php return array('ँ'=>'ँ','ं'=>'ं','ः'=>'ः','ऄ'=>'ऄ','अ'=>'अ','आ'=>'आ','इ'=>'इ','ई'=>'ई','उ'=>'उ','ऊ'=>'ऊ','ऋ'=>'ऋ','ऌ'=>'ऌ','ऍ'=>'ऍ','ऎ'=>'ऎ','ए'=>'ए','ऐ'=>'ऐ','ऑ'=>'ऑ','ऒ'=>'ऒ','ओ'=>'ओ','औ'=>'औ','क'=>'क','ख'=>'ख','ग'=>'ग','घ'=>'घ','ङ'=>'ङ','च'=>'च','छ'=>'छ','ज'=>'ज','झ'=>'झ','ञ'=>'ञ','ट'=>'ट','ठ'=>'ठ','ड'=>'ड','ढ'=>'ढ','ण'=>'ण','त'=>'त','थ'=>'थ','द'=>'द','ध'=>'ध','न'=>'न','ऩ'=>'ऩ','प'=>'प','फ'=>'फ','ब'=>'ब','भ'=>'भ','म'=>'म','य'=>'य','र'=>'र','ऱ'=>'ऱ','ल'=>'ल','ळ'=>'ळ','ऴ'=>'ऴ','व'=>'व','श'=>'श','ष'=>'ष','स'=>'स','ह'=>'ह','़'=>'़','ऽ'=>'ऽ','ा'=>'ा','ि'=>'ि','ी'=>'ी','ु'=>'ु','ू'=>'ू','ृ'=>'ृ','ॄ'=>'ॄ','ॅ'=>'ॅ','ॆ'=>'ॆ','े'=>'े','ै'=>'ै','ॉ'=>'ॉ','ॊ'=>'ॊ','ो'=>'ो','ौ'=>'ौ','्'=>'्','ॐ'=>'ॐ','॑'=>'॑','॒'=>'॒','॓'=>'॓','॔'=>'॔','क़'=>'क़','ख़'=>'ख़','ग़'=>'ग़','ज़'=>'ज़','ड़'=>'ड़','ढ़'=>'ढ़','फ़'=>'फ़','य़'=>'य़','ॠ'=>'ॠ','ॡ'=>'ॡ','ॢ'=>'ॢ','ॣ'=>'ॣ','०'=>'0','१'=>'1','२'=>'2','३'=>'3','४'=>'4','५'=>'5','६'=>'6','७'=>'7','८'=>'8','९'=>'9','ॻ'=>'ॻ','ॼ'=>'ॼ','ॽ'=>'ॽ','ॾ'=>'ॾ','ॿ'=>'ॿ','ঁ'=>'ঁ','ং'=>'ং','ঃ'=>'ঃ','অ'=>'অ','আ'=>'আ','ই'=>'ই','ঈ'=>'ঈ','উ'=>'উ','ঊ'=>'ঊ','ঋ'=>'ঋ','ঌ'=>'ঌ','এ'=>'এ','ঐ'=>'ঐ','ও'=>'ও','ঔ'=>'ঔ','ক'=>'ক','খ'=>'খ','গ'=>'গ','ঘ'=>'ঘ','ঙ'=>'ঙ','চ'=>'চ','ছ'=>'ছ','জ'=>'জ','ঝ'=>'ঝ','ঞ'=>'ঞ','ট'=>'ট','ঠ'=>'ঠ','ড'=>'ড','ঢ'=>'ঢ','ণ'=>'ণ','ত'=>'ত','থ'=>'থ','দ'=>'দ','ধ'=>'ধ','ন'=>'ন','প'=>'প','ফ'=>'ফ','ব'=>'ব','ভ'=>'ভ','ম'=>'ম','য'=>'য','র'=>'র','ল'=>'ল','শ'=>'শ','ষ'=>'ষ','স'=>'স','হ'=>'হ','়'=>'়','ঽ'=>'ঽ','া'=>'া','ি'=>'ি','ী'=>'ী','ু'=>'ু','ূ'=>'ূ','ৃ'=>'ৃ','ৄ'=>'ৄ','ে'=>'ে','ৈ'=>'ৈ','ো'=>'ো','ৌ'=>'ৌ','্'=>'্','ৎ'=>'ৎ','ৗ'=>'ৗ','ড়'=>'ড়','ঢ়'=>'ঢ়','য়'=>'য়','ৠ'=>'ৠ','ৡ'=>'ৡ','ৢ'=>'ৢ','ৣ'=>'ৣ','০'=>'0','১'=>'1','২'=>'2','৩'=>'3','৪'=>'4','৫'=>'5','৬'=>'6','৭'=>'7','৮'=>'8','৯'=>'9','ৰ'=>'ৰ','ৱ'=>'ৱ','৴'=>'1','৵'=>'2','৶'=>'3','৷'=>'4','৸'=>'৸','৹'=>'16','ਁ'=>'ਁ','ਂ'=>'ਂ','ਃ'=>'ਃ','ਅ'=>'ਅ','ਆ'=>'ਆ','ਇ'=>'ਇ','ਈ'=>'ਈ','ਉ'=>'ਉ','ਊ'=>'ਊ','ਏ'=>'ਏ','ਐ'=>'ਐ','ਓ'=>'ਓ','ਔ'=>'ਔ','ਕ'=>'ਕ','ਖ'=>'ਖ','ਗ'=>'ਗ','ਘ'=>'ਘ','ਙ'=>'ਙ','ਚ'=>'ਚ','ਛ'=>'ਛ','ਜ'=>'ਜ','ਝ'=>'ਝ','ਞ'=>'ਞ','ਟ'=>'ਟ','ਠ'=>'ਠ','ਡ'=>'ਡ','ਢ'=>'ਢ','ਣ'=>'ਣ','ਤ'=>'ਤ','ਥ'=>'ਥ','ਦ'=>'ਦ','ਧ'=>'ਧ','ਨ'=>'ਨ','ਪ'=>'ਪ','ਫ'=>'ਫ','ਬ'=>'ਬ','ਭ'=>'ਭ','ਮ'=>'ਮ','ਯ'=>'ਯ','ਰ'=>'ਰ','ਲ'=>'ਲ','ਲ਼'=>'ਲ਼','ਵ'=>'ਵ','ਸ਼'=>'ਸ਼','ਸ'=>'ਸ','ਹ'=>'ਹ','਼'=>'਼','ਾ'=>'ਾ','ਿ'=>'ਿ','ੀ'=>'ੀ','ੁ'=>'ੁ','ੂ'=>'ੂ','ੇ'=>'ੇ','ੈ'=>'ੈ','ੋ'=>'ੋ','ੌ'=>'ੌ','੍'=>'੍','ਖ਼'=>'ਖ਼','ਗ਼'=>'ਗ਼','ਜ਼'=>'ਜ਼','ੜ'=>'ੜ','ਫ਼'=>'ਫ਼','੦'=>'0','੧'=>'1','੨'=>'2','੩'=>'3','੪'=>'4','੫'=>'5','੬'=>'6','੭'=>'7','੮'=>'8','੯'=>'9','ੰ'=>'ੰ','ੱ'=>'ੱ','ੲ'=>'ੲ','ੳ'=>'ੳ','ੴ'=>'ੴ','ઁ'=>'ઁ','ં'=>'ં','ઃ'=>'ઃ','અ'=>'અ','આ'=>'આ','ઇ'=>'ઇ','ઈ'=>'ઈ','ઉ'=>'ઉ','ઊ'=>'ઊ','ઋ'=>'ઋ','ઌ'=>'ઌ','ઍ'=>'ઍ','એ'=>'એ','ઐ'=>'ઐ','ઑ'=>'ઑ','ઓ'=>'ઓ','ઔ'=>'ઔ','ક'=>'ક','ખ'=>'ખ','ગ'=>'ગ','ઘ'=>'ઘ','ઙ'=>'ઙ','ચ'=>'ચ','છ'=>'છ','જ'=>'જ','ઝ'=>'ઝ','ઞ'=>'ઞ','ટ'=>'ટ','ઠ'=>'ઠ','ડ'=>'ડ','ઢ'=>'ઢ','ણ'=>'ણ','ત'=>'ત','થ'=>'થ','દ'=>'દ','ધ'=>'ધ','ન'=>'ન','પ'=>'પ','ફ'=>'ફ','બ'=>'બ','ભ'=>'ભ','મ'=>'મ','ય'=>'ય','ર'=>'ર','લ'=>'લ','ળ'=>'ળ','વ'=>'વ','શ'=>'શ','ષ'=>'ષ','સ'=>'સ','હ'=>'હ','઼'=>'઼','ઽ'=>'ઽ','ા'=>'ા','િ'=>'િ','ી'=>'ી','ુ'=>'ુ','ૂ'=>'ૂ','ૃ'=>'ૃ','ૄ'=>'ૄ','ૅ'=>'ૅ','ે'=>'ે','ૈ'=>'ૈ','ૉ'=>'ૉ','ો'=>'ો','ૌ'=>'ૌ','્'=>'્','ૐ'=>'ૐ','ૠ'=>'ૠ','ૡ'=>'ૡ','ૢ'=>'ૢ','ૣ'=>'ૣ','૦'=>'0','૧'=>'1','૨'=>'2','૩'=>'3','૪'=>'4','૫'=>'5','૬'=>'6','૭'=>'7','૮'=>'8','૯'=>'9','ଁ'=>'ଁ','ଂ'=>'ଂ','ଃ'=>'ଃ','ଅ'=>'ଅ','ଆ'=>'ଆ','ଇ'=>'ଇ','ଈ'=>'ଈ','ଉ'=>'ଉ','ଊ'=>'ଊ','ଋ'=>'ଋ','ଌ'=>'ଌ','ଏ'=>'ଏ','ଐ'=>'ଐ','ଓ'=>'ଓ','ଔ'=>'ଔ','କ'=>'କ','ଖ'=>'ଖ','ଗ'=>'ଗ','ଘ'=>'ଘ','ଙ'=>'ଙ','ଚ'=>'ଚ','ଛ'=>'ଛ','ଜ'=>'ଜ','ଝ'=>'ଝ','ଞ'=>'ଞ','ଟ'=>'ଟ','ଠ'=>'ଠ','ଡ'=>'ଡ','ଢ'=>'ଢ','ଣ'=>'ଣ','ତ'=>'ତ','ଥ'=>'ଥ','ଦ'=>'ଦ','ଧ'=>'ଧ','ନ'=>'ନ','ପ'=>'ପ','ଫ'=>'ଫ','ବ'=>'ବ','ଭ'=>'ଭ','ମ'=>'ମ','ଯ'=>'ଯ','ର'=>'ର','ଲ'=>'ଲ','ଳ'=>'ଳ','ଵ'=>'ଵ','ଶ'=>'ଶ','ଷ'=>'ଷ','ସ'=>'ସ','ହ'=>'ହ','଼'=>'଼','ଽ'=>'ଽ','ା'=>'ା','ି'=>'ି','ୀ'=>'ୀ','ୁ'=>'ୁ','ୂ'=>'ୂ','ୃ'=>'ୃ','େ'=>'େ','ୈ'=>'ୈ','ୋ'=>'ୋ','ୌ'=>'ୌ','୍'=>'୍','ୖ'=>'ୖ','ୗ'=>'ୗ','ଡ଼'=>'ଡ଼','ଢ଼'=>'ଢ଼','ୟ'=>'ୟ','ୠ'=>'ୠ','ୡ'=>'ୡ','୦'=>'0','୧'=>'1','୨'=>'2','୩'=>'3','୪'=>'4','୫'=>'5','୬'=>'6','୭'=>'7','୮'=>'8','୯'=>'9','ୱ'=>'ୱ','ஂ'=>'ஂ','ஃ'=>'ஃ','அ'=>'அ','ஆ'=>'ஆ','இ'=>'இ','ஈ'=>'ஈ','உ'=>'உ','ஊ'=>'ஊ','எ'=>'எ','ஏ'=>'ஏ','ஐ'=>'ஐ','ஒ'=>'ஒ','ஓ'=>'ஓ','ஔ'=>'ஔ','க'=>'க','ங'=>'ங','ச'=>'ச','ஜ'=>'ஜ','ஞ'=>'ஞ','ட'=>'ட','ண'=>'ண','த'=>'த','ந'=>'ந','ன'=>'ன','ப'=>'ப','ம'=>'ம','ய'=>'ய','ர'=>'ர','ற'=>'ற','ல'=>'ல','ள'=>'ள','ழ'=>'ழ','வ'=>'வ','ஶ'=>'ஶ','ஷ'=>'ஷ','ஸ'=>'ஸ','ஹ'=>'ஹ','ா'=>'ா','ி'=>'ி','ீ'=>'ீ','ு'=>'ு','ூ'=>'ூ','ெ'=>'ெ','ே'=>'ே','ை'=>'ை','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','்'=>'்','ௗ'=>'ௗ','௦'=>'0','௧'=>'1','௨'=>'2','௩'=>'3','௪'=>'4','௫'=>'5','௬'=>'6','௭'=>'7','௮'=>'8','௯'=>'9','௰'=>'10','௱'=>'100','௲'=>'1000','ఁ'=>'ఁ','ం'=>'ం','ః'=>'ః','అ'=>'అ','ఆ'=>'ఆ','ఇ'=>'ఇ','ఈ'=>'ఈ','ఉ'=>'ఉ','ఊ'=>'ఊ','ఋ'=>'ఋ','ఌ'=>'ఌ','ఎ'=>'ఎ','ఏ'=>'ఏ','ఐ'=>'ఐ','ఒ'=>'ఒ','ఓ'=>'ఓ','ఔ'=>'ఔ','క'=>'క','ఖ'=>'ఖ','గ'=>'గ','ఘ'=>'ఘ','ఙ'=>'ఙ','చ'=>'చ','ఛ'=>'ఛ','జ'=>'జ','ఝ'=>'ఝ','ఞ'=>'ఞ','ట'=>'ట','ఠ'=>'ఠ','డ'=>'డ','ఢ'=>'ఢ','ణ'=>'ణ','త'=>'త','థ'=>'థ','ద'=>'ద','ధ'=>'ధ','న'=>'న','ప'=>'ప','ఫ'=>'ఫ','బ'=>'బ','భ'=>'భ','మ'=>'మ','య'=>'య','ర'=>'ర','ఱ'=>'ఱ','ల'=>'ల','ళ'=>'ళ','వ'=>'వ','శ'=>'శ','ష'=>'ష','స'=>'స','హ'=>'హ','ా'=>'ా','ి'=>'ి','ీ'=>'ీ','ు'=>'ు','ూ'=>'ూ','ృ'=>'ృ','ౄ'=>'ౄ','ె'=>'ె','ే'=>'ే','ై'=>'ై','ొ'=>'ొ','ో'=>'ో','ౌ'=>'ౌ','్'=>'్','ౕ'=>'ౕ','ౖ'=>'ౖ','ౠ'=>'ౠ','ౡ'=>'ౡ','౦'=>'0','౧'=>'1','౨'=>'2','౩'=>'3','౪'=>'4','౫'=>'5','౬'=>'6','౭'=>'7','౮'=>'8','౯'=>'9','ಂ'=>'ಂ','ಃ'=>'ಃ','ಅ'=>'ಅ','ಆ'=>'ಆ','ಇ'=>'ಇ','ಈ'=>'ಈ','ಉ'=>'ಉ','ಊ'=>'ಊ','ಋ'=>'ಋ','ಌ'=>'ಌ','ಎ'=>'ಎ','ಏ'=>'ಏ','ಐ'=>'ಐ','ಒ'=>'ಒ','ಓ'=>'ಓ','ಔ'=>'ಔ','ಕ'=>'ಕ','ಖ'=>'ಖ','ಗ'=>'ಗ','ಘ'=>'ಘ','ಙ'=>'ಙ','ಚ'=>'ಚ','ಛ'=>'ಛ','ಜ'=>'ಜ','ಝ'=>'ಝ','ಞ'=>'ಞ','ಟ'=>'ಟ','ಠ'=>'ಠ','ಡ'=>'ಡ','ಢ'=>'ಢ','ಣ'=>'ಣ','ತ'=>'ತ','ಥ'=>'ಥ','ದ'=>'ದ','ಧ'=>'ಧ','ನ'=>'ನ','ಪ'=>'ಪ','ಫ'=>'ಫ','ಬ'=>'ಬ','ಭ'=>'ಭ','ಮ'=>'ಮ','ಯ'=>'ಯ','ರ'=>'ರ','ಱ'=>'ಱ','ಲ'=>'ಲ','ಳ'=>'ಳ','ವ'=>'ವ','ಶ'=>'ಶ','ಷ'=>'ಷ','ಸ'=>'ಸ','ಹ'=>'ಹ','಼'=>'಼','ಽ'=>'ಽ','ಾ'=>'ಾ','ಿ'=>'ಿ','ೀ'=>'ೀ','ು'=>'ು','ೂ'=>'ೂ','ೃ'=>'ೃ','ೄ'=>'ೄ','ೆ'=>'ೆ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ೌ'=>'ೌ','್'=>'್','ೕ'=>'ೕ','ೖ'=>'ೖ','ೞ'=>'ೞ','ೠ'=>'ೠ','ೡ'=>'ೡ','ೢ'=>'ೢ','ೣ'=>'ೣ','೦'=>'0','೧'=>'1','೨'=>'2','೩'=>'3','೪'=>'4','೫'=>'5','೬'=>'6','೭'=>'7','೮'=>'8','೯'=>'9','ം'=>'ം','ഃ'=>'ഃ','അ'=>'അ','ആ'=>'ആ','ഇ'=>'ഇ','ഈ'=>'ഈ','ഉ'=>'ഉ','ഊ'=>'ഊ','ഋ'=>'ഋ','ഌ'=>'ഌ','എ'=>'എ','ഏ'=>'ഏ','ഐ'=>'ഐ','ഒ'=>'ഒ','ഓ'=>'ഓ','ഔ'=>'ഔ','ക'=>'ക','ഖ'=>'ഖ','ഗ'=>'ഗ','ഘ'=>'ഘ','ങ'=>'ങ','ച'=>'ച','ഛ'=>'ഛ','ജ'=>'ജ','ഝ'=>'ഝ','ഞ'=>'ഞ','ട'=>'ട','ഠ'=>'ഠ','ഡ'=>'ഡ','ഢ'=>'ഢ','ണ'=>'ണ','ത'=>'ത','ഥ'=>'ഥ','ദ'=>'ദ','ധ'=>'ധ','ന'=>'ന','പ'=>'പ','ഫ'=>'ഫ','ബ'=>'ബ','ഭ'=>'ഭ','മ'=>'മ','യ'=>'യ','ര'=>'ര','റ'=>'റ','ല'=>'ല','ള'=>'ള','ഴ'=>'ഴ','വ'=>'വ','ശ'=>'ശ','ഷ'=>'ഷ','സ'=>'സ','ഹ'=>'ഹ','ാ'=>'ാ','ി'=>'ി','ീ'=>'ീ','ു'=>'ു','ൂ'=>'ൂ','ൃ'=>'ൃ','െ'=>'െ','േ'=>'േ','ൈ'=>'ൈ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','്'=>'്','ൗ'=>'ൗ','ൠ'=>'ൠ','ൡ'=>'ൡ','൦'=>'0','൧'=>'1','൨'=>'2','൩'=>'3','൪'=>'4','൫'=>'5','൬'=>'6','൭'=>'7','൮'=>'8','൯'=>'9','ං'=>'ං','ඃ'=>'ඃ','අ'=>'අ','ආ'=>'ආ','ඇ'=>'ඇ','ඈ'=>'ඈ','ඉ'=>'ඉ','ඊ'=>'ඊ','උ'=>'උ','ඌ'=>'ඌ','ඍ'=>'ඍ','ඎ'=>'ඎ','ඏ'=>'ඏ','ඐ'=>'ඐ','එ'=>'එ','ඒ'=>'ඒ','ඓ'=>'ඓ','ඔ'=>'ඔ','ඕ'=>'ඕ','ඖ'=>'ඖ','ක'=>'ක','ඛ'=>'ඛ','ග'=>'ග','ඝ'=>'ඝ','ඞ'=>'ඞ','ඟ'=>'ඟ','ච'=>'ච','ඡ'=>'ඡ','ජ'=>'ජ','ඣ'=>'ඣ','ඤ'=>'ඤ','ඥ'=>'ඥ','ඦ'=>'ඦ','ට'=>'ට','ඨ'=>'ඨ','ඩ'=>'ඩ','ඪ'=>'ඪ','ණ'=>'ණ','ඬ'=>'ඬ','ත'=>'ත','ථ'=>'ථ','ද'=>'ද','ධ'=>'ධ','න'=>'න','ඳ'=>'ඳ','ප'=>'ප','ඵ'=>'ඵ','බ'=>'බ','භ'=>'භ','ම'=>'ම','ඹ'=>'ඹ','ය'=>'ය','ර'=>'ර','ල'=>'ල','ව'=>'ව','ශ'=>'ශ','ෂ'=>'ෂ','ස'=>'ස','හ'=>'හ','ළ'=>'ළ','ෆ'=>'ෆ','්'=>'්','ා'=>'ා','ැ'=>'ැ','ෑ'=>'ෑ','ි'=>'ි','ී'=>'ී','ු'=>'ු','ූ'=>'ූ','ෘ'=>'ෘ','ෙ'=>'ෙ','ේ'=>'ේ','ෛ'=>'ෛ','ො'=>'ො','ෝ'=>'ෝ','ෞ'=>'ෞ','ෟ'=>'ෟ','ෲ'=>'ෲ','ෳ'=>'ෳ','ก'=>'ก','ข'=>'ข','ฃ'=>'ฃ','ค'=>'ค','ฅ'=>'ฅ','ฆ'=>'ฆ','ง'=>'ง','จ'=>'จ','ฉ'=>'ฉ','ช'=>'ช','ซ'=>'ซ','ฌ'=>'ฌ','ญ'=>'ญ','ฎ'=>'ฎ','ฏ'=>'ฏ','ฐ'=>'ฐ','ฑ'=>'ฑ','ฒ'=>'ฒ','ณ'=>'ณ','ด'=>'ด','ต'=>'ต','ถ'=>'ถ','ท'=>'ท','ธ'=>'ธ','น'=>'น','บ'=>'บ','ป'=>'ป','ผ'=>'ผ','ฝ'=>'ฝ','พ'=>'พ','ฟ'=>'ฟ','ภ'=>'ภ','ม'=>'ม','ย'=>'ย','ร'=>'ร','ฤ'=>'ฤ','ล'=>'ล','ฦ'=>'ฦ','ว'=>'ว','ศ'=>'ศ','ษ'=>'ษ','ส'=>'ส','ห'=>'ห','ฬ'=>'ฬ','อ'=>'อ','ฮ'=>'ฮ','ฯ'=>'ฯ','ะ'=>'ะ','ั'=>'ั','า'=>'า','ำ'=>'ำ','ิ'=>'ิ','ี'=>'ี','ึ'=>'ึ','ื'=>'ื','ุ'=>'ุ','ู'=>'ู','ฺ'=>'ฺ','เ'=>'เ','แ'=>'แ','โ'=>'โ','ใ'=>'ใ','ไ'=>'ไ','ๅ'=>'ๅ','ๆ'=>'ๆ','็'=>'็','่'=>'่','้'=>'้','๊'=>'๊','๋'=>'๋','์'=>'์','ํ'=>'ํ','๎'=>'๎','๐'=>'0','๑'=>'1','๒'=>'2','๓'=>'3','๔'=>'4','๕'=>'5','๖'=>'6','๗'=>'7','๘'=>'8','๙'=>'9','ກ'=>'ກ','ຂ'=>'ຂ','ຄ'=>'ຄ','ງ'=>'ງ','ຈ'=>'ຈ','ຊ'=>'ຊ','ຍ'=>'ຍ','ດ'=>'ດ','ຕ'=>'ຕ','ຖ'=>'ຖ','ທ'=>'ທ','ນ'=>'ນ','ບ'=>'ບ','ປ'=>'ປ','ຜ'=>'ຜ','ຝ'=>'ຝ','ພ'=>'ພ','ຟ'=>'ຟ','ມ'=>'ມ','ຢ'=>'ຢ','ຣ'=>'ຣ','ລ'=>'ລ','ວ'=>'ວ','ສ'=>'ສ','ຫ'=>'ຫ','ອ'=>'ອ','ຮ'=>'ຮ','ຯ'=>'ຯ','ະ'=>'ະ','ັ'=>'ັ','າ'=>'າ','ຳ'=>'ຳ','ິ'=>'ິ','ີ'=>'ີ','ຶ'=>'ຶ','ື'=>'ື','ຸ'=>'ຸ','ູ'=>'ູ','ົ'=>'ົ','ຼ'=>'ຼ','ຽ'=>'ຽ','ເ'=>'ເ','ແ'=>'ແ','ໂ'=>'ໂ','ໃ'=>'ໃ','ໄ'=>'ໄ','ໆ'=>'ໆ','່'=>'່','້'=>'້','໊'=>'໊','໋'=>'໋','໌'=>'໌','ໍ'=>'ໍ','໐'=>'0','໑'=>'1','໒'=>'2','໓'=>'3','໔'=>'4','໕'=>'5','໖'=>'6','໗'=>'7','໘'=>'8','໙'=>'9','ໜ'=>'ໜ','ໝ'=>'ໝ','ༀ'=>'ༀ','༘'=>'༘','༙'=>'༙','༠'=>'0','༡'=>'1','༢'=>'2','༣'=>'3','༤'=>'4','༥'=>'5','༦'=>'6','༧'=>'7','༨'=>'8','༩'=>'9','༪'=>'1/2','༫'=>'3/2','༬'=>'5/2','༭'=>'7/2','༮'=>'9/2','༯'=>'11/2','༰'=>'13/2','༱'=>'15/2','༲'=>'17/2','༳'=>'-1/2','༵'=>'༵','༷'=>'༷','༹'=>'༹','༾'=>'༾','༿'=>'༿','ཀ'=>'ཀ','ཁ'=>'ཁ','ག'=>'ག','གྷ'=>'གྷ','ང'=>'ང','ཅ'=>'ཅ','ཆ'=>'ཆ','ཇ'=>'ཇ','ཉ'=>'ཉ','ཊ'=>'ཊ','ཋ'=>'ཋ','ཌ'=>'ཌ','ཌྷ'=>'ཌྷ','ཎ'=>'ཎ','ཏ'=>'ཏ','ཐ'=>'ཐ','ད'=>'ད','དྷ'=>'དྷ','ན'=>'ན','པ'=>'པ','ཕ'=>'ཕ','བ'=>'བ','བྷ'=>'བྷ','མ'=>'མ','ཙ'=>'ཙ','ཚ'=>'ཚ','ཛ'=>'ཛ','ཛྷ'=>'ཛྷ','ཝ'=>'ཝ','ཞ'=>'ཞ','ཟ'=>'ཟ','འ'=>'འ','ཡ'=>'ཡ','ར'=>'ར','ལ'=>'ལ','ཤ'=>'ཤ','ཥ'=>'ཥ','ས'=>'ས','ཧ'=>'ཧ','ཨ'=>'ཨ','ཀྵ'=>'ཀྵ','ཪ'=>'ཪ','ཱ'=>'ཱ','ི'=>'ི','ཱི'=>'ཱི','ུ'=>'ུ','ཱུ'=>'ཱུ','ྲྀ'=>'ྲྀ','ཷ'=>'ཷ','ླྀ'=>'ླྀ','ཹ'=>'ཹ','ེ'=>'ེ','ཻ'=>'ཻ','ོ'=>'ོ','ཽ'=>'ཽ','ཾ'=>'ཾ','ཿ'=>'ཿ','ྀ'=>'ྀ','ཱྀ'=>'ཱྀ','ྂ'=>'ྂ','ྃ'=>'ྃ','྄'=>'྄','྆'=>'྆','྇'=>'྇','ྈ'=>'ྈ','ྉ'=>'ྉ','ྊ'=>'ྊ','ྋ'=>'ྋ','ྐ'=>'ྐ','ྑ'=>'ྑ','ྒ'=>'ྒ','ྒྷ'=>'ྒྷ','ྔ'=>'ྔ','ྕ'=>'ྕ','ྖ'=>'ྖ','ྗ'=>'ྗ','ྙ'=>'ྙ','ྚ'=>'ྚ','ྛ'=>'ྛ','ྜ'=>'ྜ','ྜྷ'=>'ྜྷ','ྞ'=>'ྞ','ྟ'=>'ྟ','ྠ'=>'ྠ','ྡ'=>'ྡ','ྡྷ'=>'ྡྷ','ྣ'=>'ྣ','ྤ'=>'ྤ','ྥ'=>'ྥ','ྦ'=>'ྦ','ྦྷ'=>'ྦྷ','ྨ'=>'ྨ','ྩ'=>'ྩ','ྪ'=>'ྪ','ྫ'=>'ྫ','ྫྷ'=>'ྫྷ','ྭ'=>'ྭ','ྮ'=>'ྮ','ྯ'=>'ྯ','ྰ'=>'ྰ','ྱ'=>'ྱ','ྲ'=>'ྲ','ླ'=>'ླ','ྴ'=>'ྴ','ྵ'=>'ྵ','ྶ'=>'ྶ','ྷ'=>'ྷ','ྸ'=>'ྸ','ྐྵ'=>'ྐྵ','ྺ'=>'ྺ','ྻ'=>'ྻ','ྼ'=>'ྼ','࿆'=>'࿆');
\ No newline at end of file +<?php return array('ँ'=>'ँ','ं'=>'ं','ः'=>'ः','ऄ'=>'ऄ','अ'=>'अ','आ'=>'आ','इ'=>'इ','ई'=>'ई','उ'=>'उ','ऊ'=>'ऊ','ऋ'=>'ऋ','ऌ'=>'ऌ','ऍ'=>'ऍ','ऎ'=>'ऎ','ए'=>'ए','ऐ'=>'ऐ','ऑ'=>'ऑ','ऒ'=>'ऒ','ओ'=>'ओ','औ'=>'औ','क'=>'क','ख'=>'ख','ग'=>'ग','घ'=>'घ','ङ'=>'ङ','च'=>'च','छ'=>'छ','ज'=>'ज','झ'=>'झ','ञ'=>'ञ','ट'=>'ट','ठ'=>'ठ','ड'=>'ड','ढ'=>'ढ','ण'=>'ण','त'=>'त','थ'=>'थ','द'=>'द','ध'=>'ध','न'=>'न','ऩ'=>'ऩ','प'=>'प','फ'=>'फ','ब'=>'ब','भ'=>'भ','म'=>'म','य'=>'य','र'=>'र','ऱ'=>'ऱ','ल'=>'ल','ळ'=>'ळ','ऴ'=>'ऴ','व'=>'व','श'=>'श','ष'=>'ष','स'=>'स','ह'=>'ह','़'=>'़','ऽ'=>'ऽ','ा'=>'ा','ि'=>'ि','ी'=>'ी','ु'=>'ु','ू'=>'ू','ृ'=>'ृ','ॄ'=>'ॄ','ॅ'=>'ॅ','ॆ'=>'ॆ','े'=>'े','ै'=>'ै','ॉ'=>'ॉ','ॊ'=>'ॊ','ो'=>'ो','ौ'=>'ौ','्'=>'्','ॐ'=>'ॐ','॑'=>'॑','॒'=>'॒','॓'=>'॓','॔'=>'॔','क़'=>'क़','ख़'=>'ख़','ग़'=>'ग़','ज़'=>'ज़','ड़'=>'ड़','ढ़'=>'ढ़','फ़'=>'फ़','य़'=>'य़','ॠ'=>'ॠ','ॡ'=>'ॡ','ॢ'=>'ॢ','ॣ'=>'ॣ','०'=>'0','१'=>'1','२'=>'2','३'=>'3','४'=>'4','५'=>'5','६'=>'6','७'=>'7','८'=>'8','९'=>'9','ॻ'=>'ॻ','ॼ'=>'ॼ','ॽ'=>'ॽ','ॾ'=>'ॾ','ॿ'=>'ॿ','ঁ'=>'ঁ','ং'=>'ং','ঃ'=>'ঃ','অ'=>'অ','আ'=>'আ','ই'=>'ই','ঈ'=>'ঈ','উ'=>'উ','ঊ'=>'ঊ','ঋ'=>'ঋ','ঌ'=>'ঌ','এ'=>'এ','ঐ'=>'ঐ','ও'=>'ও','ঔ'=>'ঔ','ক'=>'ক','খ'=>'খ','গ'=>'গ','ঘ'=>'ঘ','ঙ'=>'ঙ','চ'=>'চ','ছ'=>'ছ','জ'=>'জ','ঝ'=>'ঝ','ঞ'=>'ঞ','ট'=>'ট','ঠ'=>'ঠ','ড'=>'ড','ঢ'=>'ঢ','ণ'=>'ণ','ত'=>'ত','থ'=>'থ','দ'=>'দ','ধ'=>'ধ','ন'=>'ন','প'=>'প','ফ'=>'ফ','ব'=>'ব','ভ'=>'ভ','ম'=>'ম','য'=>'য','র'=>'র','ল'=>'ল','শ'=>'শ','ষ'=>'ষ','স'=>'স','হ'=>'হ','়'=>'়','ঽ'=>'ঽ','া'=>'া','ি'=>'ি','ী'=>'ী','ু'=>'ু','ূ'=>'ূ','ৃ'=>'ৃ','ৄ'=>'ৄ','ে'=>'ে','ৈ'=>'ৈ','ো'=>'ো','ৌ'=>'ৌ','্'=>'্','ৎ'=>'ৎ','ৗ'=>'ৗ','ড়'=>'ড়','ঢ়'=>'ঢ়','য়'=>'য়','ৠ'=>'ৠ','ৡ'=>'ৡ','ৢ'=>'ৢ','ৣ'=>'ৣ','০'=>'0','১'=>'1','২'=>'2','৩'=>'3','৪'=>'4','৫'=>'5','৬'=>'6','৭'=>'7','৮'=>'8','৯'=>'9','ৰ'=>'ৰ','ৱ'=>'ৱ','৴'=>'1','৵'=>'2','৶'=>'3','৷'=>'4','৸'=>'৸','৹'=>'16','ਁ'=>'ਁ','ਂ'=>'ਂ','ਃ'=>'ਃ','ਅ'=>'ਅ','ਆ'=>'ਆ','ਇ'=>'ਇ','ਈ'=>'ਈ','ਉ'=>'ਉ','ਊ'=>'ਊ','ਏ'=>'ਏ','ਐ'=>'ਐ','ਓ'=>'ਓ','ਔ'=>'ਔ','ਕ'=>'ਕ','ਖ'=>'ਖ','ਗ'=>'ਗ','ਘ'=>'ਘ','ਙ'=>'ਙ','ਚ'=>'ਚ','ਛ'=>'ਛ','ਜ'=>'ਜ','ਝ'=>'ਝ','ਞ'=>'ਞ','ਟ'=>'ਟ','ਠ'=>'ਠ','ਡ'=>'ਡ','ਢ'=>'ਢ','ਣ'=>'ਣ','ਤ'=>'ਤ','ਥ'=>'ਥ','ਦ'=>'ਦ','ਧ'=>'ਧ','ਨ'=>'ਨ','ਪ'=>'ਪ','ਫ'=>'ਫ','ਬ'=>'ਬ','ਭ'=>'ਭ','ਮ'=>'ਮ','ਯ'=>'ਯ','ਰ'=>'ਰ','ਲ'=>'ਲ','ਲ਼'=>'ਲ਼','ਵ'=>'ਵ','ਸ਼'=>'ਸ਼','ਸ'=>'ਸ','ਹ'=>'ਹ','਼'=>'਼','ਾ'=>'ਾ','ਿ'=>'ਿ','ੀ'=>'ੀ','ੁ'=>'ੁ','ੂ'=>'ੂ','ੇ'=>'ੇ','ੈ'=>'ੈ','ੋ'=>'ੋ','ੌ'=>'ੌ','੍'=>'੍','ਖ਼'=>'ਖ਼','ਗ਼'=>'ਗ਼','ਜ਼'=>'ਜ਼','ੜ'=>'ੜ','ਫ਼'=>'ਫ਼','੦'=>'0','੧'=>'1','੨'=>'2','੩'=>'3','੪'=>'4','੫'=>'5','੬'=>'6','੭'=>'7','੮'=>'8','੯'=>'9','ੰ'=>'ੰ','ੱ'=>'ੱ','ੲ'=>'ੲ','ੳ'=>'ੳ','ੴ'=>'ੴ','ઁ'=>'ઁ','ં'=>'ં','ઃ'=>'ઃ','અ'=>'અ','આ'=>'આ','ઇ'=>'ઇ','ઈ'=>'ઈ','ઉ'=>'ઉ','ઊ'=>'ઊ','ઋ'=>'ઋ','ઌ'=>'ઌ','ઍ'=>'ઍ','એ'=>'એ','ઐ'=>'ઐ','ઑ'=>'ઑ','ઓ'=>'ઓ','ઔ'=>'ઔ','ક'=>'ક','ખ'=>'ખ','ગ'=>'ગ','ઘ'=>'ઘ','ઙ'=>'ઙ','ચ'=>'ચ','છ'=>'છ','જ'=>'જ','ઝ'=>'ઝ','ઞ'=>'ઞ','ટ'=>'ટ','ઠ'=>'ઠ','ડ'=>'ડ','ઢ'=>'ઢ','ણ'=>'ણ','ત'=>'ત','થ'=>'થ','દ'=>'દ','ધ'=>'ધ','ન'=>'ન','પ'=>'પ','ફ'=>'ફ','બ'=>'બ','ભ'=>'ભ','મ'=>'મ','ય'=>'ય','ર'=>'ર','લ'=>'લ','ળ'=>'ળ','વ'=>'વ','શ'=>'શ','ષ'=>'ષ','સ'=>'સ','હ'=>'હ','઼'=>'઼','ઽ'=>'ઽ','ા'=>'ા','િ'=>'િ','ી'=>'ી','ુ'=>'ુ','ૂ'=>'ૂ','ૃ'=>'ૃ','ૄ'=>'ૄ','ૅ'=>'ૅ','ે'=>'ે','ૈ'=>'ૈ','ૉ'=>'ૉ','ો'=>'ો','ૌ'=>'ૌ','્'=>'્','ૐ'=>'ૐ','ૠ'=>'ૠ','ૡ'=>'ૡ','ૢ'=>'ૢ','ૣ'=>'ૣ','૦'=>'0','૧'=>'1','૨'=>'2','૩'=>'3','૪'=>'4','૫'=>'5','૬'=>'6','૭'=>'7','૮'=>'8','૯'=>'9','ଁ'=>'ଁ','ଂ'=>'ଂ','ଃ'=>'ଃ','ଅ'=>'ଅ','ଆ'=>'ଆ','ଇ'=>'ଇ','ଈ'=>'ଈ','ଉ'=>'ଉ','ଊ'=>'ଊ','ଋ'=>'ଋ','ଌ'=>'ଌ','ଏ'=>'ଏ','ଐ'=>'ଐ','ଓ'=>'ଓ','ଔ'=>'ଔ','କ'=>'କ','ଖ'=>'ଖ','ଗ'=>'ଗ','ଘ'=>'ଘ','ଙ'=>'ଙ','ଚ'=>'ଚ','ଛ'=>'ଛ','ଜ'=>'ଜ','ଝ'=>'ଝ','ଞ'=>'ଞ','ଟ'=>'ଟ','ଠ'=>'ଠ','ଡ'=>'ଡ','ଢ'=>'ଢ','ଣ'=>'ଣ','ତ'=>'ତ','ଥ'=>'ଥ','ଦ'=>'ଦ','ଧ'=>'ଧ','ନ'=>'ନ','ପ'=>'ପ','ଫ'=>'ଫ','ବ'=>'ବ','ଭ'=>'ଭ','ମ'=>'ମ','ଯ'=>'ଯ','ର'=>'ର','ଲ'=>'ଲ','ଳ'=>'ଳ','ଵ'=>'ଵ','ଶ'=>'ଶ','ଷ'=>'ଷ','ସ'=>'ସ','ହ'=>'ହ','଼'=>'଼','ଽ'=>'ଽ','ା'=>'ା','ି'=>'ି','ୀ'=>'ୀ','ୁ'=>'ୁ','ୂ'=>'ୂ','ୃ'=>'ୃ','େ'=>'େ','ୈ'=>'ୈ','ୋ'=>'ୋ','ୌ'=>'ୌ','୍'=>'୍','ୖ'=>'ୖ','ୗ'=>'ୗ','ଡ଼'=>'ଡ଼','ଢ଼'=>'ଢ଼','ୟ'=>'ୟ','ୠ'=>'ୠ','ୡ'=>'ୡ','୦'=>'0','୧'=>'1','୨'=>'2','୩'=>'3','୪'=>'4','୫'=>'5','୬'=>'6','୭'=>'7','୮'=>'8','୯'=>'9','ୱ'=>'ୱ','ஂ'=>'ஂ','ஃ'=>'ஃ','அ'=>'அ','ஆ'=>'ஆ','இ'=>'இ','ஈ'=>'ஈ','உ'=>'உ','ஊ'=>'ஊ','எ'=>'எ','ஏ'=>'ஏ','ஐ'=>'ஐ','ஒ'=>'ஒ','ஓ'=>'ஓ','ஔ'=>'ஔ','க'=>'க','ங'=>'ங','ச'=>'ச','ஜ'=>'ஜ','ஞ'=>'ஞ','ட'=>'ட','ண'=>'ண','த'=>'த','ந'=>'ந','ன'=>'ன','ப'=>'ப','ம'=>'ம','ய'=>'ய','ர'=>'ர','ற'=>'ற','ல'=>'ல','ள'=>'ள','ழ'=>'ழ','வ'=>'வ','ஶ'=>'ஶ','ஷ'=>'ஷ','ஸ'=>'ஸ','ஹ'=>'ஹ','ா'=>'ா','ி'=>'ி','ீ'=>'ீ','ு'=>'ு','ூ'=>'ூ','ெ'=>'ெ','ே'=>'ே','ை'=>'ை','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','்'=>'்','ௗ'=>'ௗ','௦'=>'0','௧'=>'1','௨'=>'2','௩'=>'3','௪'=>'4','௫'=>'5','௬'=>'6','௭'=>'7','௮'=>'8','௯'=>'9','௰'=>'10','௱'=>'100','௲'=>'1000','ఁ'=>'ఁ','ం'=>'ం','ః'=>'ః','అ'=>'అ','ఆ'=>'ఆ','ఇ'=>'ఇ','ఈ'=>'ఈ','ఉ'=>'ఉ','ఊ'=>'ఊ','ఋ'=>'ఋ','ఌ'=>'ఌ','ఎ'=>'ఎ','ఏ'=>'ఏ','ఐ'=>'ఐ','ఒ'=>'ఒ','ఓ'=>'ఓ','ఔ'=>'ఔ','క'=>'క','ఖ'=>'ఖ','గ'=>'గ','ఘ'=>'ఘ','ఙ'=>'ఙ','చ'=>'చ','ఛ'=>'ఛ','జ'=>'జ','ఝ'=>'ఝ','ఞ'=>'ఞ','ట'=>'ట','ఠ'=>'ఠ','డ'=>'డ','ఢ'=>'ఢ','ణ'=>'ణ','త'=>'త','థ'=>'థ','ద'=>'ద','ధ'=>'ధ','న'=>'న','ప'=>'ప','ఫ'=>'ఫ','బ'=>'బ','భ'=>'భ','మ'=>'మ','య'=>'య','ర'=>'ర','ఱ'=>'ఱ','ల'=>'ల','ళ'=>'ళ','వ'=>'వ','శ'=>'శ','ష'=>'ష','స'=>'స','హ'=>'హ','ా'=>'ా','ి'=>'ి','ీ'=>'ీ','ు'=>'ు','ూ'=>'ూ','ృ'=>'ృ','ౄ'=>'ౄ','ె'=>'ె','ే'=>'ే','ై'=>'ై','ొ'=>'ొ','ో'=>'ో','ౌ'=>'ౌ','్'=>'్','ౕ'=>'ౕ','ౖ'=>'ౖ','ౠ'=>'ౠ','ౡ'=>'ౡ','౦'=>'0','౧'=>'1','౨'=>'2','౩'=>'3','౪'=>'4','౫'=>'5','౬'=>'6','౭'=>'7','౮'=>'8','౯'=>'9','ಂ'=>'ಂ','ಃ'=>'ಃ','ಅ'=>'ಅ','ಆ'=>'ಆ','ಇ'=>'ಇ','ಈ'=>'ಈ','ಉ'=>'ಉ','ಊ'=>'ಊ','ಋ'=>'ಋ','ಌ'=>'ಌ','ಎ'=>'ಎ','ಏ'=>'ಏ','ಐ'=>'ಐ','ಒ'=>'ಒ','ಓ'=>'ಓ','ಔ'=>'ಔ','ಕ'=>'ಕ','ಖ'=>'ಖ','ಗ'=>'ಗ','ಘ'=>'ಘ','ಙ'=>'ಙ','ಚ'=>'ಚ','ಛ'=>'ಛ','ಜ'=>'ಜ','ಝ'=>'ಝ','ಞ'=>'ಞ','ಟ'=>'ಟ','ಠ'=>'ಠ','ಡ'=>'ಡ','ಢ'=>'ಢ','ಣ'=>'ಣ','ತ'=>'ತ','ಥ'=>'ಥ','ದ'=>'ದ','ಧ'=>'ಧ','ನ'=>'ನ','ಪ'=>'ಪ','ಫ'=>'ಫ','ಬ'=>'ಬ','ಭ'=>'ಭ','ಮ'=>'ಮ','ಯ'=>'ಯ','ರ'=>'ರ','ಱ'=>'ಱ','ಲ'=>'ಲ','ಳ'=>'ಳ','ವ'=>'ವ','ಶ'=>'ಶ','ಷ'=>'ಷ','ಸ'=>'ಸ','ಹ'=>'ಹ','಼'=>'಼','ಽ'=>'ಽ','ಾ'=>'ಾ','ಿ'=>'ಿ','ೀ'=>'ೀ','ು'=>'ು','ೂ'=>'ೂ','ೃ'=>'ೃ','ೄ'=>'ೄ','ೆ'=>'ೆ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ೌ'=>'ೌ','್'=>'್','ೕ'=>'ೕ','ೖ'=>'ೖ','ೞ'=>'ೞ','ೠ'=>'ೠ','ೡ'=>'ೡ','ೢ'=>'ೢ','ೣ'=>'ೣ','೦'=>'0','೧'=>'1','೨'=>'2','೩'=>'3','೪'=>'4','೫'=>'5','೬'=>'6','೭'=>'7','೮'=>'8','೯'=>'9','ം'=>'ം','ഃ'=>'ഃ','അ'=>'അ','ആ'=>'ആ','ഇ'=>'ഇ','ഈ'=>'ഈ','ഉ'=>'ഉ','ഊ'=>'ഊ','ഋ'=>'ഋ','ഌ'=>'ഌ','എ'=>'എ','ഏ'=>'ഏ','ഐ'=>'ഐ','ഒ'=>'ഒ','ഓ'=>'ഓ','ഔ'=>'ഔ','ക'=>'ക','ഖ'=>'ഖ','ഗ'=>'ഗ','ഘ'=>'ഘ','ങ'=>'ങ','ച'=>'ച','ഛ'=>'ഛ','ജ'=>'ജ','ഝ'=>'ഝ','ഞ'=>'ഞ','ട'=>'ട','ഠ'=>'ഠ','ഡ'=>'ഡ','ഢ'=>'ഢ','ണ'=>'ണ','ത'=>'ത','ഥ'=>'ഥ','ദ'=>'ദ','ധ'=>'ധ','ന'=>'ന','പ'=>'പ','ഫ'=>'ഫ','ബ'=>'ബ','ഭ'=>'ഭ','മ'=>'മ','യ'=>'യ','ര'=>'ര','റ'=>'റ','ല'=>'ല','ള'=>'ള','ഴ'=>'ഴ','വ'=>'വ','ശ'=>'ശ','ഷ'=>'ഷ','സ'=>'സ','ഹ'=>'ഹ','ാ'=>'ാ','ി'=>'ി','ീ'=>'ീ','ു'=>'ു','ൂ'=>'ൂ','ൃ'=>'ൃ','െ'=>'െ','േ'=>'േ','ൈ'=>'ൈ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','്'=>'്','ൗ'=>'ൗ','ൠ'=>'ൠ','ൡ'=>'ൡ','൦'=>'0','൧'=>'1','൨'=>'2','൩'=>'3','൪'=>'4','൫'=>'5','൬'=>'6','൭'=>'7','൮'=>'8','൯'=>'9','ං'=>'ං','ඃ'=>'ඃ','අ'=>'අ','ආ'=>'ආ','ඇ'=>'ඇ','ඈ'=>'ඈ','ඉ'=>'ඉ','ඊ'=>'ඊ','උ'=>'උ','ඌ'=>'ඌ','ඍ'=>'ඍ','ඎ'=>'ඎ','ඏ'=>'ඏ','ඐ'=>'ඐ','එ'=>'එ','ඒ'=>'ඒ','ඓ'=>'ඓ','ඔ'=>'ඔ','ඕ'=>'ඕ','ඖ'=>'ඖ','ක'=>'ක','ඛ'=>'ඛ','ග'=>'ග','ඝ'=>'ඝ','ඞ'=>'ඞ','ඟ'=>'ඟ','ච'=>'ච','ඡ'=>'ඡ','ජ'=>'ජ','ඣ'=>'ඣ','ඤ'=>'ඤ','ඥ'=>'ඥ','ඦ'=>'ඦ','ට'=>'ට','ඨ'=>'ඨ','ඩ'=>'ඩ','ඪ'=>'ඪ','ණ'=>'ණ','ඬ'=>'ඬ','ත'=>'ත','ථ'=>'ථ','ද'=>'ද','ධ'=>'ධ','න'=>'න','ඳ'=>'ඳ','ප'=>'ප','ඵ'=>'ඵ','බ'=>'බ','භ'=>'භ','ම'=>'ම','ඹ'=>'ඹ','ය'=>'ය','ර'=>'ර','ල'=>'ල','ව'=>'ව','ශ'=>'ශ','ෂ'=>'ෂ','ස'=>'ස','හ'=>'හ','ළ'=>'ළ','ෆ'=>'ෆ','්'=>'්','ා'=>'ා','ැ'=>'ැ','ෑ'=>'ෑ','ි'=>'ි','ී'=>'ී','ු'=>'ු','ූ'=>'ූ','ෘ'=>'ෘ','ෙ'=>'ෙ','ේ'=>'ේ','ෛ'=>'ෛ','ො'=>'ො','ෝ'=>'ෝ','ෞ'=>'ෞ','ෟ'=>'ෟ','ෲ'=>'ෲ','ෳ'=>'ෳ','ก'=>'ก','ข'=>'ข','ฃ'=>'ฃ','ค'=>'ค','ฅ'=>'ฅ','ฆ'=>'ฆ','ง'=>'ง','จ'=>'จ','ฉ'=>'ฉ','ช'=>'ช','ซ'=>'ซ','ฌ'=>'ฌ','ญ'=>'ญ','ฎ'=>'ฎ','ฏ'=>'ฏ','ฐ'=>'ฐ','ฑ'=>'ฑ','ฒ'=>'ฒ','ณ'=>'ณ','ด'=>'ด','ต'=>'ต','ถ'=>'ถ','ท'=>'ท','ธ'=>'ธ','น'=>'น','บ'=>'บ','ป'=>'ป','ผ'=>'ผ','ฝ'=>'ฝ','พ'=>'พ','ฟ'=>'ฟ','ภ'=>'ภ','ม'=>'ม','ย'=>'ย','ร'=>'ร','ฤ'=>'ฤ','ล'=>'ล','ฦ'=>'ฦ','ว'=>'ว','ศ'=>'ศ','ษ'=>'ษ','ส'=>'ส','ห'=>'ห','ฬ'=>'ฬ','อ'=>'อ','ฮ'=>'ฮ','ฯ'=>'ฯ','ะ'=>'ะ','ั'=>'ั','า'=>'า','ำ'=>'ำ','ิ'=>'ิ','ี'=>'ี','ึ'=>'ึ','ื'=>'ื','ุ'=>'ุ','ู'=>'ู','ฺ'=>'ฺ','เ'=>'เ','แ'=>'แ','โ'=>'โ','ใ'=>'ใ','ไ'=>'ไ','ๅ'=>'ๅ','ๆ'=>'ๆ','็'=>'็','่'=>'่','้'=>'้','๊'=>'๊','๋'=>'๋','์'=>'์','ํ'=>'ํ','๎'=>'๎','๐'=>'0','๑'=>'1','๒'=>'2','๓'=>'3','๔'=>'4','๕'=>'5','๖'=>'6','๗'=>'7','๘'=>'8','๙'=>'9','ກ'=>'ກ','ຂ'=>'ຂ','ຄ'=>'ຄ','ງ'=>'ງ','ຈ'=>'ຈ','ຊ'=>'ຊ','ຍ'=>'ຍ','ດ'=>'ດ','ຕ'=>'ຕ','ຖ'=>'ຖ','ທ'=>'ທ','ນ'=>'ນ','ບ'=>'ບ','ປ'=>'ປ','ຜ'=>'ຜ','ຝ'=>'ຝ','ພ'=>'ພ','ຟ'=>'ຟ','ມ'=>'ມ','ຢ'=>'ຢ','ຣ'=>'ຣ','ລ'=>'ລ','ວ'=>'ວ','ສ'=>'ສ','ຫ'=>'ຫ','ອ'=>'ອ','ຮ'=>'ຮ','ຯ'=>'ຯ','ະ'=>'ະ','ັ'=>'ັ','າ'=>'າ','ຳ'=>'ຳ','ິ'=>'ິ','ີ'=>'ີ','ຶ'=>'ຶ','ື'=>'ື','ຸ'=>'ຸ','ູ'=>'ູ','ົ'=>'ົ','ຼ'=>'ຼ','ຽ'=>'ຽ','ເ'=>'ເ','ແ'=>'ແ','ໂ'=>'ໂ','ໃ'=>'ໃ','ໄ'=>'ໄ','ໆ'=>'ໆ','່'=>'່','້'=>'້','໊'=>'໊','໋'=>'໋','໌'=>'໌','ໍ'=>'ໍ','໐'=>'0','໑'=>'1','໒'=>'2','໓'=>'3','໔'=>'4','໕'=>'5','໖'=>'6','໗'=>'7','໘'=>'8','໙'=>'9','ໜ'=>'ໜ','ໝ'=>'ໝ','ༀ'=>'ༀ','༘'=>'༘','༙'=>'༙','༠'=>'0','༡'=>'1','༢'=>'2','༣'=>'3','༤'=>'4','༥'=>'5','༦'=>'6','༧'=>'7','༨'=>'8','༩'=>'9','༪'=>'1/2','༫'=>'3/2','༬'=>'5/2','༭'=>'7/2','༮'=>'9/2','༯'=>'11/2','༰'=>'13/2','༱'=>'15/2','༲'=>'17/2','༳'=>'-1/2','༵'=>'༵','༷'=>'༷','༹'=>'༹','༾'=>'༾','༿'=>'༿','ཀ'=>'ཀ','ཁ'=>'ཁ','ག'=>'ག','གྷ'=>'གྷ','ང'=>'ང','ཅ'=>'ཅ','ཆ'=>'ཆ','ཇ'=>'ཇ','ཉ'=>'ཉ','ཊ'=>'ཊ','ཋ'=>'ཋ','ཌ'=>'ཌ','ཌྷ'=>'ཌྷ','ཎ'=>'ཎ','ཏ'=>'ཏ','ཐ'=>'ཐ','ད'=>'ད','དྷ'=>'དྷ','ན'=>'ན','པ'=>'པ','ཕ'=>'ཕ','བ'=>'བ','བྷ'=>'བྷ','མ'=>'མ','ཙ'=>'ཙ','ཚ'=>'ཚ','ཛ'=>'ཛ','ཛྷ'=>'ཛྷ','ཝ'=>'ཝ','ཞ'=>'ཞ','ཟ'=>'ཟ','འ'=>'འ','ཡ'=>'ཡ','ར'=>'ར','ལ'=>'ལ','ཤ'=>'ཤ','ཥ'=>'ཥ','ས'=>'ས','ཧ'=>'ཧ','ཨ'=>'ཨ','ཀྵ'=>'ཀྵ','ཪ'=>'ཪ','ཱ'=>'ཱ','ི'=>'ི','ཱི'=>'ཱི','ུ'=>'ུ','ཱུ'=>'ཱུ','ྲྀ'=>'ྲྀ','ཷ'=>'ཷ','ླྀ'=>'ླྀ','ཹ'=>'ཹ','ེ'=>'ེ','ཻ'=>'ཻ','ོ'=>'ོ','ཽ'=>'ཽ','ཾ'=>'ཾ','ཿ'=>'ཿ','ྀ'=>'ྀ','ཱྀ'=>'ཱྀ','ྂ'=>'ྂ','ྃ'=>'ྃ','྄'=>'྄','྆'=>'྆','྇'=>'྇','ྈ'=>'ྈ','ྉ'=>'ྉ','ྊ'=>'ྊ','ྋ'=>'ྋ','ྐ'=>'ྐ','ྑ'=>'ྑ','ྒ'=>'ྒ','ྒྷ'=>'ྒྷ','ྔ'=>'ྔ','ྕ'=>'ྕ','ྖ'=>'ྖ','ྗ'=>'ྗ','ྙ'=>'ྙ','ྚ'=>'ྚ','ྛ'=>'ྛ','ྜ'=>'ྜ','ྜྷ'=>'ྜྷ','ྞ'=>'ྞ','ྟ'=>'ྟ','ྠ'=>'ྠ','ྡ'=>'ྡ','ྡྷ'=>'ྡྷ','ྣ'=>'ྣ','ྤ'=>'ྤ','ྥ'=>'ྥ','ྦ'=>'ྦ','ྦྷ'=>'ྦྷ','ྨ'=>'ྨ','ྩ'=>'ྩ','ྪ'=>'ྪ','ྫ'=>'ྫ','ྫྷ'=>'ྫྷ','ྭ'=>'ྭ','ྮ'=>'ྮ','ྯ'=>'ྯ','ྰ'=>'ྰ','ྱ'=>'ྱ','ྲ'=>'ྲ','ླ'=>'ླ','ྴ'=>'ྴ','ྵ'=>'ྵ','ྶ'=>'ྶ','ྷ'=>'ྷ','ྸ'=>'ྸ','ྐྵ'=>'ྐྵ','ྺ'=>'ྺ','ྻ'=>'ྻ','ྼ'=>'ྼ','࿆'=>'࿆'); diff --git a/phpBB/includes/utf/data/search_indexer_19.php b/phpBB/includes/utf/data/search_indexer_19.php index e26f7d81a0..d10d09f061 100644 --- a/phpBB/includes/utf/data/search_indexer_19.php +++ b/phpBB/includes/utf/data/search_indexer_19.php @@ -1 +1 @@ -<?php return array('龻'=>'龻');
\ No newline at end of file +<?php return array('龻'=>'龻'); diff --git a/phpBB/includes/utf/data/search_indexer_2.php b/phpBB/includes/utf/data/search_indexer_2.php index 751226ed22..5b5f03448f 100644 --- a/phpBB/includes/utf/data/search_indexer_2.php +++ b/phpBB/includes/utf/data/search_indexer_2.php @@ -1 +1 @@ -<?php return array('က'=>'က','ခ'=>'ခ','ဂ'=>'ဂ','ဃ'=>'ဃ','င'=>'င','စ'=>'စ','ဆ'=>'ဆ','ဇ'=>'ဇ','ဈ'=>'ဈ','ဉ'=>'ဉ','ည'=>'ည','ဋ'=>'ဋ','ဌ'=>'ဌ','ဍ'=>'ဍ','ဎ'=>'ဎ','ဏ'=>'ဏ','တ'=>'တ','ထ'=>'ထ','ဒ'=>'ဒ','ဓ'=>'ဓ','န'=>'န','ပ'=>'ပ','ဖ'=>'ဖ','ဗ'=>'ဗ','ဘ'=>'ဘ','မ'=>'မ','ယ'=>'ယ','ရ'=>'ရ','လ'=>'လ','ဝ'=>'ဝ','သ'=>'သ','ဟ'=>'ဟ','ဠ'=>'ဠ','အ'=>'အ','ဣ'=>'ဣ','ဤ'=>'ဤ','ဥ'=>'ဥ','ဦ'=>'ဦ','ဧ'=>'ဧ','ဩ'=>'ဩ','ဪ'=>'ဪ','ာ'=>'ာ','ိ'=>'ိ','ီ'=>'ီ','ု'=>'ု','ူ'=>'ူ','ေ'=>'ေ','ဲ'=>'ဲ','ံ'=>'ံ','့'=>'့','း'=>'း','္'=>'္','၀'=>'0','၁'=>'1','၂'=>'2','၃'=>'3','၄'=>'4','၅'=>'5','၆'=>'6','၇'=>'7','၈'=>'8','၉'=>'9','ၐ'=>'ၐ','ၑ'=>'ၑ','ၒ'=>'ၒ','ၓ'=>'ၓ','ၔ'=>'ၔ','ၕ'=>'ၕ','ၖ'=>'ၖ','ၗ'=>'ၗ','ၘ'=>'ၘ','ၙ'=>'ၙ','Ⴀ'=>'ⴀ','Ⴁ'=>'ⴁ','Ⴂ'=>'ⴂ','Ⴃ'=>'ⴃ','Ⴄ'=>'ⴄ','Ⴅ'=>'ⴅ','Ⴆ'=>'ⴆ','Ⴇ'=>'ⴇ','Ⴈ'=>'ⴈ','Ⴉ'=>'ⴉ','Ⴊ'=>'ⴊ','Ⴋ'=>'ⴋ','Ⴌ'=>'ⴌ','Ⴍ'=>'ⴍ','Ⴎ'=>'ⴎ','Ⴏ'=>'ⴏ','Ⴐ'=>'ⴐ','Ⴑ'=>'ⴑ','Ⴒ'=>'ⴒ','Ⴓ'=>'ⴓ','Ⴔ'=>'ⴔ','Ⴕ'=>'ⴕ','Ⴖ'=>'ⴖ','Ⴗ'=>'ⴗ','Ⴘ'=>'ⴘ','Ⴙ'=>'ⴙ','Ⴚ'=>'ⴚ','Ⴛ'=>'ⴛ','Ⴜ'=>'ⴜ','Ⴝ'=>'ⴝ','Ⴞ'=>'ⴞ','Ⴟ'=>'ⴟ','Ⴠ'=>'ⴠ','Ⴡ'=>'ⴡ','Ⴢ'=>'ⴢ','Ⴣ'=>'ⴣ','Ⴤ'=>'ⴤ','Ⴥ'=>'ⴥ','ა'=>'ა','ბ'=>'ბ','გ'=>'გ','დ'=>'დ','ე'=>'ე','ვ'=>'ვ','ზ'=>'ზ','თ'=>'თ','ი'=>'ი','კ'=>'კ','ლ'=>'ლ','მ'=>'მ','ნ'=>'ნ','ო'=>'ო','პ'=>'პ','ჟ'=>'ჟ','რ'=>'რ','ს'=>'ს','ტ'=>'ტ','უ'=>'უ','ფ'=>'ფ','ქ'=>'ქ','ღ'=>'ღ','ყ'=>'ყ','შ'=>'შ','ჩ'=>'ჩ','ც'=>'ც','ძ'=>'ძ','წ'=>'წ','ჭ'=>'ჭ','ხ'=>'ხ','ჯ'=>'ჯ','ჰ'=>'ჰ','ჱ'=>'ჱ','ჲ'=>'ჲ','ჳ'=>'ჳ','ჴ'=>'ჴ','ჵ'=>'ჵ','ჶ'=>'ჶ','ჷ'=>'ჷ','ჸ'=>'ჸ','ჹ'=>'ჹ','ჺ'=>'ჺ','ჼ'=>'ჼ','ᄀ'=>'ᄀ','ᄁ'=>'ᄁ','ᄂ'=>'ᄂ','ᄃ'=>'ᄃ','ᄄ'=>'ᄄ','ᄅ'=>'ᄅ','ᄆ'=>'ᄆ','ᄇ'=>'ᄇ','ᄈ'=>'ᄈ','ᄉ'=>'ᄉ','ᄊ'=>'ᄊ','ᄋ'=>'ᄋ','ᄌ'=>'ᄌ','ᄍ'=>'ᄍ','ᄎ'=>'ᄎ','ᄏ'=>'ᄏ','ᄐ'=>'ᄐ','ᄑ'=>'ᄑ','ᄒ'=>'ᄒ','ᄓ'=>'ᄓ','ᄔ'=>'ᄔ','ᄕ'=>'ᄕ','ᄖ'=>'ᄖ','ᄗ'=>'ᄗ','ᄘ'=>'ᄘ','ᄙ'=>'ᄙ','ᄚ'=>'ᄚ','ᄛ'=>'ᄛ','ᄜ'=>'ᄜ','ᄝ'=>'ᄝ','ᄞ'=>'ᄞ','ᄟ'=>'ᄟ','ᄠ'=>'ᄠ','ᄡ'=>'ᄡ','ᄢ'=>'ᄢ','ᄣ'=>'ᄣ','ᄤ'=>'ᄤ','ᄥ'=>'ᄥ','ᄦ'=>'ᄦ','ᄧ'=>'ᄧ','ᄨ'=>'ᄨ','ᄩ'=>'ᄩ','ᄪ'=>'ᄪ','ᄫ'=>'ᄫ','ᄬ'=>'ᄬ','ᄭ'=>'ᄭ','ᄮ'=>'ᄮ','ᄯ'=>'ᄯ','ᄰ'=>'ᄰ','ᄱ'=>'ᄱ','ᄲ'=>'ᄲ','ᄳ'=>'ᄳ','ᄴ'=>'ᄴ','ᄵ'=>'ᄵ','ᄶ'=>'ᄶ','ᄷ'=>'ᄷ','ᄸ'=>'ᄸ','ᄹ'=>'ᄹ','ᄺ'=>'ᄺ','ᄻ'=>'ᄻ','ᄼ'=>'ᄼ','ᄽ'=>'ᄽ','ᄾ'=>'ᄾ','ᄿ'=>'ᄿ','ᅀ'=>'ᅀ','ᅁ'=>'ᅁ','ᅂ'=>'ᅂ','ᅃ'=>'ᅃ','ᅄ'=>'ᅄ','ᅅ'=>'ᅅ','ᅆ'=>'ᅆ','ᅇ'=>'ᅇ','ᅈ'=>'ᅈ','ᅉ'=>'ᅉ','ᅊ'=>'ᅊ','ᅋ'=>'ᅋ','ᅌ'=>'ᅌ','ᅍ'=>'ᅍ','ᅎ'=>'ᅎ','ᅏ'=>'ᅏ','ᅐ'=>'ᅐ','ᅑ'=>'ᅑ','ᅒ'=>'ᅒ','ᅓ'=>'ᅓ','ᅔ'=>'ᅔ','ᅕ'=>'ᅕ','ᅖ'=>'ᅖ','ᅗ'=>'ᅗ','ᅘ'=>'ᅘ','ᅙ'=>'ᅙ','ᅟ'=>'ᅟ','ᅠ'=>'ᅠ','ᅡ'=>'ᅡ','ᅢ'=>'ᅢ','ᅣ'=>'ᅣ','ᅤ'=>'ᅤ','ᅥ'=>'ᅥ','ᅦ'=>'ᅦ','ᅧ'=>'ᅧ','ᅨ'=>'ᅨ','ᅩ'=>'ᅩ','ᅪ'=>'ᅪ','ᅫ'=>'ᅫ','ᅬ'=>'ᅬ','ᅭ'=>'ᅭ','ᅮ'=>'ᅮ','ᅯ'=>'ᅯ','ᅰ'=>'ᅰ','ᅱ'=>'ᅱ','ᅲ'=>'ᅲ','ᅳ'=>'ᅳ','ᅴ'=>'ᅴ','ᅵ'=>'ᅵ','ᅶ'=>'ᅶ','ᅷ'=>'ᅷ','ᅸ'=>'ᅸ','ᅹ'=>'ᅹ','ᅺ'=>'ᅺ','ᅻ'=>'ᅻ','ᅼ'=>'ᅼ','ᅽ'=>'ᅽ','ᅾ'=>'ᅾ','ᅿ'=>'ᅿ','ᆀ'=>'ᆀ','ᆁ'=>'ᆁ','ᆂ'=>'ᆂ','ᆃ'=>'ᆃ','ᆄ'=>'ᆄ','ᆅ'=>'ᆅ','ᆆ'=>'ᆆ','ᆇ'=>'ᆇ','ᆈ'=>'ᆈ','ᆉ'=>'ᆉ','ᆊ'=>'ᆊ','ᆋ'=>'ᆋ','ᆌ'=>'ᆌ','ᆍ'=>'ᆍ','ᆎ'=>'ᆎ','ᆏ'=>'ᆏ','ᆐ'=>'ᆐ','ᆑ'=>'ᆑ','ᆒ'=>'ᆒ','ᆓ'=>'ᆓ','ᆔ'=>'ᆔ','ᆕ'=>'ᆕ','ᆖ'=>'ᆖ','ᆗ'=>'ᆗ','ᆘ'=>'ᆘ','ᆙ'=>'ᆙ','ᆚ'=>'ᆚ','ᆛ'=>'ᆛ','ᆜ'=>'ᆜ','ᆝ'=>'ᆝ','ᆞ'=>'ᆞ','ᆟ'=>'ᆟ','ᆠ'=>'ᆠ','ᆡ'=>'ᆡ','ᆢ'=>'ᆢ','ᆨ'=>'ᆨ','ᆩ'=>'ᆩ','ᆪ'=>'ᆪ','ᆫ'=>'ᆫ','ᆬ'=>'ᆬ','ᆭ'=>'ᆭ','ᆮ'=>'ᆮ','ᆯ'=>'ᆯ','ᆰ'=>'ᆰ','ᆱ'=>'ᆱ','ᆲ'=>'ᆲ','ᆳ'=>'ᆳ','ᆴ'=>'ᆴ','ᆵ'=>'ᆵ','ᆶ'=>'ᆶ','ᆷ'=>'ᆷ','ᆸ'=>'ᆸ','ᆹ'=>'ᆹ','ᆺ'=>'ᆺ','ᆻ'=>'ᆻ','ᆼ'=>'ᆼ','ᆽ'=>'ᆽ','ᆾ'=>'ᆾ','ᆿ'=>'ᆿ','ᇀ'=>'ᇀ','ᇁ'=>'ᇁ','ᇂ'=>'ᇂ','ᇃ'=>'ᇃ','ᇄ'=>'ᇄ','ᇅ'=>'ᇅ','ᇆ'=>'ᇆ','ᇇ'=>'ᇇ','ᇈ'=>'ᇈ','ᇉ'=>'ᇉ','ᇊ'=>'ᇊ','ᇋ'=>'ᇋ','ᇌ'=>'ᇌ','ᇍ'=>'ᇍ','ᇎ'=>'ᇎ','ᇏ'=>'ᇏ','ᇐ'=>'ᇐ','ᇑ'=>'ᇑ','ᇒ'=>'ᇒ','ᇓ'=>'ᇓ','ᇔ'=>'ᇔ','ᇕ'=>'ᇕ','ᇖ'=>'ᇖ','ᇗ'=>'ᇗ','ᇘ'=>'ᇘ','ᇙ'=>'ᇙ','ᇚ'=>'ᇚ','ᇛ'=>'ᇛ','ᇜ'=>'ᇜ','ᇝ'=>'ᇝ','ᇞ'=>'ᇞ','ᇟ'=>'ᇟ','ᇠ'=>'ᇠ','ᇡ'=>'ᇡ','ᇢ'=>'ᇢ','ᇣ'=>'ᇣ','ᇤ'=>'ᇤ','ᇥ'=>'ᇥ','ᇦ'=>'ᇦ','ᇧ'=>'ᇧ','ᇨ'=>'ᇨ','ᇩ'=>'ᇩ','ᇪ'=>'ᇪ','ᇫ'=>'ᇫ','ᇬ'=>'ᇬ','ᇭ'=>'ᇭ','ᇮ'=>'ᇮ','ᇯ'=>'ᇯ','ᇰ'=>'ᇰ','ᇱ'=>'ᇱ','ᇲ'=>'ᇲ','ᇳ'=>'ᇳ','ᇴ'=>'ᇴ','ᇵ'=>'ᇵ','ᇶ'=>'ᇶ','ᇷ'=>'ᇷ','ᇸ'=>'ᇸ','ᇹ'=>'ᇹ','ሀ'=>'ሀ','ሁ'=>'ሁ','ሂ'=>'ሂ','ሃ'=>'ሃ','ሄ'=>'ሄ','ህ'=>'ህ','ሆ'=>'ሆ','ሇ'=>'ሇ','ለ'=>'ለ','ሉ'=>'ሉ','ሊ'=>'ሊ','ላ'=>'ላ','ሌ'=>'ሌ','ል'=>'ል','ሎ'=>'ሎ','ሏ'=>'ሏ','ሐ'=>'ሐ','ሑ'=>'ሑ','ሒ'=>'ሒ','ሓ'=>'ሓ','ሔ'=>'ሔ','ሕ'=>'ሕ','ሖ'=>'ሖ','ሗ'=>'ሗ','መ'=>'መ','ሙ'=>'ሙ','ሚ'=>'ሚ','ማ'=>'ማ','ሜ'=>'ሜ','ም'=>'ም','ሞ'=>'ሞ','ሟ'=>'ሟ','ሠ'=>'ሠ','ሡ'=>'ሡ','ሢ'=>'ሢ','ሣ'=>'ሣ','ሤ'=>'ሤ','ሥ'=>'ሥ','ሦ'=>'ሦ','ሧ'=>'ሧ','ረ'=>'ረ','ሩ'=>'ሩ','ሪ'=>'ሪ','ራ'=>'ራ','ሬ'=>'ሬ','ር'=>'ር','ሮ'=>'ሮ','ሯ'=>'ሯ','ሰ'=>'ሰ','ሱ'=>'ሱ','ሲ'=>'ሲ','ሳ'=>'ሳ','ሴ'=>'ሴ','ስ'=>'ስ','ሶ'=>'ሶ','ሷ'=>'ሷ','ሸ'=>'ሸ','ሹ'=>'ሹ','ሺ'=>'ሺ','ሻ'=>'ሻ','ሼ'=>'ሼ','ሽ'=>'ሽ','ሾ'=>'ሾ','ሿ'=>'ሿ','ቀ'=>'ቀ','ቁ'=>'ቁ','ቂ'=>'ቂ','ቃ'=>'ቃ','ቄ'=>'ቄ','ቅ'=>'ቅ','ቆ'=>'ቆ','ቇ'=>'ቇ','ቈ'=>'ቈ','ቊ'=>'ቊ','ቋ'=>'ቋ','ቌ'=>'ቌ','ቍ'=>'ቍ','ቐ'=>'ቐ','ቑ'=>'ቑ','ቒ'=>'ቒ','ቓ'=>'ቓ','ቔ'=>'ቔ','ቕ'=>'ቕ','ቖ'=>'ቖ','ቘ'=>'ቘ','ቚ'=>'ቚ','ቛ'=>'ቛ','ቜ'=>'ቜ','ቝ'=>'ቝ','በ'=>'በ','ቡ'=>'ቡ','ቢ'=>'ቢ','ባ'=>'ባ','ቤ'=>'ቤ','ብ'=>'ብ','ቦ'=>'ቦ','ቧ'=>'ቧ','ቨ'=>'ቨ','ቩ'=>'ቩ','ቪ'=>'ቪ','ቫ'=>'ቫ','ቬ'=>'ቬ','ቭ'=>'ቭ','ቮ'=>'ቮ','ቯ'=>'ቯ','ተ'=>'ተ','ቱ'=>'ቱ','ቲ'=>'ቲ','ታ'=>'ታ','ቴ'=>'ቴ','ት'=>'ት','ቶ'=>'ቶ','ቷ'=>'ቷ','ቸ'=>'ቸ','ቹ'=>'ቹ','ቺ'=>'ቺ','ቻ'=>'ቻ','ቼ'=>'ቼ','ች'=>'ች','ቾ'=>'ቾ','ቿ'=>'ቿ','ኀ'=>'ኀ','ኁ'=>'ኁ','ኂ'=>'ኂ','ኃ'=>'ኃ','ኄ'=>'ኄ','ኅ'=>'ኅ','ኆ'=>'ኆ','ኇ'=>'ኇ','ኈ'=>'ኈ','ኊ'=>'ኊ','ኋ'=>'ኋ','ኌ'=>'ኌ','ኍ'=>'ኍ','ነ'=>'ነ','ኑ'=>'ኑ','ኒ'=>'ኒ','ና'=>'ና','ኔ'=>'ኔ','ን'=>'ን','ኖ'=>'ኖ','ኗ'=>'ኗ','ኘ'=>'ኘ','ኙ'=>'ኙ','ኚ'=>'ኚ','ኛ'=>'ኛ','ኜ'=>'ኜ','ኝ'=>'ኝ','ኞ'=>'ኞ','ኟ'=>'ኟ','አ'=>'አ','ኡ'=>'ኡ','ኢ'=>'ኢ','ኣ'=>'ኣ','ኤ'=>'ኤ','እ'=>'እ','ኦ'=>'ኦ','ኧ'=>'ኧ','ከ'=>'ከ','ኩ'=>'ኩ','ኪ'=>'ኪ','ካ'=>'ካ','ኬ'=>'ኬ','ክ'=>'ክ','ኮ'=>'ኮ','ኯ'=>'ኯ','ኰ'=>'ኰ','ኲ'=>'ኲ','ኳ'=>'ኳ','ኴ'=>'ኴ','ኵ'=>'ኵ','ኸ'=>'ኸ','ኹ'=>'ኹ','ኺ'=>'ኺ','ኻ'=>'ኻ','ኼ'=>'ኼ','ኽ'=>'ኽ','ኾ'=>'ኾ','ዀ'=>'ዀ','ዂ'=>'ዂ','ዃ'=>'ዃ','ዄ'=>'ዄ','ዅ'=>'ዅ','ወ'=>'ወ','ዉ'=>'ዉ','ዊ'=>'ዊ','ዋ'=>'ዋ','ዌ'=>'ዌ','ው'=>'ው','ዎ'=>'ዎ','ዏ'=>'ዏ','ዐ'=>'ዐ','ዑ'=>'ዑ','ዒ'=>'ዒ','ዓ'=>'ዓ','ዔ'=>'ዔ','ዕ'=>'ዕ','ዖ'=>'ዖ','ዘ'=>'ዘ','ዙ'=>'ዙ','ዚ'=>'ዚ','ዛ'=>'ዛ','ዜ'=>'ዜ','ዝ'=>'ዝ','ዞ'=>'ዞ','ዟ'=>'ዟ','ዠ'=>'ዠ','ዡ'=>'ዡ','ዢ'=>'ዢ','ዣ'=>'ዣ','ዤ'=>'ዤ','ዥ'=>'ዥ','ዦ'=>'ዦ','ዧ'=>'ዧ','የ'=>'የ','ዩ'=>'ዩ','ዪ'=>'ዪ','ያ'=>'ያ','ዬ'=>'ዬ','ይ'=>'ይ','ዮ'=>'ዮ','ዯ'=>'ዯ','ደ'=>'ደ','ዱ'=>'ዱ','ዲ'=>'ዲ','ዳ'=>'ዳ','ዴ'=>'ዴ','ድ'=>'ድ','ዶ'=>'ዶ','ዷ'=>'ዷ','ዸ'=>'ዸ','ዹ'=>'ዹ','ዺ'=>'ዺ','ዻ'=>'ዻ','ዼ'=>'ዼ','ዽ'=>'ዽ','ዾ'=>'ዾ','ዿ'=>'ዿ','ጀ'=>'ጀ','ጁ'=>'ጁ','ጂ'=>'ጂ','ጃ'=>'ጃ','ጄ'=>'ጄ','ጅ'=>'ጅ','ጆ'=>'ጆ','ጇ'=>'ጇ','ገ'=>'ገ','ጉ'=>'ጉ','ጊ'=>'ጊ','ጋ'=>'ጋ','ጌ'=>'ጌ','ግ'=>'ግ','ጎ'=>'ጎ','ጏ'=>'ጏ','ጐ'=>'ጐ','ጒ'=>'ጒ','ጓ'=>'ጓ','ጔ'=>'ጔ','ጕ'=>'ጕ','ጘ'=>'ጘ','ጙ'=>'ጙ','ጚ'=>'ጚ','ጛ'=>'ጛ','ጜ'=>'ጜ','ጝ'=>'ጝ','ጞ'=>'ጞ','ጟ'=>'ጟ','ጠ'=>'ጠ','ጡ'=>'ጡ','ጢ'=>'ጢ','ጣ'=>'ጣ','ጤ'=>'ጤ','ጥ'=>'ጥ','ጦ'=>'ጦ','ጧ'=>'ጧ','ጨ'=>'ጨ','ጩ'=>'ጩ','ጪ'=>'ጪ','ጫ'=>'ጫ','ጬ'=>'ጬ','ጭ'=>'ጭ','ጮ'=>'ጮ','ጯ'=>'ጯ','ጰ'=>'ጰ','ጱ'=>'ጱ','ጲ'=>'ጲ','ጳ'=>'ጳ','ጴ'=>'ጴ','ጵ'=>'ጵ','ጶ'=>'ጶ','ጷ'=>'ጷ','ጸ'=>'ጸ','ጹ'=>'ጹ','ጺ'=>'ጺ','ጻ'=>'ጻ','ጼ'=>'ጼ','ጽ'=>'ጽ','ጾ'=>'ጾ','ጿ'=>'ጿ','ፀ'=>'ፀ','ፁ'=>'ፁ','ፂ'=>'ፂ','ፃ'=>'ፃ','ፄ'=>'ፄ','ፅ'=>'ፅ','ፆ'=>'ፆ','ፇ'=>'ፇ','ፈ'=>'ፈ','ፉ'=>'ፉ','ፊ'=>'ፊ','ፋ'=>'ፋ','ፌ'=>'ፌ','ፍ'=>'ፍ','ፎ'=>'ፎ','ፏ'=>'ፏ','ፐ'=>'ፐ','ፑ'=>'ፑ','ፒ'=>'ፒ','ፓ'=>'ፓ','ፔ'=>'ፔ','ፕ'=>'ፕ','ፖ'=>'ፖ','ፗ'=>'ፗ','ፘ'=>'ፘ','ፙ'=>'ፙ','ፚ'=>'ፚ','፟'=>'፟','፩'=>'1','፪'=>'2','፫'=>'3','፬'=>'4','፭'=>'5','፮'=>'6','፯'=>'7','፰'=>'8','፱'=>'9','፲'=>'10','፳'=>'20','፴'=>'30','፵'=>'40','፶'=>'50','፷'=>'60','፸'=>'70','፹'=>'80','፺'=>'90','፻'=>'100','፼'=>'10000','ᎀ'=>'ᎀ','ᎁ'=>'ᎁ','ᎂ'=>'ᎂ','ᎃ'=>'ᎃ','ᎄ'=>'ᎄ','ᎅ'=>'ᎅ','ᎆ'=>'ᎆ','ᎇ'=>'ᎇ','ᎈ'=>'ᎈ','ᎉ'=>'ᎉ','ᎊ'=>'ᎊ','ᎋ'=>'ᎋ','ᎌ'=>'ᎌ','ᎍ'=>'ᎍ','ᎎ'=>'ᎎ','ᎏ'=>'ᎏ','Ꭰ'=>'Ꭰ','Ꭱ'=>'Ꭱ','Ꭲ'=>'Ꭲ','Ꭳ'=>'Ꭳ','Ꭴ'=>'Ꭴ','Ꭵ'=>'Ꭵ','Ꭶ'=>'Ꭶ','Ꭷ'=>'Ꭷ','Ꭸ'=>'Ꭸ','Ꭹ'=>'Ꭹ','Ꭺ'=>'Ꭺ','Ꭻ'=>'Ꭻ','Ꭼ'=>'Ꭼ','Ꭽ'=>'Ꭽ','Ꭾ'=>'Ꭾ','Ꭿ'=>'Ꭿ','Ꮀ'=>'Ꮀ','Ꮁ'=>'Ꮁ','Ꮂ'=>'Ꮂ','Ꮃ'=>'Ꮃ','Ꮄ'=>'Ꮄ','Ꮅ'=>'Ꮅ','Ꮆ'=>'Ꮆ','Ꮇ'=>'Ꮇ','Ꮈ'=>'Ꮈ','Ꮉ'=>'Ꮉ','Ꮊ'=>'Ꮊ','Ꮋ'=>'Ꮋ','Ꮌ'=>'Ꮌ','Ꮍ'=>'Ꮍ','Ꮎ'=>'Ꮎ','Ꮏ'=>'Ꮏ','Ꮐ'=>'Ꮐ','Ꮑ'=>'Ꮑ','Ꮒ'=>'Ꮒ','Ꮓ'=>'Ꮓ','Ꮔ'=>'Ꮔ','Ꮕ'=>'Ꮕ','Ꮖ'=>'Ꮖ','Ꮗ'=>'Ꮗ','Ꮘ'=>'Ꮘ','Ꮙ'=>'Ꮙ','Ꮚ'=>'Ꮚ','Ꮛ'=>'Ꮛ','Ꮜ'=>'Ꮜ','Ꮝ'=>'Ꮝ','Ꮞ'=>'Ꮞ','Ꮟ'=>'Ꮟ','Ꮠ'=>'Ꮠ','Ꮡ'=>'Ꮡ','Ꮢ'=>'Ꮢ','Ꮣ'=>'Ꮣ','Ꮤ'=>'Ꮤ','Ꮥ'=>'Ꮥ','Ꮦ'=>'Ꮦ','Ꮧ'=>'Ꮧ','Ꮨ'=>'Ꮨ','Ꮩ'=>'Ꮩ','Ꮪ'=>'Ꮪ','Ꮫ'=>'Ꮫ','Ꮬ'=>'Ꮬ','Ꮭ'=>'Ꮭ','Ꮮ'=>'Ꮮ','Ꮯ'=>'Ꮯ','Ꮰ'=>'Ꮰ','Ꮱ'=>'Ꮱ','Ꮲ'=>'Ꮲ','Ꮳ'=>'Ꮳ','Ꮴ'=>'Ꮴ','Ꮵ'=>'Ꮵ','Ꮶ'=>'Ꮶ','Ꮷ'=>'Ꮷ','Ꮸ'=>'Ꮸ','Ꮹ'=>'Ꮹ','Ꮺ'=>'Ꮺ','Ꮻ'=>'Ꮻ','Ꮼ'=>'Ꮼ','Ꮽ'=>'Ꮽ','Ꮾ'=>'Ꮾ','Ꮿ'=>'Ꮿ','Ᏸ'=>'Ᏸ','Ᏹ'=>'Ᏹ','Ᏺ'=>'Ᏺ','Ᏻ'=>'Ᏻ','Ᏼ'=>'Ᏼ','ᐁ'=>'ᐁ','ᐂ'=>'ᐂ','ᐃ'=>'ᐃ','ᐄ'=>'ᐄ','ᐅ'=>'ᐅ','ᐆ'=>'ᐆ','ᐇ'=>'ᐇ','ᐈ'=>'ᐈ','ᐉ'=>'ᐉ','ᐊ'=>'ᐊ','ᐋ'=>'ᐋ','ᐌ'=>'ᐌ','ᐍ'=>'ᐍ','ᐎ'=>'ᐎ','ᐏ'=>'ᐏ','ᐐ'=>'ᐐ','ᐑ'=>'ᐑ','ᐒ'=>'ᐒ','ᐓ'=>'ᐓ','ᐔ'=>'ᐔ','ᐕ'=>'ᐕ','ᐖ'=>'ᐖ','ᐗ'=>'ᐗ','ᐘ'=>'ᐘ','ᐙ'=>'ᐙ','ᐚ'=>'ᐚ','ᐛ'=>'ᐛ','ᐜ'=>'ᐜ','ᐝ'=>'ᐝ','ᐞ'=>'ᐞ','ᐟ'=>'ᐟ','ᐠ'=>'ᐠ','ᐡ'=>'ᐡ','ᐢ'=>'ᐢ','ᐣ'=>'ᐣ','ᐤ'=>'ᐤ','ᐥ'=>'ᐥ','ᐦ'=>'ᐦ','ᐧ'=>'ᐧ','ᐨ'=>'ᐨ','ᐩ'=>'ᐩ','ᐪ'=>'ᐪ','ᐫ'=>'ᐫ','ᐬ'=>'ᐬ','ᐭ'=>'ᐭ','ᐮ'=>'ᐮ','ᐯ'=>'ᐯ','ᐰ'=>'ᐰ','ᐱ'=>'ᐱ','ᐲ'=>'ᐲ','ᐳ'=>'ᐳ','ᐴ'=>'ᐴ','ᐵ'=>'ᐵ','ᐶ'=>'ᐶ','ᐷ'=>'ᐷ','ᐸ'=>'ᐸ','ᐹ'=>'ᐹ','ᐺ'=>'ᐺ','ᐻ'=>'ᐻ','ᐼ'=>'ᐼ','ᐽ'=>'ᐽ','ᐾ'=>'ᐾ','ᐿ'=>'ᐿ','ᑀ'=>'ᑀ','ᑁ'=>'ᑁ','ᑂ'=>'ᑂ','ᑃ'=>'ᑃ','ᑄ'=>'ᑄ','ᑅ'=>'ᑅ','ᑆ'=>'ᑆ','ᑇ'=>'ᑇ','ᑈ'=>'ᑈ','ᑉ'=>'ᑉ','ᑊ'=>'ᑊ','ᑋ'=>'ᑋ','ᑌ'=>'ᑌ','ᑍ'=>'ᑍ','ᑎ'=>'ᑎ','ᑏ'=>'ᑏ','ᑐ'=>'ᑐ','ᑑ'=>'ᑑ','ᑒ'=>'ᑒ','ᑓ'=>'ᑓ','ᑔ'=>'ᑔ','ᑕ'=>'ᑕ','ᑖ'=>'ᑖ','ᑗ'=>'ᑗ','ᑘ'=>'ᑘ','ᑙ'=>'ᑙ','ᑚ'=>'ᑚ','ᑛ'=>'ᑛ','ᑜ'=>'ᑜ','ᑝ'=>'ᑝ','ᑞ'=>'ᑞ','ᑟ'=>'ᑟ','ᑠ'=>'ᑠ','ᑡ'=>'ᑡ','ᑢ'=>'ᑢ','ᑣ'=>'ᑣ','ᑤ'=>'ᑤ','ᑥ'=>'ᑥ','ᑦ'=>'ᑦ','ᑧ'=>'ᑧ','ᑨ'=>'ᑨ','ᑩ'=>'ᑩ','ᑪ'=>'ᑪ','ᑫ'=>'ᑫ','ᑬ'=>'ᑬ','ᑭ'=>'ᑭ','ᑮ'=>'ᑮ','ᑯ'=>'ᑯ','ᑰ'=>'ᑰ','ᑱ'=>'ᑱ','ᑲ'=>'ᑲ','ᑳ'=>'ᑳ','ᑴ'=>'ᑴ','ᑵ'=>'ᑵ','ᑶ'=>'ᑶ','ᑷ'=>'ᑷ','ᑸ'=>'ᑸ','ᑹ'=>'ᑹ','ᑺ'=>'ᑺ','ᑻ'=>'ᑻ','ᑼ'=>'ᑼ','ᑽ'=>'ᑽ','ᑾ'=>'ᑾ','ᑿ'=>'ᑿ','ᒀ'=>'ᒀ','ᒁ'=>'ᒁ','ᒂ'=>'ᒂ','ᒃ'=>'ᒃ','ᒄ'=>'ᒄ','ᒅ'=>'ᒅ','ᒆ'=>'ᒆ','ᒇ'=>'ᒇ','ᒈ'=>'ᒈ','ᒉ'=>'ᒉ','ᒊ'=>'ᒊ','ᒋ'=>'ᒋ','ᒌ'=>'ᒌ','ᒍ'=>'ᒍ','ᒎ'=>'ᒎ','ᒏ'=>'ᒏ','ᒐ'=>'ᒐ','ᒑ'=>'ᒑ','ᒒ'=>'ᒒ','ᒓ'=>'ᒓ','ᒔ'=>'ᒔ','ᒕ'=>'ᒕ','ᒖ'=>'ᒖ','ᒗ'=>'ᒗ','ᒘ'=>'ᒘ','ᒙ'=>'ᒙ','ᒚ'=>'ᒚ','ᒛ'=>'ᒛ','ᒜ'=>'ᒜ','ᒝ'=>'ᒝ','ᒞ'=>'ᒞ','ᒟ'=>'ᒟ','ᒠ'=>'ᒠ','ᒡ'=>'ᒡ','ᒢ'=>'ᒢ','ᒣ'=>'ᒣ','ᒤ'=>'ᒤ','ᒥ'=>'ᒥ','ᒦ'=>'ᒦ','ᒧ'=>'ᒧ','ᒨ'=>'ᒨ','ᒩ'=>'ᒩ','ᒪ'=>'ᒪ','ᒫ'=>'ᒫ','ᒬ'=>'ᒬ','ᒭ'=>'ᒭ','ᒮ'=>'ᒮ','ᒯ'=>'ᒯ','ᒰ'=>'ᒰ','ᒱ'=>'ᒱ','ᒲ'=>'ᒲ','ᒳ'=>'ᒳ','ᒴ'=>'ᒴ','ᒵ'=>'ᒵ','ᒶ'=>'ᒶ','ᒷ'=>'ᒷ','ᒸ'=>'ᒸ','ᒹ'=>'ᒹ','ᒺ'=>'ᒺ','ᒻ'=>'ᒻ','ᒼ'=>'ᒼ','ᒽ'=>'ᒽ','ᒾ'=>'ᒾ','ᒿ'=>'ᒿ','ᓀ'=>'ᓀ','ᓁ'=>'ᓁ','ᓂ'=>'ᓂ','ᓃ'=>'ᓃ','ᓄ'=>'ᓄ','ᓅ'=>'ᓅ','ᓆ'=>'ᓆ','ᓇ'=>'ᓇ','ᓈ'=>'ᓈ','ᓉ'=>'ᓉ','ᓊ'=>'ᓊ','ᓋ'=>'ᓋ','ᓌ'=>'ᓌ','ᓍ'=>'ᓍ','ᓎ'=>'ᓎ','ᓏ'=>'ᓏ','ᓐ'=>'ᓐ','ᓑ'=>'ᓑ','ᓒ'=>'ᓒ','ᓓ'=>'ᓓ','ᓔ'=>'ᓔ','ᓕ'=>'ᓕ','ᓖ'=>'ᓖ','ᓗ'=>'ᓗ','ᓘ'=>'ᓘ','ᓙ'=>'ᓙ','ᓚ'=>'ᓚ','ᓛ'=>'ᓛ','ᓜ'=>'ᓜ','ᓝ'=>'ᓝ','ᓞ'=>'ᓞ','ᓟ'=>'ᓟ','ᓠ'=>'ᓠ','ᓡ'=>'ᓡ','ᓢ'=>'ᓢ','ᓣ'=>'ᓣ','ᓤ'=>'ᓤ','ᓥ'=>'ᓥ','ᓦ'=>'ᓦ','ᓧ'=>'ᓧ','ᓨ'=>'ᓨ','ᓩ'=>'ᓩ','ᓪ'=>'ᓪ','ᓫ'=>'ᓫ','ᓬ'=>'ᓬ','ᓭ'=>'ᓭ','ᓮ'=>'ᓮ','ᓯ'=>'ᓯ','ᓰ'=>'ᓰ','ᓱ'=>'ᓱ','ᓲ'=>'ᓲ','ᓳ'=>'ᓳ','ᓴ'=>'ᓴ','ᓵ'=>'ᓵ','ᓶ'=>'ᓶ','ᓷ'=>'ᓷ','ᓸ'=>'ᓸ','ᓹ'=>'ᓹ','ᓺ'=>'ᓺ','ᓻ'=>'ᓻ','ᓼ'=>'ᓼ','ᓽ'=>'ᓽ','ᓾ'=>'ᓾ','ᓿ'=>'ᓿ','ᔀ'=>'ᔀ','ᔁ'=>'ᔁ','ᔂ'=>'ᔂ','ᔃ'=>'ᔃ','ᔄ'=>'ᔄ','ᔅ'=>'ᔅ','ᔆ'=>'ᔆ','ᔇ'=>'ᔇ','ᔈ'=>'ᔈ','ᔉ'=>'ᔉ','ᔊ'=>'ᔊ','ᔋ'=>'ᔋ','ᔌ'=>'ᔌ','ᔍ'=>'ᔍ','ᔎ'=>'ᔎ','ᔏ'=>'ᔏ','ᔐ'=>'ᔐ','ᔑ'=>'ᔑ','ᔒ'=>'ᔒ','ᔓ'=>'ᔓ','ᔔ'=>'ᔔ','ᔕ'=>'ᔕ','ᔖ'=>'ᔖ','ᔗ'=>'ᔗ','ᔘ'=>'ᔘ','ᔙ'=>'ᔙ','ᔚ'=>'ᔚ','ᔛ'=>'ᔛ','ᔜ'=>'ᔜ','ᔝ'=>'ᔝ','ᔞ'=>'ᔞ','ᔟ'=>'ᔟ','ᔠ'=>'ᔠ','ᔡ'=>'ᔡ','ᔢ'=>'ᔢ','ᔣ'=>'ᔣ','ᔤ'=>'ᔤ','ᔥ'=>'ᔥ','ᔦ'=>'ᔦ','ᔧ'=>'ᔧ','ᔨ'=>'ᔨ','ᔩ'=>'ᔩ','ᔪ'=>'ᔪ','ᔫ'=>'ᔫ','ᔬ'=>'ᔬ','ᔭ'=>'ᔭ','ᔮ'=>'ᔮ','ᔯ'=>'ᔯ','ᔰ'=>'ᔰ','ᔱ'=>'ᔱ','ᔲ'=>'ᔲ','ᔳ'=>'ᔳ','ᔴ'=>'ᔴ','ᔵ'=>'ᔵ','ᔶ'=>'ᔶ','ᔷ'=>'ᔷ','ᔸ'=>'ᔸ','ᔹ'=>'ᔹ','ᔺ'=>'ᔺ','ᔻ'=>'ᔻ','ᔼ'=>'ᔼ','ᔽ'=>'ᔽ','ᔾ'=>'ᔾ','ᔿ'=>'ᔿ','ᕀ'=>'ᕀ','ᕁ'=>'ᕁ','ᕂ'=>'ᕂ','ᕃ'=>'ᕃ','ᕄ'=>'ᕄ','ᕅ'=>'ᕅ','ᕆ'=>'ᕆ','ᕇ'=>'ᕇ','ᕈ'=>'ᕈ','ᕉ'=>'ᕉ','ᕊ'=>'ᕊ','ᕋ'=>'ᕋ','ᕌ'=>'ᕌ','ᕍ'=>'ᕍ','ᕎ'=>'ᕎ','ᕏ'=>'ᕏ','ᕐ'=>'ᕐ','ᕑ'=>'ᕑ','ᕒ'=>'ᕒ','ᕓ'=>'ᕓ','ᕔ'=>'ᕔ','ᕕ'=>'ᕕ','ᕖ'=>'ᕖ','ᕗ'=>'ᕗ','ᕘ'=>'ᕘ','ᕙ'=>'ᕙ','ᕚ'=>'ᕚ','ᕛ'=>'ᕛ','ᕜ'=>'ᕜ','ᕝ'=>'ᕝ','ᕞ'=>'ᕞ','ᕟ'=>'ᕟ','ᕠ'=>'ᕠ','ᕡ'=>'ᕡ','ᕢ'=>'ᕢ','ᕣ'=>'ᕣ','ᕤ'=>'ᕤ','ᕥ'=>'ᕥ','ᕦ'=>'ᕦ','ᕧ'=>'ᕧ','ᕨ'=>'ᕨ','ᕩ'=>'ᕩ','ᕪ'=>'ᕪ','ᕫ'=>'ᕫ','ᕬ'=>'ᕬ','ᕭ'=>'ᕭ','ᕮ'=>'ᕮ','ᕯ'=>'ᕯ','ᕰ'=>'ᕰ','ᕱ'=>'ᕱ','ᕲ'=>'ᕲ','ᕳ'=>'ᕳ','ᕴ'=>'ᕴ','ᕵ'=>'ᕵ','ᕶ'=>'ᕶ','ᕷ'=>'ᕷ','ᕸ'=>'ᕸ','ᕹ'=>'ᕹ','ᕺ'=>'ᕺ','ᕻ'=>'ᕻ','ᕼ'=>'ᕼ','ᕽ'=>'ᕽ','ᕾ'=>'ᕾ','ᕿ'=>'ᕿ','ᖀ'=>'ᖀ','ᖁ'=>'ᖁ','ᖂ'=>'ᖂ','ᖃ'=>'ᖃ','ᖄ'=>'ᖄ','ᖅ'=>'ᖅ','ᖆ'=>'ᖆ','ᖇ'=>'ᖇ','ᖈ'=>'ᖈ','ᖉ'=>'ᖉ','ᖊ'=>'ᖊ','ᖋ'=>'ᖋ','ᖌ'=>'ᖌ','ᖍ'=>'ᖍ','ᖎ'=>'ᖎ','ᖏ'=>'ᖏ','ᖐ'=>'ᖐ','ᖑ'=>'ᖑ','ᖒ'=>'ᖒ','ᖓ'=>'ᖓ','ᖔ'=>'ᖔ','ᖕ'=>'ᖕ','ᖖ'=>'ᖖ','ᖗ'=>'ᖗ','ᖘ'=>'ᖘ','ᖙ'=>'ᖙ','ᖚ'=>'ᖚ','ᖛ'=>'ᖛ','ᖜ'=>'ᖜ','ᖝ'=>'ᖝ','ᖞ'=>'ᖞ','ᖟ'=>'ᖟ','ᖠ'=>'ᖠ','ᖡ'=>'ᖡ','ᖢ'=>'ᖢ','ᖣ'=>'ᖣ','ᖤ'=>'ᖤ','ᖥ'=>'ᖥ','ᖦ'=>'ᖦ','ᖧ'=>'ᖧ','ᖨ'=>'ᖨ','ᖩ'=>'ᖩ','ᖪ'=>'ᖪ','ᖫ'=>'ᖫ','ᖬ'=>'ᖬ','ᖭ'=>'ᖭ','ᖮ'=>'ᖮ','ᖯ'=>'ᖯ','ᖰ'=>'ᖰ','ᖱ'=>'ᖱ','ᖲ'=>'ᖲ','ᖳ'=>'ᖳ','ᖴ'=>'ᖴ','ᖵ'=>'ᖵ','ᖶ'=>'ᖶ','ᖷ'=>'ᖷ','ᖸ'=>'ᖸ','ᖹ'=>'ᖹ','ᖺ'=>'ᖺ','ᖻ'=>'ᖻ','ᖼ'=>'ᖼ','ᖽ'=>'ᖽ','ᖾ'=>'ᖾ','ᖿ'=>'ᖿ','ᗀ'=>'ᗀ','ᗁ'=>'ᗁ','ᗂ'=>'ᗂ','ᗃ'=>'ᗃ','ᗄ'=>'ᗄ','ᗅ'=>'ᗅ','ᗆ'=>'ᗆ','ᗇ'=>'ᗇ','ᗈ'=>'ᗈ','ᗉ'=>'ᗉ','ᗊ'=>'ᗊ','ᗋ'=>'ᗋ','ᗌ'=>'ᗌ','ᗍ'=>'ᗍ','ᗎ'=>'ᗎ','ᗏ'=>'ᗏ','ᗐ'=>'ᗐ','ᗑ'=>'ᗑ','ᗒ'=>'ᗒ','ᗓ'=>'ᗓ','ᗔ'=>'ᗔ','ᗕ'=>'ᗕ','ᗖ'=>'ᗖ','ᗗ'=>'ᗗ','ᗘ'=>'ᗘ','ᗙ'=>'ᗙ','ᗚ'=>'ᗚ','ᗛ'=>'ᗛ','ᗜ'=>'ᗜ','ᗝ'=>'ᗝ','ᗞ'=>'ᗞ','ᗟ'=>'ᗟ','ᗠ'=>'ᗠ','ᗡ'=>'ᗡ','ᗢ'=>'ᗢ','ᗣ'=>'ᗣ','ᗤ'=>'ᗤ','ᗥ'=>'ᗥ','ᗦ'=>'ᗦ','ᗧ'=>'ᗧ','ᗨ'=>'ᗨ','ᗩ'=>'ᗩ','ᗪ'=>'ᗪ','ᗫ'=>'ᗫ','ᗬ'=>'ᗬ','ᗭ'=>'ᗭ','ᗮ'=>'ᗮ','ᗯ'=>'ᗯ','ᗰ'=>'ᗰ','ᗱ'=>'ᗱ','ᗲ'=>'ᗲ','ᗳ'=>'ᗳ','ᗴ'=>'ᗴ','ᗵ'=>'ᗵ','ᗶ'=>'ᗶ','ᗷ'=>'ᗷ','ᗸ'=>'ᗸ','ᗹ'=>'ᗹ','ᗺ'=>'ᗺ','ᗻ'=>'ᗻ','ᗼ'=>'ᗼ','ᗽ'=>'ᗽ','ᗾ'=>'ᗾ','ᗿ'=>'ᗿ','ᘀ'=>'ᘀ','ᘁ'=>'ᘁ','ᘂ'=>'ᘂ','ᘃ'=>'ᘃ','ᘄ'=>'ᘄ','ᘅ'=>'ᘅ','ᘆ'=>'ᘆ','ᘇ'=>'ᘇ','ᘈ'=>'ᘈ','ᘉ'=>'ᘉ','ᘊ'=>'ᘊ','ᘋ'=>'ᘋ','ᘌ'=>'ᘌ','ᘍ'=>'ᘍ','ᘎ'=>'ᘎ','ᘏ'=>'ᘏ','ᘐ'=>'ᘐ','ᘑ'=>'ᘑ','ᘒ'=>'ᘒ','ᘓ'=>'ᘓ','ᘔ'=>'ᘔ','ᘕ'=>'ᘕ','ᘖ'=>'ᘖ','ᘗ'=>'ᘗ','ᘘ'=>'ᘘ','ᘙ'=>'ᘙ','ᘚ'=>'ᘚ','ᘛ'=>'ᘛ','ᘜ'=>'ᘜ','ᘝ'=>'ᘝ','ᘞ'=>'ᘞ','ᘟ'=>'ᘟ','ᘠ'=>'ᘠ','ᘡ'=>'ᘡ','ᘢ'=>'ᘢ','ᘣ'=>'ᘣ','ᘤ'=>'ᘤ','ᘥ'=>'ᘥ','ᘦ'=>'ᘦ','ᘧ'=>'ᘧ','ᘨ'=>'ᘨ','ᘩ'=>'ᘩ','ᘪ'=>'ᘪ','ᘫ'=>'ᘫ','ᘬ'=>'ᘬ','ᘭ'=>'ᘭ','ᘮ'=>'ᘮ','ᘯ'=>'ᘯ','ᘰ'=>'ᘰ','ᘱ'=>'ᘱ','ᘲ'=>'ᘲ','ᘳ'=>'ᘳ','ᘴ'=>'ᘴ','ᘵ'=>'ᘵ','ᘶ'=>'ᘶ','ᘷ'=>'ᘷ','ᘸ'=>'ᘸ','ᘹ'=>'ᘹ','ᘺ'=>'ᘺ','ᘻ'=>'ᘻ','ᘼ'=>'ᘼ','ᘽ'=>'ᘽ','ᘾ'=>'ᘾ','ᘿ'=>'ᘿ','ᙀ'=>'ᙀ','ᙁ'=>'ᙁ','ᙂ'=>'ᙂ','ᙃ'=>'ᙃ','ᙄ'=>'ᙄ','ᙅ'=>'ᙅ','ᙆ'=>'ᙆ','ᙇ'=>'ᙇ','ᙈ'=>'ᙈ','ᙉ'=>'ᙉ','ᙊ'=>'ᙊ','ᙋ'=>'ᙋ','ᙌ'=>'ᙌ','ᙍ'=>'ᙍ','ᙎ'=>'ᙎ','ᙏ'=>'ᙏ','ᙐ'=>'ᙐ','ᙑ'=>'ᙑ','ᙒ'=>'ᙒ','ᙓ'=>'ᙓ','ᙔ'=>'ᙔ','ᙕ'=>'ᙕ','ᙖ'=>'ᙖ','ᙗ'=>'ᙗ','ᙘ'=>'ᙘ','ᙙ'=>'ᙙ','ᙚ'=>'ᙚ','ᙛ'=>'ᙛ','ᙜ'=>'ᙜ','ᙝ'=>'ᙝ','ᙞ'=>'ᙞ','ᙟ'=>'ᙟ','ᙠ'=>'ᙠ','ᙡ'=>'ᙡ','ᙢ'=>'ᙢ','ᙣ'=>'ᙣ','ᙤ'=>'ᙤ','ᙥ'=>'ᙥ','ᙦ'=>'ᙦ','ᙧ'=>'ᙧ','ᙨ'=>'ᙨ','ᙩ'=>'ᙩ','ᙪ'=>'ᙪ','ᙫ'=>'ᙫ','ᙬ'=>'ᙬ','ᙯ'=>'ᙯ','ᙰ'=>'ᙰ','ᙱ'=>'ᙱ','ᙲ'=>'ᙲ','ᙳ'=>'ᙳ','ᙴ'=>'ᙴ','ᙵ'=>'ᙵ','ᙶ'=>'ᙶ','ᚁ'=>'ᚁ','ᚂ'=>'ᚂ','ᚃ'=>'ᚃ','ᚄ'=>'ᚄ','ᚅ'=>'ᚅ','ᚆ'=>'ᚆ','ᚇ'=>'ᚇ','ᚈ'=>'ᚈ','ᚉ'=>'ᚉ','ᚊ'=>'ᚊ','ᚋ'=>'ᚋ','ᚌ'=>'ᚌ','ᚍ'=>'ᚍ','ᚎ'=>'ᚎ','ᚏ'=>'ᚏ','ᚐ'=>'ᚐ','ᚑ'=>'ᚑ','ᚒ'=>'ᚒ','ᚓ'=>'ᚓ','ᚔ'=>'ᚔ','ᚕ'=>'ᚕ','ᚖ'=>'ᚖ','ᚗ'=>'ᚗ','ᚘ'=>'ᚘ','ᚙ'=>'ᚙ','ᚚ'=>'ᚚ','ᚠ'=>'ᚠ','ᚡ'=>'ᚡ','ᚢ'=>'ᚢ','ᚣ'=>'ᚣ','ᚤ'=>'ᚤ','ᚥ'=>'ᚥ','ᚦ'=>'ᚦ','ᚧ'=>'ᚧ','ᚨ'=>'ᚨ','ᚩ'=>'ᚩ','ᚪ'=>'ᚪ','ᚫ'=>'ᚫ','ᚬ'=>'ᚬ','ᚭ'=>'ᚭ','ᚮ'=>'ᚮ','ᚯ'=>'ᚯ','ᚰ'=>'ᚰ','ᚱ'=>'ᚱ','ᚲ'=>'ᚲ','ᚳ'=>'ᚳ','ᚴ'=>'ᚴ','ᚵ'=>'ᚵ','ᚶ'=>'ᚶ','ᚷ'=>'ᚷ','ᚸ'=>'ᚸ','ᚹ'=>'ᚹ','ᚺ'=>'ᚺ','ᚻ'=>'ᚻ','ᚼ'=>'ᚼ','ᚽ'=>'ᚽ','ᚾ'=>'ᚾ','ᚿ'=>'ᚿ','ᛀ'=>'ᛀ','ᛁ'=>'ᛁ','ᛂ'=>'ᛂ','ᛃ'=>'ᛃ','ᛄ'=>'ᛄ','ᛅ'=>'ᛅ','ᛆ'=>'ᛆ','ᛇ'=>'ᛇ','ᛈ'=>'ᛈ','ᛉ'=>'ᛉ','ᛊ'=>'ᛊ','ᛋ'=>'ᛋ','ᛌ'=>'ᛌ','ᛍ'=>'ᛍ','ᛎ'=>'ᛎ','ᛏ'=>'ᛏ','ᛐ'=>'ᛐ','ᛑ'=>'ᛑ','ᛒ'=>'ᛒ','ᛓ'=>'ᛓ','ᛔ'=>'ᛔ','ᛕ'=>'ᛕ','ᛖ'=>'ᛖ','ᛗ'=>'ᛗ','ᛘ'=>'ᛘ','ᛙ'=>'ᛙ','ᛚ'=>'ᛚ','ᛛ'=>'ᛛ','ᛜ'=>'ᛜ','ᛝ'=>'ᛝ','ᛞ'=>'ᛞ','ᛟ'=>'ᛟ','ᛠ'=>'ᛠ','ᛡ'=>'ᛡ','ᛢ'=>'ᛢ','ᛣ'=>'ᛣ','ᛤ'=>'ᛤ','ᛥ'=>'ᛥ','ᛦ'=>'ᛦ','ᛧ'=>'ᛧ','ᛨ'=>'ᛨ','ᛩ'=>'ᛩ','ᛪ'=>'ᛪ','ᛮ'=>'17','ᛯ'=>'18','ᛰ'=>'19','ᜀ'=>'ᜀ','ᜁ'=>'ᜁ','ᜂ'=>'ᜂ','ᜃ'=>'ᜃ','ᜄ'=>'ᜄ','ᜅ'=>'ᜅ','ᜆ'=>'ᜆ','ᜇ'=>'ᜇ','ᜈ'=>'ᜈ','ᜉ'=>'ᜉ','ᜊ'=>'ᜊ','ᜋ'=>'ᜋ','ᜌ'=>'ᜌ','ᜎ'=>'ᜎ','ᜏ'=>'ᜏ','ᜐ'=>'ᜐ','ᜑ'=>'ᜑ','ᜒ'=>'ᜒ','ᜓ'=>'ᜓ','᜔'=>'᜔','ᜠ'=>'ᜠ','ᜡ'=>'ᜡ','ᜢ'=>'ᜢ','ᜣ'=>'ᜣ','ᜤ'=>'ᜤ','ᜥ'=>'ᜥ','ᜦ'=>'ᜦ','ᜧ'=>'ᜧ','ᜨ'=>'ᜨ','ᜩ'=>'ᜩ','ᜪ'=>'ᜪ','ᜫ'=>'ᜫ','ᜬ'=>'ᜬ','ᜭ'=>'ᜭ','ᜮ'=>'ᜮ','ᜯ'=>'ᜯ','ᜰ'=>'ᜰ','ᜱ'=>'ᜱ','ᜲ'=>'ᜲ','ᜳ'=>'ᜳ','᜴'=>'᜴','ᝀ'=>'ᝀ','ᝁ'=>'ᝁ','ᝂ'=>'ᝂ','ᝃ'=>'ᝃ','ᝄ'=>'ᝄ','ᝅ'=>'ᝅ','ᝆ'=>'ᝆ','ᝇ'=>'ᝇ','ᝈ'=>'ᝈ','ᝉ'=>'ᝉ','ᝊ'=>'ᝊ','ᝋ'=>'ᝋ','ᝌ'=>'ᝌ','ᝍ'=>'ᝍ','ᝎ'=>'ᝎ','ᝏ'=>'ᝏ','ᝐ'=>'ᝐ','ᝑ'=>'ᝑ','ᝒ'=>'ᝒ','ᝓ'=>'ᝓ','ᝠ'=>'ᝠ','ᝡ'=>'ᝡ','ᝢ'=>'ᝢ','ᝣ'=>'ᝣ','ᝤ'=>'ᝤ','ᝥ'=>'ᝥ','ᝦ'=>'ᝦ','ᝧ'=>'ᝧ','ᝨ'=>'ᝨ','ᝩ'=>'ᝩ','ᝪ'=>'ᝪ','ᝫ'=>'ᝫ','ᝬ'=>'ᝬ','ᝮ'=>'ᝮ','ᝯ'=>'ᝯ','ᝰ'=>'ᝰ','ᝲ'=>'ᝲ','ᝳ'=>'ᝳ','ក'=>'ក','ខ'=>'ខ','គ'=>'គ','ឃ'=>'ឃ','ង'=>'ង','ច'=>'ច','ឆ'=>'ឆ','ជ'=>'ជ','ឈ'=>'ឈ','ញ'=>'ញ','ដ'=>'ដ','ឋ'=>'ឋ','ឌ'=>'ឌ','ឍ'=>'ឍ','ណ'=>'ណ','ត'=>'ត','ថ'=>'ថ','ទ'=>'ទ','ធ'=>'ធ','ន'=>'ន','ប'=>'ប','ផ'=>'ផ','ព'=>'ព','ភ'=>'ភ','ម'=>'ម','យ'=>'យ','រ'=>'រ','ល'=>'ល','វ'=>'វ','ឝ'=>'ឝ','ឞ'=>'ឞ','ស'=>'ស','ហ'=>'ហ','ឡ'=>'ឡ','អ'=>'អ','ឣ'=>'ឣ','ឤ'=>'ឤ','ឥ'=>'ឥ','ឦ'=>'ឦ','ឧ'=>'ឧ','ឨ'=>'ឨ','ឩ'=>'ឩ','ឪ'=>'ឪ','ឫ'=>'ឫ','ឬ'=>'ឬ','ឭ'=>'ឭ','ឮ'=>'ឮ','ឯ'=>'ឯ','ឰ'=>'ឰ','ឱ'=>'ឱ','ឲ'=>'ឲ','ឳ'=>'ឳ','ា'=>'ា','ិ'=>'ិ','ី'=>'ី','ឹ'=>'ឹ','ឺ'=>'ឺ','ុ'=>'ុ','ូ'=>'ូ','ួ'=>'ួ','ើ'=>'ើ','ឿ'=>'ឿ','ៀ'=>'ៀ','េ'=>'េ','ែ'=>'ែ','ៃ'=>'ៃ','ោ'=>'ោ','ៅ'=>'ៅ','ំ'=>'ំ','ះ'=>'ះ','ៈ'=>'ៈ','៉'=>'៉','៊'=>'៊','់'=>'់','៌'=>'៌','៍'=>'៍','៎'=>'៎','៏'=>'៏','័'=>'័','៑'=>'៑','្'=>'្','៓'=>'៓','ៗ'=>'ៗ','ៜ'=>'ៜ','៝'=>'៝','០'=>'0','១'=>'1','២'=>'2','៣'=>'3','៤'=>'4','៥'=>'5','៦'=>'6','៧'=>'7','៨'=>'8','៩'=>'9','៰'=>'0','៱'=>'1','៲'=>'2','៳'=>'3','៴'=>'4','៵'=>'5','៶'=>'6','៷'=>'7','៸'=>'8','៹'=>'9');
\ No newline at end of file +<?php return array('က'=>'က','ခ'=>'ခ','ဂ'=>'ဂ','ဃ'=>'ဃ','င'=>'င','စ'=>'စ','ဆ'=>'ဆ','ဇ'=>'ဇ','ဈ'=>'ဈ','ဉ'=>'ဉ','ည'=>'ည','ဋ'=>'ဋ','ဌ'=>'ဌ','ဍ'=>'ဍ','ဎ'=>'ဎ','ဏ'=>'ဏ','တ'=>'တ','ထ'=>'ထ','ဒ'=>'ဒ','ဓ'=>'ဓ','န'=>'န','ပ'=>'ပ','ဖ'=>'ဖ','ဗ'=>'ဗ','ဘ'=>'ဘ','မ'=>'မ','ယ'=>'ယ','ရ'=>'ရ','လ'=>'လ','ဝ'=>'ဝ','သ'=>'သ','ဟ'=>'ဟ','ဠ'=>'ဠ','အ'=>'အ','ဣ'=>'ဣ','ဤ'=>'ဤ','ဥ'=>'ဥ','ဦ'=>'ဦ','ဧ'=>'ဧ','ဩ'=>'ဩ','ဪ'=>'ဪ','ာ'=>'ာ','ိ'=>'ိ','ီ'=>'ီ','ု'=>'ု','ူ'=>'ူ','ေ'=>'ေ','ဲ'=>'ဲ','ံ'=>'ံ','့'=>'့','း'=>'း','္'=>'္','၀'=>'0','၁'=>'1','၂'=>'2','၃'=>'3','၄'=>'4','၅'=>'5','၆'=>'6','၇'=>'7','၈'=>'8','၉'=>'9','ၐ'=>'ၐ','ၑ'=>'ၑ','ၒ'=>'ၒ','ၓ'=>'ၓ','ၔ'=>'ၔ','ၕ'=>'ၕ','ၖ'=>'ၖ','ၗ'=>'ၗ','ၘ'=>'ၘ','ၙ'=>'ၙ','Ⴀ'=>'ⴀ','Ⴁ'=>'ⴁ','Ⴂ'=>'ⴂ','Ⴃ'=>'ⴃ','Ⴄ'=>'ⴄ','Ⴅ'=>'ⴅ','Ⴆ'=>'ⴆ','Ⴇ'=>'ⴇ','Ⴈ'=>'ⴈ','Ⴉ'=>'ⴉ','Ⴊ'=>'ⴊ','Ⴋ'=>'ⴋ','Ⴌ'=>'ⴌ','Ⴍ'=>'ⴍ','Ⴎ'=>'ⴎ','Ⴏ'=>'ⴏ','Ⴐ'=>'ⴐ','Ⴑ'=>'ⴑ','Ⴒ'=>'ⴒ','Ⴓ'=>'ⴓ','Ⴔ'=>'ⴔ','Ⴕ'=>'ⴕ','Ⴖ'=>'ⴖ','Ⴗ'=>'ⴗ','Ⴘ'=>'ⴘ','Ⴙ'=>'ⴙ','Ⴚ'=>'ⴚ','Ⴛ'=>'ⴛ','Ⴜ'=>'ⴜ','Ⴝ'=>'ⴝ','Ⴞ'=>'ⴞ','Ⴟ'=>'ⴟ','Ⴠ'=>'ⴠ','Ⴡ'=>'ⴡ','Ⴢ'=>'ⴢ','Ⴣ'=>'ⴣ','Ⴤ'=>'ⴤ','Ⴥ'=>'ⴥ','ა'=>'ა','ბ'=>'ბ','გ'=>'გ','დ'=>'დ','ე'=>'ე','ვ'=>'ვ','ზ'=>'ზ','თ'=>'თ','ი'=>'ი','კ'=>'კ','ლ'=>'ლ','მ'=>'მ','ნ'=>'ნ','ო'=>'ო','პ'=>'პ','ჟ'=>'ჟ','რ'=>'რ','ს'=>'ს','ტ'=>'ტ','უ'=>'უ','ფ'=>'ფ','ქ'=>'ქ','ღ'=>'ღ','ყ'=>'ყ','შ'=>'შ','ჩ'=>'ჩ','ც'=>'ც','ძ'=>'ძ','წ'=>'წ','ჭ'=>'ჭ','ხ'=>'ხ','ჯ'=>'ჯ','ჰ'=>'ჰ','ჱ'=>'ჱ','ჲ'=>'ჲ','ჳ'=>'ჳ','ჴ'=>'ჴ','ჵ'=>'ჵ','ჶ'=>'ჶ','ჷ'=>'ჷ','ჸ'=>'ჸ','ჹ'=>'ჹ','ჺ'=>'ჺ','ჼ'=>'ჼ','ᄀ'=>'ᄀ','ᄁ'=>'ᄁ','ᄂ'=>'ᄂ','ᄃ'=>'ᄃ','ᄄ'=>'ᄄ','ᄅ'=>'ᄅ','ᄆ'=>'ᄆ','ᄇ'=>'ᄇ','ᄈ'=>'ᄈ','ᄉ'=>'ᄉ','ᄊ'=>'ᄊ','ᄋ'=>'ᄋ','ᄌ'=>'ᄌ','ᄍ'=>'ᄍ','ᄎ'=>'ᄎ','ᄏ'=>'ᄏ','ᄐ'=>'ᄐ','ᄑ'=>'ᄑ','ᄒ'=>'ᄒ','ᄓ'=>'ᄓ','ᄔ'=>'ᄔ','ᄕ'=>'ᄕ','ᄖ'=>'ᄖ','ᄗ'=>'ᄗ','ᄘ'=>'ᄘ','ᄙ'=>'ᄙ','ᄚ'=>'ᄚ','ᄛ'=>'ᄛ','ᄜ'=>'ᄜ','ᄝ'=>'ᄝ','ᄞ'=>'ᄞ','ᄟ'=>'ᄟ','ᄠ'=>'ᄠ','ᄡ'=>'ᄡ','ᄢ'=>'ᄢ','ᄣ'=>'ᄣ','ᄤ'=>'ᄤ','ᄥ'=>'ᄥ','ᄦ'=>'ᄦ','ᄧ'=>'ᄧ','ᄨ'=>'ᄨ','ᄩ'=>'ᄩ','ᄪ'=>'ᄪ','ᄫ'=>'ᄫ','ᄬ'=>'ᄬ','ᄭ'=>'ᄭ','ᄮ'=>'ᄮ','ᄯ'=>'ᄯ','ᄰ'=>'ᄰ','ᄱ'=>'ᄱ','ᄲ'=>'ᄲ','ᄳ'=>'ᄳ','ᄴ'=>'ᄴ','ᄵ'=>'ᄵ','ᄶ'=>'ᄶ','ᄷ'=>'ᄷ','ᄸ'=>'ᄸ','ᄹ'=>'ᄹ','ᄺ'=>'ᄺ','ᄻ'=>'ᄻ','ᄼ'=>'ᄼ','ᄽ'=>'ᄽ','ᄾ'=>'ᄾ','ᄿ'=>'ᄿ','ᅀ'=>'ᅀ','ᅁ'=>'ᅁ','ᅂ'=>'ᅂ','ᅃ'=>'ᅃ','ᅄ'=>'ᅄ','ᅅ'=>'ᅅ','ᅆ'=>'ᅆ','ᅇ'=>'ᅇ','ᅈ'=>'ᅈ','ᅉ'=>'ᅉ','ᅊ'=>'ᅊ','ᅋ'=>'ᅋ','ᅌ'=>'ᅌ','ᅍ'=>'ᅍ','ᅎ'=>'ᅎ','ᅏ'=>'ᅏ','ᅐ'=>'ᅐ','ᅑ'=>'ᅑ','ᅒ'=>'ᅒ','ᅓ'=>'ᅓ','ᅔ'=>'ᅔ','ᅕ'=>'ᅕ','ᅖ'=>'ᅖ','ᅗ'=>'ᅗ','ᅘ'=>'ᅘ','ᅙ'=>'ᅙ','ᅟ'=>'ᅟ','ᅠ'=>'ᅠ','ᅡ'=>'ᅡ','ᅢ'=>'ᅢ','ᅣ'=>'ᅣ','ᅤ'=>'ᅤ','ᅥ'=>'ᅥ','ᅦ'=>'ᅦ','ᅧ'=>'ᅧ','ᅨ'=>'ᅨ','ᅩ'=>'ᅩ','ᅪ'=>'ᅪ','ᅫ'=>'ᅫ','ᅬ'=>'ᅬ','ᅭ'=>'ᅭ','ᅮ'=>'ᅮ','ᅯ'=>'ᅯ','ᅰ'=>'ᅰ','ᅱ'=>'ᅱ','ᅲ'=>'ᅲ','ᅳ'=>'ᅳ','ᅴ'=>'ᅴ','ᅵ'=>'ᅵ','ᅶ'=>'ᅶ','ᅷ'=>'ᅷ','ᅸ'=>'ᅸ','ᅹ'=>'ᅹ','ᅺ'=>'ᅺ','ᅻ'=>'ᅻ','ᅼ'=>'ᅼ','ᅽ'=>'ᅽ','ᅾ'=>'ᅾ','ᅿ'=>'ᅿ','ᆀ'=>'ᆀ','ᆁ'=>'ᆁ','ᆂ'=>'ᆂ','ᆃ'=>'ᆃ','ᆄ'=>'ᆄ','ᆅ'=>'ᆅ','ᆆ'=>'ᆆ','ᆇ'=>'ᆇ','ᆈ'=>'ᆈ','ᆉ'=>'ᆉ','ᆊ'=>'ᆊ','ᆋ'=>'ᆋ','ᆌ'=>'ᆌ','ᆍ'=>'ᆍ','ᆎ'=>'ᆎ','ᆏ'=>'ᆏ','ᆐ'=>'ᆐ','ᆑ'=>'ᆑ','ᆒ'=>'ᆒ','ᆓ'=>'ᆓ','ᆔ'=>'ᆔ','ᆕ'=>'ᆕ','ᆖ'=>'ᆖ','ᆗ'=>'ᆗ','ᆘ'=>'ᆘ','ᆙ'=>'ᆙ','ᆚ'=>'ᆚ','ᆛ'=>'ᆛ','ᆜ'=>'ᆜ','ᆝ'=>'ᆝ','ᆞ'=>'ᆞ','ᆟ'=>'ᆟ','ᆠ'=>'ᆠ','ᆡ'=>'ᆡ','ᆢ'=>'ᆢ','ᆨ'=>'ᆨ','ᆩ'=>'ᆩ','ᆪ'=>'ᆪ','ᆫ'=>'ᆫ','ᆬ'=>'ᆬ','ᆭ'=>'ᆭ','ᆮ'=>'ᆮ','ᆯ'=>'ᆯ','ᆰ'=>'ᆰ','ᆱ'=>'ᆱ','ᆲ'=>'ᆲ','ᆳ'=>'ᆳ','ᆴ'=>'ᆴ','ᆵ'=>'ᆵ','ᆶ'=>'ᆶ','ᆷ'=>'ᆷ','ᆸ'=>'ᆸ','ᆹ'=>'ᆹ','ᆺ'=>'ᆺ','ᆻ'=>'ᆻ','ᆼ'=>'ᆼ','ᆽ'=>'ᆽ','ᆾ'=>'ᆾ','ᆿ'=>'ᆿ','ᇀ'=>'ᇀ','ᇁ'=>'ᇁ','ᇂ'=>'ᇂ','ᇃ'=>'ᇃ','ᇄ'=>'ᇄ','ᇅ'=>'ᇅ','ᇆ'=>'ᇆ','ᇇ'=>'ᇇ','ᇈ'=>'ᇈ','ᇉ'=>'ᇉ','ᇊ'=>'ᇊ','ᇋ'=>'ᇋ','ᇌ'=>'ᇌ','ᇍ'=>'ᇍ','ᇎ'=>'ᇎ','ᇏ'=>'ᇏ','ᇐ'=>'ᇐ','ᇑ'=>'ᇑ','ᇒ'=>'ᇒ','ᇓ'=>'ᇓ','ᇔ'=>'ᇔ','ᇕ'=>'ᇕ','ᇖ'=>'ᇖ','ᇗ'=>'ᇗ','ᇘ'=>'ᇘ','ᇙ'=>'ᇙ','ᇚ'=>'ᇚ','ᇛ'=>'ᇛ','ᇜ'=>'ᇜ','ᇝ'=>'ᇝ','ᇞ'=>'ᇞ','ᇟ'=>'ᇟ','ᇠ'=>'ᇠ','ᇡ'=>'ᇡ','ᇢ'=>'ᇢ','ᇣ'=>'ᇣ','ᇤ'=>'ᇤ','ᇥ'=>'ᇥ','ᇦ'=>'ᇦ','ᇧ'=>'ᇧ','ᇨ'=>'ᇨ','ᇩ'=>'ᇩ','ᇪ'=>'ᇪ','ᇫ'=>'ᇫ','ᇬ'=>'ᇬ','ᇭ'=>'ᇭ','ᇮ'=>'ᇮ','ᇯ'=>'ᇯ','ᇰ'=>'ᇰ','ᇱ'=>'ᇱ','ᇲ'=>'ᇲ','ᇳ'=>'ᇳ','ᇴ'=>'ᇴ','ᇵ'=>'ᇵ','ᇶ'=>'ᇶ','ᇷ'=>'ᇷ','ᇸ'=>'ᇸ','ᇹ'=>'ᇹ','ሀ'=>'ሀ','ሁ'=>'ሁ','ሂ'=>'ሂ','ሃ'=>'ሃ','ሄ'=>'ሄ','ህ'=>'ህ','ሆ'=>'ሆ','ሇ'=>'ሇ','ለ'=>'ለ','ሉ'=>'ሉ','ሊ'=>'ሊ','ላ'=>'ላ','ሌ'=>'ሌ','ል'=>'ል','ሎ'=>'ሎ','ሏ'=>'ሏ','ሐ'=>'ሐ','ሑ'=>'ሑ','ሒ'=>'ሒ','ሓ'=>'ሓ','ሔ'=>'ሔ','ሕ'=>'ሕ','ሖ'=>'ሖ','ሗ'=>'ሗ','መ'=>'መ','ሙ'=>'ሙ','ሚ'=>'ሚ','ማ'=>'ማ','ሜ'=>'ሜ','ም'=>'ም','ሞ'=>'ሞ','ሟ'=>'ሟ','ሠ'=>'ሠ','ሡ'=>'ሡ','ሢ'=>'ሢ','ሣ'=>'ሣ','ሤ'=>'ሤ','ሥ'=>'ሥ','ሦ'=>'ሦ','ሧ'=>'ሧ','ረ'=>'ረ','ሩ'=>'ሩ','ሪ'=>'ሪ','ራ'=>'ራ','ሬ'=>'ሬ','ር'=>'ር','ሮ'=>'ሮ','ሯ'=>'ሯ','ሰ'=>'ሰ','ሱ'=>'ሱ','ሲ'=>'ሲ','ሳ'=>'ሳ','ሴ'=>'ሴ','ስ'=>'ስ','ሶ'=>'ሶ','ሷ'=>'ሷ','ሸ'=>'ሸ','ሹ'=>'ሹ','ሺ'=>'ሺ','ሻ'=>'ሻ','ሼ'=>'ሼ','ሽ'=>'ሽ','ሾ'=>'ሾ','ሿ'=>'ሿ','ቀ'=>'ቀ','ቁ'=>'ቁ','ቂ'=>'ቂ','ቃ'=>'ቃ','ቄ'=>'ቄ','ቅ'=>'ቅ','ቆ'=>'ቆ','ቇ'=>'ቇ','ቈ'=>'ቈ','ቊ'=>'ቊ','ቋ'=>'ቋ','ቌ'=>'ቌ','ቍ'=>'ቍ','ቐ'=>'ቐ','ቑ'=>'ቑ','ቒ'=>'ቒ','ቓ'=>'ቓ','ቔ'=>'ቔ','ቕ'=>'ቕ','ቖ'=>'ቖ','ቘ'=>'ቘ','ቚ'=>'ቚ','ቛ'=>'ቛ','ቜ'=>'ቜ','ቝ'=>'ቝ','በ'=>'በ','ቡ'=>'ቡ','ቢ'=>'ቢ','ባ'=>'ባ','ቤ'=>'ቤ','ብ'=>'ብ','ቦ'=>'ቦ','ቧ'=>'ቧ','ቨ'=>'ቨ','ቩ'=>'ቩ','ቪ'=>'ቪ','ቫ'=>'ቫ','ቬ'=>'ቬ','ቭ'=>'ቭ','ቮ'=>'ቮ','ቯ'=>'ቯ','ተ'=>'ተ','ቱ'=>'ቱ','ቲ'=>'ቲ','ታ'=>'ታ','ቴ'=>'ቴ','ት'=>'ት','ቶ'=>'ቶ','ቷ'=>'ቷ','ቸ'=>'ቸ','ቹ'=>'ቹ','ቺ'=>'ቺ','ቻ'=>'ቻ','ቼ'=>'ቼ','ች'=>'ች','ቾ'=>'ቾ','ቿ'=>'ቿ','ኀ'=>'ኀ','ኁ'=>'ኁ','ኂ'=>'ኂ','ኃ'=>'ኃ','ኄ'=>'ኄ','ኅ'=>'ኅ','ኆ'=>'ኆ','ኇ'=>'ኇ','ኈ'=>'ኈ','ኊ'=>'ኊ','ኋ'=>'ኋ','ኌ'=>'ኌ','ኍ'=>'ኍ','ነ'=>'ነ','ኑ'=>'ኑ','ኒ'=>'ኒ','ና'=>'ና','ኔ'=>'ኔ','ን'=>'ን','ኖ'=>'ኖ','ኗ'=>'ኗ','ኘ'=>'ኘ','ኙ'=>'ኙ','ኚ'=>'ኚ','ኛ'=>'ኛ','ኜ'=>'ኜ','ኝ'=>'ኝ','ኞ'=>'ኞ','ኟ'=>'ኟ','አ'=>'አ','ኡ'=>'ኡ','ኢ'=>'ኢ','ኣ'=>'ኣ','ኤ'=>'ኤ','እ'=>'እ','ኦ'=>'ኦ','ኧ'=>'ኧ','ከ'=>'ከ','ኩ'=>'ኩ','ኪ'=>'ኪ','ካ'=>'ካ','ኬ'=>'ኬ','ክ'=>'ክ','ኮ'=>'ኮ','ኯ'=>'ኯ','ኰ'=>'ኰ','ኲ'=>'ኲ','ኳ'=>'ኳ','ኴ'=>'ኴ','ኵ'=>'ኵ','ኸ'=>'ኸ','ኹ'=>'ኹ','ኺ'=>'ኺ','ኻ'=>'ኻ','ኼ'=>'ኼ','ኽ'=>'ኽ','ኾ'=>'ኾ','ዀ'=>'ዀ','ዂ'=>'ዂ','ዃ'=>'ዃ','ዄ'=>'ዄ','ዅ'=>'ዅ','ወ'=>'ወ','ዉ'=>'ዉ','ዊ'=>'ዊ','ዋ'=>'ዋ','ዌ'=>'ዌ','ው'=>'ው','ዎ'=>'ዎ','ዏ'=>'ዏ','ዐ'=>'ዐ','ዑ'=>'ዑ','ዒ'=>'ዒ','ዓ'=>'ዓ','ዔ'=>'ዔ','ዕ'=>'ዕ','ዖ'=>'ዖ','ዘ'=>'ዘ','ዙ'=>'ዙ','ዚ'=>'ዚ','ዛ'=>'ዛ','ዜ'=>'ዜ','ዝ'=>'ዝ','ዞ'=>'ዞ','ዟ'=>'ዟ','ዠ'=>'ዠ','ዡ'=>'ዡ','ዢ'=>'ዢ','ዣ'=>'ዣ','ዤ'=>'ዤ','ዥ'=>'ዥ','ዦ'=>'ዦ','ዧ'=>'ዧ','የ'=>'የ','ዩ'=>'ዩ','ዪ'=>'ዪ','ያ'=>'ያ','ዬ'=>'ዬ','ይ'=>'ይ','ዮ'=>'ዮ','ዯ'=>'ዯ','ደ'=>'ደ','ዱ'=>'ዱ','ዲ'=>'ዲ','ዳ'=>'ዳ','ዴ'=>'ዴ','ድ'=>'ድ','ዶ'=>'ዶ','ዷ'=>'ዷ','ዸ'=>'ዸ','ዹ'=>'ዹ','ዺ'=>'ዺ','ዻ'=>'ዻ','ዼ'=>'ዼ','ዽ'=>'ዽ','ዾ'=>'ዾ','ዿ'=>'ዿ','ጀ'=>'ጀ','ጁ'=>'ጁ','ጂ'=>'ጂ','ጃ'=>'ጃ','ጄ'=>'ጄ','ጅ'=>'ጅ','ጆ'=>'ጆ','ጇ'=>'ጇ','ገ'=>'ገ','ጉ'=>'ጉ','ጊ'=>'ጊ','ጋ'=>'ጋ','ጌ'=>'ጌ','ግ'=>'ግ','ጎ'=>'ጎ','ጏ'=>'ጏ','ጐ'=>'ጐ','ጒ'=>'ጒ','ጓ'=>'ጓ','ጔ'=>'ጔ','ጕ'=>'ጕ','ጘ'=>'ጘ','ጙ'=>'ጙ','ጚ'=>'ጚ','ጛ'=>'ጛ','ጜ'=>'ጜ','ጝ'=>'ጝ','ጞ'=>'ጞ','ጟ'=>'ጟ','ጠ'=>'ጠ','ጡ'=>'ጡ','ጢ'=>'ጢ','ጣ'=>'ጣ','ጤ'=>'ጤ','ጥ'=>'ጥ','ጦ'=>'ጦ','ጧ'=>'ጧ','ጨ'=>'ጨ','ጩ'=>'ጩ','ጪ'=>'ጪ','ጫ'=>'ጫ','ጬ'=>'ጬ','ጭ'=>'ጭ','ጮ'=>'ጮ','ጯ'=>'ጯ','ጰ'=>'ጰ','ጱ'=>'ጱ','ጲ'=>'ጲ','ጳ'=>'ጳ','ጴ'=>'ጴ','ጵ'=>'ጵ','ጶ'=>'ጶ','ጷ'=>'ጷ','ጸ'=>'ጸ','ጹ'=>'ጹ','ጺ'=>'ጺ','ጻ'=>'ጻ','ጼ'=>'ጼ','ጽ'=>'ጽ','ጾ'=>'ጾ','ጿ'=>'ጿ','ፀ'=>'ፀ','ፁ'=>'ፁ','ፂ'=>'ፂ','ፃ'=>'ፃ','ፄ'=>'ፄ','ፅ'=>'ፅ','ፆ'=>'ፆ','ፇ'=>'ፇ','ፈ'=>'ፈ','ፉ'=>'ፉ','ፊ'=>'ፊ','ፋ'=>'ፋ','ፌ'=>'ፌ','ፍ'=>'ፍ','ፎ'=>'ፎ','ፏ'=>'ፏ','ፐ'=>'ፐ','ፑ'=>'ፑ','ፒ'=>'ፒ','ፓ'=>'ፓ','ፔ'=>'ፔ','ፕ'=>'ፕ','ፖ'=>'ፖ','ፗ'=>'ፗ','ፘ'=>'ፘ','ፙ'=>'ፙ','ፚ'=>'ፚ','፟'=>'፟','፩'=>'1','፪'=>'2','፫'=>'3','፬'=>'4','፭'=>'5','፮'=>'6','፯'=>'7','፰'=>'8','፱'=>'9','፲'=>'10','፳'=>'20','፴'=>'30','፵'=>'40','፶'=>'50','፷'=>'60','፸'=>'70','፹'=>'80','፺'=>'90','፻'=>'100','፼'=>'10000','ᎀ'=>'ᎀ','ᎁ'=>'ᎁ','ᎂ'=>'ᎂ','ᎃ'=>'ᎃ','ᎄ'=>'ᎄ','ᎅ'=>'ᎅ','ᎆ'=>'ᎆ','ᎇ'=>'ᎇ','ᎈ'=>'ᎈ','ᎉ'=>'ᎉ','ᎊ'=>'ᎊ','ᎋ'=>'ᎋ','ᎌ'=>'ᎌ','ᎍ'=>'ᎍ','ᎎ'=>'ᎎ','ᎏ'=>'ᎏ','Ꭰ'=>'Ꭰ','Ꭱ'=>'Ꭱ','Ꭲ'=>'Ꭲ','Ꭳ'=>'Ꭳ','Ꭴ'=>'Ꭴ','Ꭵ'=>'Ꭵ','Ꭶ'=>'Ꭶ','Ꭷ'=>'Ꭷ','Ꭸ'=>'Ꭸ','Ꭹ'=>'Ꭹ','Ꭺ'=>'Ꭺ','Ꭻ'=>'Ꭻ','Ꭼ'=>'Ꭼ','Ꭽ'=>'Ꭽ','Ꭾ'=>'Ꭾ','Ꭿ'=>'Ꭿ','Ꮀ'=>'Ꮀ','Ꮁ'=>'Ꮁ','Ꮂ'=>'Ꮂ','Ꮃ'=>'Ꮃ','Ꮄ'=>'Ꮄ','Ꮅ'=>'Ꮅ','Ꮆ'=>'Ꮆ','Ꮇ'=>'Ꮇ','Ꮈ'=>'Ꮈ','Ꮉ'=>'Ꮉ','Ꮊ'=>'Ꮊ','Ꮋ'=>'Ꮋ','Ꮌ'=>'Ꮌ','Ꮍ'=>'Ꮍ','Ꮎ'=>'Ꮎ','Ꮏ'=>'Ꮏ','Ꮐ'=>'Ꮐ','Ꮑ'=>'Ꮑ','Ꮒ'=>'Ꮒ','Ꮓ'=>'Ꮓ','Ꮔ'=>'Ꮔ','Ꮕ'=>'Ꮕ','Ꮖ'=>'Ꮖ','Ꮗ'=>'Ꮗ','Ꮘ'=>'Ꮘ','Ꮙ'=>'Ꮙ','Ꮚ'=>'Ꮚ','Ꮛ'=>'Ꮛ','Ꮜ'=>'Ꮜ','Ꮝ'=>'Ꮝ','Ꮞ'=>'Ꮞ','Ꮟ'=>'Ꮟ','Ꮠ'=>'Ꮠ','Ꮡ'=>'Ꮡ','Ꮢ'=>'Ꮢ','Ꮣ'=>'Ꮣ','Ꮤ'=>'Ꮤ','Ꮥ'=>'Ꮥ','Ꮦ'=>'Ꮦ','Ꮧ'=>'Ꮧ','Ꮨ'=>'Ꮨ','Ꮩ'=>'Ꮩ','Ꮪ'=>'Ꮪ','Ꮫ'=>'Ꮫ','Ꮬ'=>'Ꮬ','Ꮭ'=>'Ꮭ','Ꮮ'=>'Ꮮ','Ꮯ'=>'Ꮯ','Ꮰ'=>'Ꮰ','Ꮱ'=>'Ꮱ','Ꮲ'=>'Ꮲ','Ꮳ'=>'Ꮳ','Ꮴ'=>'Ꮴ','Ꮵ'=>'Ꮵ','Ꮶ'=>'Ꮶ','Ꮷ'=>'Ꮷ','Ꮸ'=>'Ꮸ','Ꮹ'=>'Ꮹ','Ꮺ'=>'Ꮺ','Ꮻ'=>'Ꮻ','Ꮼ'=>'Ꮼ','Ꮽ'=>'Ꮽ','Ꮾ'=>'Ꮾ','Ꮿ'=>'Ꮿ','Ᏸ'=>'Ᏸ','Ᏹ'=>'Ᏹ','Ᏺ'=>'Ᏺ','Ᏻ'=>'Ᏻ','Ᏼ'=>'Ᏼ','ᐁ'=>'ᐁ','ᐂ'=>'ᐂ','ᐃ'=>'ᐃ','ᐄ'=>'ᐄ','ᐅ'=>'ᐅ','ᐆ'=>'ᐆ','ᐇ'=>'ᐇ','ᐈ'=>'ᐈ','ᐉ'=>'ᐉ','ᐊ'=>'ᐊ','ᐋ'=>'ᐋ','ᐌ'=>'ᐌ','ᐍ'=>'ᐍ','ᐎ'=>'ᐎ','ᐏ'=>'ᐏ','ᐐ'=>'ᐐ','ᐑ'=>'ᐑ','ᐒ'=>'ᐒ','ᐓ'=>'ᐓ','ᐔ'=>'ᐔ','ᐕ'=>'ᐕ','ᐖ'=>'ᐖ','ᐗ'=>'ᐗ','ᐘ'=>'ᐘ','ᐙ'=>'ᐙ','ᐚ'=>'ᐚ','ᐛ'=>'ᐛ','ᐜ'=>'ᐜ','ᐝ'=>'ᐝ','ᐞ'=>'ᐞ','ᐟ'=>'ᐟ','ᐠ'=>'ᐠ','ᐡ'=>'ᐡ','ᐢ'=>'ᐢ','ᐣ'=>'ᐣ','ᐤ'=>'ᐤ','ᐥ'=>'ᐥ','ᐦ'=>'ᐦ','ᐧ'=>'ᐧ','ᐨ'=>'ᐨ','ᐩ'=>'ᐩ','ᐪ'=>'ᐪ','ᐫ'=>'ᐫ','ᐬ'=>'ᐬ','ᐭ'=>'ᐭ','ᐮ'=>'ᐮ','ᐯ'=>'ᐯ','ᐰ'=>'ᐰ','ᐱ'=>'ᐱ','ᐲ'=>'ᐲ','ᐳ'=>'ᐳ','ᐴ'=>'ᐴ','ᐵ'=>'ᐵ','ᐶ'=>'ᐶ','ᐷ'=>'ᐷ','ᐸ'=>'ᐸ','ᐹ'=>'ᐹ','ᐺ'=>'ᐺ','ᐻ'=>'ᐻ','ᐼ'=>'ᐼ','ᐽ'=>'ᐽ','ᐾ'=>'ᐾ','ᐿ'=>'ᐿ','ᑀ'=>'ᑀ','ᑁ'=>'ᑁ','ᑂ'=>'ᑂ','ᑃ'=>'ᑃ','ᑄ'=>'ᑄ','ᑅ'=>'ᑅ','ᑆ'=>'ᑆ','ᑇ'=>'ᑇ','ᑈ'=>'ᑈ','ᑉ'=>'ᑉ','ᑊ'=>'ᑊ','ᑋ'=>'ᑋ','ᑌ'=>'ᑌ','ᑍ'=>'ᑍ','ᑎ'=>'ᑎ','ᑏ'=>'ᑏ','ᑐ'=>'ᑐ','ᑑ'=>'ᑑ','ᑒ'=>'ᑒ','ᑓ'=>'ᑓ','ᑔ'=>'ᑔ','ᑕ'=>'ᑕ','ᑖ'=>'ᑖ','ᑗ'=>'ᑗ','ᑘ'=>'ᑘ','ᑙ'=>'ᑙ','ᑚ'=>'ᑚ','ᑛ'=>'ᑛ','ᑜ'=>'ᑜ','ᑝ'=>'ᑝ','ᑞ'=>'ᑞ','ᑟ'=>'ᑟ','ᑠ'=>'ᑠ','ᑡ'=>'ᑡ','ᑢ'=>'ᑢ','ᑣ'=>'ᑣ','ᑤ'=>'ᑤ','ᑥ'=>'ᑥ','ᑦ'=>'ᑦ','ᑧ'=>'ᑧ','ᑨ'=>'ᑨ','ᑩ'=>'ᑩ','ᑪ'=>'ᑪ','ᑫ'=>'ᑫ','ᑬ'=>'ᑬ','ᑭ'=>'ᑭ','ᑮ'=>'ᑮ','ᑯ'=>'ᑯ','ᑰ'=>'ᑰ','ᑱ'=>'ᑱ','ᑲ'=>'ᑲ','ᑳ'=>'ᑳ','ᑴ'=>'ᑴ','ᑵ'=>'ᑵ','ᑶ'=>'ᑶ','ᑷ'=>'ᑷ','ᑸ'=>'ᑸ','ᑹ'=>'ᑹ','ᑺ'=>'ᑺ','ᑻ'=>'ᑻ','ᑼ'=>'ᑼ','ᑽ'=>'ᑽ','ᑾ'=>'ᑾ','ᑿ'=>'ᑿ','ᒀ'=>'ᒀ','ᒁ'=>'ᒁ','ᒂ'=>'ᒂ','ᒃ'=>'ᒃ','ᒄ'=>'ᒄ','ᒅ'=>'ᒅ','ᒆ'=>'ᒆ','ᒇ'=>'ᒇ','ᒈ'=>'ᒈ','ᒉ'=>'ᒉ','ᒊ'=>'ᒊ','ᒋ'=>'ᒋ','ᒌ'=>'ᒌ','ᒍ'=>'ᒍ','ᒎ'=>'ᒎ','ᒏ'=>'ᒏ','ᒐ'=>'ᒐ','ᒑ'=>'ᒑ','ᒒ'=>'ᒒ','ᒓ'=>'ᒓ','ᒔ'=>'ᒔ','ᒕ'=>'ᒕ','ᒖ'=>'ᒖ','ᒗ'=>'ᒗ','ᒘ'=>'ᒘ','ᒙ'=>'ᒙ','ᒚ'=>'ᒚ','ᒛ'=>'ᒛ','ᒜ'=>'ᒜ','ᒝ'=>'ᒝ','ᒞ'=>'ᒞ','ᒟ'=>'ᒟ','ᒠ'=>'ᒠ','ᒡ'=>'ᒡ','ᒢ'=>'ᒢ','ᒣ'=>'ᒣ','ᒤ'=>'ᒤ','ᒥ'=>'ᒥ','ᒦ'=>'ᒦ','ᒧ'=>'ᒧ','ᒨ'=>'ᒨ','ᒩ'=>'ᒩ','ᒪ'=>'ᒪ','ᒫ'=>'ᒫ','ᒬ'=>'ᒬ','ᒭ'=>'ᒭ','ᒮ'=>'ᒮ','ᒯ'=>'ᒯ','ᒰ'=>'ᒰ','ᒱ'=>'ᒱ','ᒲ'=>'ᒲ','ᒳ'=>'ᒳ','ᒴ'=>'ᒴ','ᒵ'=>'ᒵ','ᒶ'=>'ᒶ','ᒷ'=>'ᒷ','ᒸ'=>'ᒸ','ᒹ'=>'ᒹ','ᒺ'=>'ᒺ','ᒻ'=>'ᒻ','ᒼ'=>'ᒼ','ᒽ'=>'ᒽ','ᒾ'=>'ᒾ','ᒿ'=>'ᒿ','ᓀ'=>'ᓀ','ᓁ'=>'ᓁ','ᓂ'=>'ᓂ','ᓃ'=>'ᓃ','ᓄ'=>'ᓄ','ᓅ'=>'ᓅ','ᓆ'=>'ᓆ','ᓇ'=>'ᓇ','ᓈ'=>'ᓈ','ᓉ'=>'ᓉ','ᓊ'=>'ᓊ','ᓋ'=>'ᓋ','ᓌ'=>'ᓌ','ᓍ'=>'ᓍ','ᓎ'=>'ᓎ','ᓏ'=>'ᓏ','ᓐ'=>'ᓐ','ᓑ'=>'ᓑ','ᓒ'=>'ᓒ','ᓓ'=>'ᓓ','ᓔ'=>'ᓔ','ᓕ'=>'ᓕ','ᓖ'=>'ᓖ','ᓗ'=>'ᓗ','ᓘ'=>'ᓘ','ᓙ'=>'ᓙ','ᓚ'=>'ᓚ','ᓛ'=>'ᓛ','ᓜ'=>'ᓜ','ᓝ'=>'ᓝ','ᓞ'=>'ᓞ','ᓟ'=>'ᓟ','ᓠ'=>'ᓠ','ᓡ'=>'ᓡ','ᓢ'=>'ᓢ','ᓣ'=>'ᓣ','ᓤ'=>'ᓤ','ᓥ'=>'ᓥ','ᓦ'=>'ᓦ','ᓧ'=>'ᓧ','ᓨ'=>'ᓨ','ᓩ'=>'ᓩ','ᓪ'=>'ᓪ','ᓫ'=>'ᓫ','ᓬ'=>'ᓬ','ᓭ'=>'ᓭ','ᓮ'=>'ᓮ','ᓯ'=>'ᓯ','ᓰ'=>'ᓰ','ᓱ'=>'ᓱ','ᓲ'=>'ᓲ','ᓳ'=>'ᓳ','ᓴ'=>'ᓴ','ᓵ'=>'ᓵ','ᓶ'=>'ᓶ','ᓷ'=>'ᓷ','ᓸ'=>'ᓸ','ᓹ'=>'ᓹ','ᓺ'=>'ᓺ','ᓻ'=>'ᓻ','ᓼ'=>'ᓼ','ᓽ'=>'ᓽ','ᓾ'=>'ᓾ','ᓿ'=>'ᓿ','ᔀ'=>'ᔀ','ᔁ'=>'ᔁ','ᔂ'=>'ᔂ','ᔃ'=>'ᔃ','ᔄ'=>'ᔄ','ᔅ'=>'ᔅ','ᔆ'=>'ᔆ','ᔇ'=>'ᔇ','ᔈ'=>'ᔈ','ᔉ'=>'ᔉ','ᔊ'=>'ᔊ','ᔋ'=>'ᔋ','ᔌ'=>'ᔌ','ᔍ'=>'ᔍ','ᔎ'=>'ᔎ','ᔏ'=>'ᔏ','ᔐ'=>'ᔐ','ᔑ'=>'ᔑ','ᔒ'=>'ᔒ','ᔓ'=>'ᔓ','ᔔ'=>'ᔔ','ᔕ'=>'ᔕ','ᔖ'=>'ᔖ','ᔗ'=>'ᔗ','ᔘ'=>'ᔘ','ᔙ'=>'ᔙ','ᔚ'=>'ᔚ','ᔛ'=>'ᔛ','ᔜ'=>'ᔜ','ᔝ'=>'ᔝ','ᔞ'=>'ᔞ','ᔟ'=>'ᔟ','ᔠ'=>'ᔠ','ᔡ'=>'ᔡ','ᔢ'=>'ᔢ','ᔣ'=>'ᔣ','ᔤ'=>'ᔤ','ᔥ'=>'ᔥ','ᔦ'=>'ᔦ','ᔧ'=>'ᔧ','ᔨ'=>'ᔨ','ᔩ'=>'ᔩ','ᔪ'=>'ᔪ','ᔫ'=>'ᔫ','ᔬ'=>'ᔬ','ᔭ'=>'ᔭ','ᔮ'=>'ᔮ','ᔯ'=>'ᔯ','ᔰ'=>'ᔰ','ᔱ'=>'ᔱ','ᔲ'=>'ᔲ','ᔳ'=>'ᔳ','ᔴ'=>'ᔴ','ᔵ'=>'ᔵ','ᔶ'=>'ᔶ','ᔷ'=>'ᔷ','ᔸ'=>'ᔸ','ᔹ'=>'ᔹ','ᔺ'=>'ᔺ','ᔻ'=>'ᔻ','ᔼ'=>'ᔼ','ᔽ'=>'ᔽ','ᔾ'=>'ᔾ','ᔿ'=>'ᔿ','ᕀ'=>'ᕀ','ᕁ'=>'ᕁ','ᕂ'=>'ᕂ','ᕃ'=>'ᕃ','ᕄ'=>'ᕄ','ᕅ'=>'ᕅ','ᕆ'=>'ᕆ','ᕇ'=>'ᕇ','ᕈ'=>'ᕈ','ᕉ'=>'ᕉ','ᕊ'=>'ᕊ','ᕋ'=>'ᕋ','ᕌ'=>'ᕌ','ᕍ'=>'ᕍ','ᕎ'=>'ᕎ','ᕏ'=>'ᕏ','ᕐ'=>'ᕐ','ᕑ'=>'ᕑ','ᕒ'=>'ᕒ','ᕓ'=>'ᕓ','ᕔ'=>'ᕔ','ᕕ'=>'ᕕ','ᕖ'=>'ᕖ','ᕗ'=>'ᕗ','ᕘ'=>'ᕘ','ᕙ'=>'ᕙ','ᕚ'=>'ᕚ','ᕛ'=>'ᕛ','ᕜ'=>'ᕜ','ᕝ'=>'ᕝ','ᕞ'=>'ᕞ','ᕟ'=>'ᕟ','ᕠ'=>'ᕠ','ᕡ'=>'ᕡ','ᕢ'=>'ᕢ','ᕣ'=>'ᕣ','ᕤ'=>'ᕤ','ᕥ'=>'ᕥ','ᕦ'=>'ᕦ','ᕧ'=>'ᕧ','ᕨ'=>'ᕨ','ᕩ'=>'ᕩ','ᕪ'=>'ᕪ','ᕫ'=>'ᕫ','ᕬ'=>'ᕬ','ᕭ'=>'ᕭ','ᕮ'=>'ᕮ','ᕯ'=>'ᕯ','ᕰ'=>'ᕰ','ᕱ'=>'ᕱ','ᕲ'=>'ᕲ','ᕳ'=>'ᕳ','ᕴ'=>'ᕴ','ᕵ'=>'ᕵ','ᕶ'=>'ᕶ','ᕷ'=>'ᕷ','ᕸ'=>'ᕸ','ᕹ'=>'ᕹ','ᕺ'=>'ᕺ','ᕻ'=>'ᕻ','ᕼ'=>'ᕼ','ᕽ'=>'ᕽ','ᕾ'=>'ᕾ','ᕿ'=>'ᕿ','ᖀ'=>'ᖀ','ᖁ'=>'ᖁ','ᖂ'=>'ᖂ','ᖃ'=>'ᖃ','ᖄ'=>'ᖄ','ᖅ'=>'ᖅ','ᖆ'=>'ᖆ','ᖇ'=>'ᖇ','ᖈ'=>'ᖈ','ᖉ'=>'ᖉ','ᖊ'=>'ᖊ','ᖋ'=>'ᖋ','ᖌ'=>'ᖌ','ᖍ'=>'ᖍ','ᖎ'=>'ᖎ','ᖏ'=>'ᖏ','ᖐ'=>'ᖐ','ᖑ'=>'ᖑ','ᖒ'=>'ᖒ','ᖓ'=>'ᖓ','ᖔ'=>'ᖔ','ᖕ'=>'ᖕ','ᖖ'=>'ᖖ','ᖗ'=>'ᖗ','ᖘ'=>'ᖘ','ᖙ'=>'ᖙ','ᖚ'=>'ᖚ','ᖛ'=>'ᖛ','ᖜ'=>'ᖜ','ᖝ'=>'ᖝ','ᖞ'=>'ᖞ','ᖟ'=>'ᖟ','ᖠ'=>'ᖠ','ᖡ'=>'ᖡ','ᖢ'=>'ᖢ','ᖣ'=>'ᖣ','ᖤ'=>'ᖤ','ᖥ'=>'ᖥ','ᖦ'=>'ᖦ','ᖧ'=>'ᖧ','ᖨ'=>'ᖨ','ᖩ'=>'ᖩ','ᖪ'=>'ᖪ','ᖫ'=>'ᖫ','ᖬ'=>'ᖬ','ᖭ'=>'ᖭ','ᖮ'=>'ᖮ','ᖯ'=>'ᖯ','ᖰ'=>'ᖰ','ᖱ'=>'ᖱ','ᖲ'=>'ᖲ','ᖳ'=>'ᖳ','ᖴ'=>'ᖴ','ᖵ'=>'ᖵ','ᖶ'=>'ᖶ','ᖷ'=>'ᖷ','ᖸ'=>'ᖸ','ᖹ'=>'ᖹ','ᖺ'=>'ᖺ','ᖻ'=>'ᖻ','ᖼ'=>'ᖼ','ᖽ'=>'ᖽ','ᖾ'=>'ᖾ','ᖿ'=>'ᖿ','ᗀ'=>'ᗀ','ᗁ'=>'ᗁ','ᗂ'=>'ᗂ','ᗃ'=>'ᗃ','ᗄ'=>'ᗄ','ᗅ'=>'ᗅ','ᗆ'=>'ᗆ','ᗇ'=>'ᗇ','ᗈ'=>'ᗈ','ᗉ'=>'ᗉ','ᗊ'=>'ᗊ','ᗋ'=>'ᗋ','ᗌ'=>'ᗌ','ᗍ'=>'ᗍ','ᗎ'=>'ᗎ','ᗏ'=>'ᗏ','ᗐ'=>'ᗐ','ᗑ'=>'ᗑ','ᗒ'=>'ᗒ','ᗓ'=>'ᗓ','ᗔ'=>'ᗔ','ᗕ'=>'ᗕ','ᗖ'=>'ᗖ','ᗗ'=>'ᗗ','ᗘ'=>'ᗘ','ᗙ'=>'ᗙ','ᗚ'=>'ᗚ','ᗛ'=>'ᗛ','ᗜ'=>'ᗜ','ᗝ'=>'ᗝ','ᗞ'=>'ᗞ','ᗟ'=>'ᗟ','ᗠ'=>'ᗠ','ᗡ'=>'ᗡ','ᗢ'=>'ᗢ','ᗣ'=>'ᗣ','ᗤ'=>'ᗤ','ᗥ'=>'ᗥ','ᗦ'=>'ᗦ','ᗧ'=>'ᗧ','ᗨ'=>'ᗨ','ᗩ'=>'ᗩ','ᗪ'=>'ᗪ','ᗫ'=>'ᗫ','ᗬ'=>'ᗬ','ᗭ'=>'ᗭ','ᗮ'=>'ᗮ','ᗯ'=>'ᗯ','ᗰ'=>'ᗰ','ᗱ'=>'ᗱ','ᗲ'=>'ᗲ','ᗳ'=>'ᗳ','ᗴ'=>'ᗴ','ᗵ'=>'ᗵ','ᗶ'=>'ᗶ','ᗷ'=>'ᗷ','ᗸ'=>'ᗸ','ᗹ'=>'ᗹ','ᗺ'=>'ᗺ','ᗻ'=>'ᗻ','ᗼ'=>'ᗼ','ᗽ'=>'ᗽ','ᗾ'=>'ᗾ','ᗿ'=>'ᗿ','ᘀ'=>'ᘀ','ᘁ'=>'ᘁ','ᘂ'=>'ᘂ','ᘃ'=>'ᘃ','ᘄ'=>'ᘄ','ᘅ'=>'ᘅ','ᘆ'=>'ᘆ','ᘇ'=>'ᘇ','ᘈ'=>'ᘈ','ᘉ'=>'ᘉ','ᘊ'=>'ᘊ','ᘋ'=>'ᘋ','ᘌ'=>'ᘌ','ᘍ'=>'ᘍ','ᘎ'=>'ᘎ','ᘏ'=>'ᘏ','ᘐ'=>'ᘐ','ᘑ'=>'ᘑ','ᘒ'=>'ᘒ','ᘓ'=>'ᘓ','ᘔ'=>'ᘔ','ᘕ'=>'ᘕ','ᘖ'=>'ᘖ','ᘗ'=>'ᘗ','ᘘ'=>'ᘘ','ᘙ'=>'ᘙ','ᘚ'=>'ᘚ','ᘛ'=>'ᘛ','ᘜ'=>'ᘜ','ᘝ'=>'ᘝ','ᘞ'=>'ᘞ','ᘟ'=>'ᘟ','ᘠ'=>'ᘠ','ᘡ'=>'ᘡ','ᘢ'=>'ᘢ','ᘣ'=>'ᘣ','ᘤ'=>'ᘤ','ᘥ'=>'ᘥ','ᘦ'=>'ᘦ','ᘧ'=>'ᘧ','ᘨ'=>'ᘨ','ᘩ'=>'ᘩ','ᘪ'=>'ᘪ','ᘫ'=>'ᘫ','ᘬ'=>'ᘬ','ᘭ'=>'ᘭ','ᘮ'=>'ᘮ','ᘯ'=>'ᘯ','ᘰ'=>'ᘰ','ᘱ'=>'ᘱ','ᘲ'=>'ᘲ','ᘳ'=>'ᘳ','ᘴ'=>'ᘴ','ᘵ'=>'ᘵ','ᘶ'=>'ᘶ','ᘷ'=>'ᘷ','ᘸ'=>'ᘸ','ᘹ'=>'ᘹ','ᘺ'=>'ᘺ','ᘻ'=>'ᘻ','ᘼ'=>'ᘼ','ᘽ'=>'ᘽ','ᘾ'=>'ᘾ','ᘿ'=>'ᘿ','ᙀ'=>'ᙀ','ᙁ'=>'ᙁ','ᙂ'=>'ᙂ','ᙃ'=>'ᙃ','ᙄ'=>'ᙄ','ᙅ'=>'ᙅ','ᙆ'=>'ᙆ','ᙇ'=>'ᙇ','ᙈ'=>'ᙈ','ᙉ'=>'ᙉ','ᙊ'=>'ᙊ','ᙋ'=>'ᙋ','ᙌ'=>'ᙌ','ᙍ'=>'ᙍ','ᙎ'=>'ᙎ','ᙏ'=>'ᙏ','ᙐ'=>'ᙐ','ᙑ'=>'ᙑ','ᙒ'=>'ᙒ','ᙓ'=>'ᙓ','ᙔ'=>'ᙔ','ᙕ'=>'ᙕ','ᙖ'=>'ᙖ','ᙗ'=>'ᙗ','ᙘ'=>'ᙘ','ᙙ'=>'ᙙ','ᙚ'=>'ᙚ','ᙛ'=>'ᙛ','ᙜ'=>'ᙜ','ᙝ'=>'ᙝ','ᙞ'=>'ᙞ','ᙟ'=>'ᙟ','ᙠ'=>'ᙠ','ᙡ'=>'ᙡ','ᙢ'=>'ᙢ','ᙣ'=>'ᙣ','ᙤ'=>'ᙤ','ᙥ'=>'ᙥ','ᙦ'=>'ᙦ','ᙧ'=>'ᙧ','ᙨ'=>'ᙨ','ᙩ'=>'ᙩ','ᙪ'=>'ᙪ','ᙫ'=>'ᙫ','ᙬ'=>'ᙬ','ᙯ'=>'ᙯ','ᙰ'=>'ᙰ','ᙱ'=>'ᙱ','ᙲ'=>'ᙲ','ᙳ'=>'ᙳ','ᙴ'=>'ᙴ','ᙵ'=>'ᙵ','ᙶ'=>'ᙶ','ᚁ'=>'ᚁ','ᚂ'=>'ᚂ','ᚃ'=>'ᚃ','ᚄ'=>'ᚄ','ᚅ'=>'ᚅ','ᚆ'=>'ᚆ','ᚇ'=>'ᚇ','ᚈ'=>'ᚈ','ᚉ'=>'ᚉ','ᚊ'=>'ᚊ','ᚋ'=>'ᚋ','ᚌ'=>'ᚌ','ᚍ'=>'ᚍ','ᚎ'=>'ᚎ','ᚏ'=>'ᚏ','ᚐ'=>'ᚐ','ᚑ'=>'ᚑ','ᚒ'=>'ᚒ','ᚓ'=>'ᚓ','ᚔ'=>'ᚔ','ᚕ'=>'ᚕ','ᚖ'=>'ᚖ','ᚗ'=>'ᚗ','ᚘ'=>'ᚘ','ᚙ'=>'ᚙ','ᚚ'=>'ᚚ','ᚠ'=>'ᚠ','ᚡ'=>'ᚡ','ᚢ'=>'ᚢ','ᚣ'=>'ᚣ','ᚤ'=>'ᚤ','ᚥ'=>'ᚥ','ᚦ'=>'ᚦ','ᚧ'=>'ᚧ','ᚨ'=>'ᚨ','ᚩ'=>'ᚩ','ᚪ'=>'ᚪ','ᚫ'=>'ᚫ','ᚬ'=>'ᚬ','ᚭ'=>'ᚭ','ᚮ'=>'ᚮ','ᚯ'=>'ᚯ','ᚰ'=>'ᚰ','ᚱ'=>'ᚱ','ᚲ'=>'ᚲ','ᚳ'=>'ᚳ','ᚴ'=>'ᚴ','ᚵ'=>'ᚵ','ᚶ'=>'ᚶ','ᚷ'=>'ᚷ','ᚸ'=>'ᚸ','ᚹ'=>'ᚹ','ᚺ'=>'ᚺ','ᚻ'=>'ᚻ','ᚼ'=>'ᚼ','ᚽ'=>'ᚽ','ᚾ'=>'ᚾ','ᚿ'=>'ᚿ','ᛀ'=>'ᛀ','ᛁ'=>'ᛁ','ᛂ'=>'ᛂ','ᛃ'=>'ᛃ','ᛄ'=>'ᛄ','ᛅ'=>'ᛅ','ᛆ'=>'ᛆ','ᛇ'=>'ᛇ','ᛈ'=>'ᛈ','ᛉ'=>'ᛉ','ᛊ'=>'ᛊ','ᛋ'=>'ᛋ','ᛌ'=>'ᛌ','ᛍ'=>'ᛍ','ᛎ'=>'ᛎ','ᛏ'=>'ᛏ','ᛐ'=>'ᛐ','ᛑ'=>'ᛑ','ᛒ'=>'ᛒ','ᛓ'=>'ᛓ','ᛔ'=>'ᛔ','ᛕ'=>'ᛕ','ᛖ'=>'ᛖ','ᛗ'=>'ᛗ','ᛘ'=>'ᛘ','ᛙ'=>'ᛙ','ᛚ'=>'ᛚ','ᛛ'=>'ᛛ','ᛜ'=>'ᛜ','ᛝ'=>'ᛝ','ᛞ'=>'ᛞ','ᛟ'=>'ᛟ','ᛠ'=>'ᛠ','ᛡ'=>'ᛡ','ᛢ'=>'ᛢ','ᛣ'=>'ᛣ','ᛤ'=>'ᛤ','ᛥ'=>'ᛥ','ᛦ'=>'ᛦ','ᛧ'=>'ᛧ','ᛨ'=>'ᛨ','ᛩ'=>'ᛩ','ᛪ'=>'ᛪ','ᛮ'=>'17','ᛯ'=>'18','ᛰ'=>'19','ᜀ'=>'ᜀ','ᜁ'=>'ᜁ','ᜂ'=>'ᜂ','ᜃ'=>'ᜃ','ᜄ'=>'ᜄ','ᜅ'=>'ᜅ','ᜆ'=>'ᜆ','ᜇ'=>'ᜇ','ᜈ'=>'ᜈ','ᜉ'=>'ᜉ','ᜊ'=>'ᜊ','ᜋ'=>'ᜋ','ᜌ'=>'ᜌ','ᜎ'=>'ᜎ','ᜏ'=>'ᜏ','ᜐ'=>'ᜐ','ᜑ'=>'ᜑ','ᜒ'=>'ᜒ','ᜓ'=>'ᜓ','᜔'=>'᜔','ᜠ'=>'ᜠ','ᜡ'=>'ᜡ','ᜢ'=>'ᜢ','ᜣ'=>'ᜣ','ᜤ'=>'ᜤ','ᜥ'=>'ᜥ','ᜦ'=>'ᜦ','ᜧ'=>'ᜧ','ᜨ'=>'ᜨ','ᜩ'=>'ᜩ','ᜪ'=>'ᜪ','ᜫ'=>'ᜫ','ᜬ'=>'ᜬ','ᜭ'=>'ᜭ','ᜮ'=>'ᜮ','ᜯ'=>'ᜯ','ᜰ'=>'ᜰ','ᜱ'=>'ᜱ','ᜲ'=>'ᜲ','ᜳ'=>'ᜳ','᜴'=>'᜴','ᝀ'=>'ᝀ','ᝁ'=>'ᝁ','ᝂ'=>'ᝂ','ᝃ'=>'ᝃ','ᝄ'=>'ᝄ','ᝅ'=>'ᝅ','ᝆ'=>'ᝆ','ᝇ'=>'ᝇ','ᝈ'=>'ᝈ','ᝉ'=>'ᝉ','ᝊ'=>'ᝊ','ᝋ'=>'ᝋ','ᝌ'=>'ᝌ','ᝍ'=>'ᝍ','ᝎ'=>'ᝎ','ᝏ'=>'ᝏ','ᝐ'=>'ᝐ','ᝑ'=>'ᝑ','ᝒ'=>'ᝒ','ᝓ'=>'ᝓ','ᝠ'=>'ᝠ','ᝡ'=>'ᝡ','ᝢ'=>'ᝢ','ᝣ'=>'ᝣ','ᝤ'=>'ᝤ','ᝥ'=>'ᝥ','ᝦ'=>'ᝦ','ᝧ'=>'ᝧ','ᝨ'=>'ᝨ','ᝩ'=>'ᝩ','ᝪ'=>'ᝪ','ᝫ'=>'ᝫ','ᝬ'=>'ᝬ','ᝮ'=>'ᝮ','ᝯ'=>'ᝯ','ᝰ'=>'ᝰ','ᝲ'=>'ᝲ','ᝳ'=>'ᝳ','ក'=>'ក','ខ'=>'ខ','គ'=>'គ','ឃ'=>'ឃ','ង'=>'ង','ច'=>'ច','ឆ'=>'ឆ','ជ'=>'ជ','ឈ'=>'ឈ','ញ'=>'ញ','ដ'=>'ដ','ឋ'=>'ឋ','ឌ'=>'ឌ','ឍ'=>'ឍ','ណ'=>'ណ','ត'=>'ត','ថ'=>'ថ','ទ'=>'ទ','ធ'=>'ធ','ន'=>'ន','ប'=>'ប','ផ'=>'ផ','ព'=>'ព','ភ'=>'ភ','ម'=>'ម','យ'=>'យ','រ'=>'រ','ល'=>'ល','វ'=>'វ','ឝ'=>'ឝ','ឞ'=>'ឞ','ស'=>'ស','ហ'=>'ហ','ឡ'=>'ឡ','អ'=>'អ','ឣ'=>'ឣ','ឤ'=>'ឤ','ឥ'=>'ឥ','ឦ'=>'ឦ','ឧ'=>'ឧ','ឨ'=>'ឨ','ឩ'=>'ឩ','ឪ'=>'ឪ','ឫ'=>'ឫ','ឬ'=>'ឬ','ឭ'=>'ឭ','ឮ'=>'ឮ','ឯ'=>'ឯ','ឰ'=>'ឰ','ឱ'=>'ឱ','ឲ'=>'ឲ','ឳ'=>'ឳ','ា'=>'ា','ិ'=>'ិ','ី'=>'ី','ឹ'=>'ឹ','ឺ'=>'ឺ','ុ'=>'ុ','ូ'=>'ូ','ួ'=>'ួ','ើ'=>'ើ','ឿ'=>'ឿ','ៀ'=>'ៀ','េ'=>'េ','ែ'=>'ែ','ៃ'=>'ៃ','ោ'=>'ោ','ៅ'=>'ៅ','ំ'=>'ំ','ះ'=>'ះ','ៈ'=>'ៈ','៉'=>'៉','៊'=>'៊','់'=>'់','៌'=>'៌','៍'=>'៍','៎'=>'៎','៏'=>'៏','័'=>'័','៑'=>'៑','្'=>'្','៓'=>'៓','ៗ'=>'ៗ','ៜ'=>'ៜ','៝'=>'៝','០'=>'0','១'=>'1','២'=>'2','៣'=>'3','៤'=>'4','៥'=>'5','៦'=>'6','៧'=>'7','៨'=>'8','៩'=>'9','៰'=>'0','៱'=>'1','៲'=>'2','៳'=>'3','៴'=>'4','៵'=>'5','៶'=>'6','៷'=>'7','៸'=>'8','៹'=>'9'); diff --git a/phpBB/includes/utf/data/search_indexer_20.php b/phpBB/includes/utf/data/search_indexer_20.php index caab3c540b..0d2dfa6340 100644 --- a/phpBB/includes/utf/data/search_indexer_20.php +++ b/phpBB/includes/utf/data/search_indexer_20.php @@ -1 +1 @@ -<?php return array('ꀀ'=>'ꀀ','ꀁ'=>'ꀁ','ꀂ'=>'ꀂ','ꀃ'=>'ꀃ','ꀄ'=>'ꀄ','ꀅ'=>'ꀅ','ꀆ'=>'ꀆ','ꀇ'=>'ꀇ','ꀈ'=>'ꀈ','ꀉ'=>'ꀉ','ꀊ'=>'ꀊ','ꀋ'=>'ꀋ','ꀌ'=>'ꀌ','ꀍ'=>'ꀍ','ꀎ'=>'ꀎ','ꀏ'=>'ꀏ','ꀐ'=>'ꀐ','ꀑ'=>'ꀑ','ꀒ'=>'ꀒ','ꀓ'=>'ꀓ','ꀔ'=>'ꀔ','ꀕ'=>'ꀕ','ꀖ'=>'ꀖ','ꀗ'=>'ꀗ','ꀘ'=>'ꀘ','ꀙ'=>'ꀙ','ꀚ'=>'ꀚ','ꀛ'=>'ꀛ','ꀜ'=>'ꀜ','ꀝ'=>'ꀝ','ꀞ'=>'ꀞ','ꀟ'=>'ꀟ','ꀠ'=>'ꀠ','ꀡ'=>'ꀡ','ꀢ'=>'ꀢ','ꀣ'=>'ꀣ','ꀤ'=>'ꀤ','ꀥ'=>'ꀥ','ꀦ'=>'ꀦ','ꀧ'=>'ꀧ','ꀨ'=>'ꀨ','ꀩ'=>'ꀩ','ꀪ'=>'ꀪ','ꀫ'=>'ꀫ','ꀬ'=>'ꀬ','ꀭ'=>'ꀭ','ꀮ'=>'ꀮ','ꀯ'=>'ꀯ','ꀰ'=>'ꀰ','ꀱ'=>'ꀱ','ꀲ'=>'ꀲ','ꀳ'=>'ꀳ','ꀴ'=>'ꀴ','ꀵ'=>'ꀵ','ꀶ'=>'ꀶ','ꀷ'=>'ꀷ','ꀸ'=>'ꀸ','ꀹ'=>'ꀹ','ꀺ'=>'ꀺ','ꀻ'=>'ꀻ','ꀼ'=>'ꀼ','ꀽ'=>'ꀽ','ꀾ'=>'ꀾ','ꀿ'=>'ꀿ','ꁀ'=>'ꁀ','ꁁ'=>'ꁁ','ꁂ'=>'ꁂ','ꁃ'=>'ꁃ','ꁄ'=>'ꁄ','ꁅ'=>'ꁅ','ꁆ'=>'ꁆ','ꁇ'=>'ꁇ','ꁈ'=>'ꁈ','ꁉ'=>'ꁉ','ꁊ'=>'ꁊ','ꁋ'=>'ꁋ','ꁌ'=>'ꁌ','ꁍ'=>'ꁍ','ꁎ'=>'ꁎ','ꁏ'=>'ꁏ','ꁐ'=>'ꁐ','ꁑ'=>'ꁑ','ꁒ'=>'ꁒ','ꁓ'=>'ꁓ','ꁔ'=>'ꁔ','ꁕ'=>'ꁕ','ꁖ'=>'ꁖ','ꁗ'=>'ꁗ','ꁘ'=>'ꁘ','ꁙ'=>'ꁙ','ꁚ'=>'ꁚ','ꁛ'=>'ꁛ','ꁜ'=>'ꁜ','ꁝ'=>'ꁝ','ꁞ'=>'ꁞ','ꁟ'=>'ꁟ','ꁠ'=>'ꁠ','ꁡ'=>'ꁡ','ꁢ'=>'ꁢ','ꁣ'=>'ꁣ','ꁤ'=>'ꁤ','ꁥ'=>'ꁥ','ꁦ'=>'ꁦ','ꁧ'=>'ꁧ','ꁨ'=>'ꁨ','ꁩ'=>'ꁩ','ꁪ'=>'ꁪ','ꁫ'=>'ꁫ','ꁬ'=>'ꁬ','ꁭ'=>'ꁭ','ꁮ'=>'ꁮ','ꁯ'=>'ꁯ','ꁰ'=>'ꁰ','ꁱ'=>'ꁱ','ꁲ'=>'ꁲ','ꁳ'=>'ꁳ','ꁴ'=>'ꁴ','ꁵ'=>'ꁵ','ꁶ'=>'ꁶ','ꁷ'=>'ꁷ','ꁸ'=>'ꁸ','ꁹ'=>'ꁹ','ꁺ'=>'ꁺ','ꁻ'=>'ꁻ','ꁼ'=>'ꁼ','ꁽ'=>'ꁽ','ꁾ'=>'ꁾ','ꁿ'=>'ꁿ','ꂀ'=>'ꂀ','ꂁ'=>'ꂁ','ꂂ'=>'ꂂ','ꂃ'=>'ꂃ','ꂄ'=>'ꂄ','ꂅ'=>'ꂅ','ꂆ'=>'ꂆ','ꂇ'=>'ꂇ','ꂈ'=>'ꂈ','ꂉ'=>'ꂉ','ꂊ'=>'ꂊ','ꂋ'=>'ꂋ','ꂌ'=>'ꂌ','ꂍ'=>'ꂍ','ꂎ'=>'ꂎ','ꂏ'=>'ꂏ','ꂐ'=>'ꂐ','ꂑ'=>'ꂑ','ꂒ'=>'ꂒ','ꂓ'=>'ꂓ','ꂔ'=>'ꂔ','ꂕ'=>'ꂕ','ꂖ'=>'ꂖ','ꂗ'=>'ꂗ','ꂘ'=>'ꂘ','ꂙ'=>'ꂙ','ꂚ'=>'ꂚ','ꂛ'=>'ꂛ','ꂜ'=>'ꂜ','ꂝ'=>'ꂝ','ꂞ'=>'ꂞ','ꂟ'=>'ꂟ','ꂠ'=>'ꂠ','ꂡ'=>'ꂡ','ꂢ'=>'ꂢ','ꂣ'=>'ꂣ','ꂤ'=>'ꂤ','ꂥ'=>'ꂥ','ꂦ'=>'ꂦ','ꂧ'=>'ꂧ','ꂨ'=>'ꂨ','ꂩ'=>'ꂩ','ꂪ'=>'ꂪ','ꂫ'=>'ꂫ','ꂬ'=>'ꂬ','ꂭ'=>'ꂭ','ꂮ'=>'ꂮ','ꂯ'=>'ꂯ','ꂰ'=>'ꂰ','ꂱ'=>'ꂱ','ꂲ'=>'ꂲ','ꂳ'=>'ꂳ','ꂴ'=>'ꂴ','ꂵ'=>'ꂵ','ꂶ'=>'ꂶ','ꂷ'=>'ꂷ','ꂸ'=>'ꂸ','ꂹ'=>'ꂹ','ꂺ'=>'ꂺ','ꂻ'=>'ꂻ','ꂼ'=>'ꂼ','ꂽ'=>'ꂽ','ꂾ'=>'ꂾ','ꂿ'=>'ꂿ','ꃀ'=>'ꃀ','ꃁ'=>'ꃁ','ꃂ'=>'ꃂ','ꃃ'=>'ꃃ','ꃄ'=>'ꃄ','ꃅ'=>'ꃅ','ꃆ'=>'ꃆ','ꃇ'=>'ꃇ','ꃈ'=>'ꃈ','ꃉ'=>'ꃉ','ꃊ'=>'ꃊ','ꃋ'=>'ꃋ','ꃌ'=>'ꃌ','ꃍ'=>'ꃍ','ꃎ'=>'ꃎ','ꃏ'=>'ꃏ','ꃐ'=>'ꃐ','ꃑ'=>'ꃑ','ꃒ'=>'ꃒ','ꃓ'=>'ꃓ','ꃔ'=>'ꃔ','ꃕ'=>'ꃕ','ꃖ'=>'ꃖ','ꃗ'=>'ꃗ','ꃘ'=>'ꃘ','ꃙ'=>'ꃙ','ꃚ'=>'ꃚ','ꃛ'=>'ꃛ','ꃜ'=>'ꃜ','ꃝ'=>'ꃝ','ꃞ'=>'ꃞ','ꃟ'=>'ꃟ','ꃠ'=>'ꃠ','ꃡ'=>'ꃡ','ꃢ'=>'ꃢ','ꃣ'=>'ꃣ','ꃤ'=>'ꃤ','ꃥ'=>'ꃥ','ꃦ'=>'ꃦ','ꃧ'=>'ꃧ','ꃨ'=>'ꃨ','ꃩ'=>'ꃩ','ꃪ'=>'ꃪ','ꃫ'=>'ꃫ','ꃬ'=>'ꃬ','ꃭ'=>'ꃭ','ꃮ'=>'ꃮ','ꃯ'=>'ꃯ','ꃰ'=>'ꃰ','ꃱ'=>'ꃱ','ꃲ'=>'ꃲ','ꃳ'=>'ꃳ','ꃴ'=>'ꃴ','ꃵ'=>'ꃵ','ꃶ'=>'ꃶ','ꃷ'=>'ꃷ','ꃸ'=>'ꃸ','ꃹ'=>'ꃹ','ꃺ'=>'ꃺ','ꃻ'=>'ꃻ','ꃼ'=>'ꃼ','ꃽ'=>'ꃽ','ꃾ'=>'ꃾ','ꃿ'=>'ꃿ','ꄀ'=>'ꄀ','ꄁ'=>'ꄁ','ꄂ'=>'ꄂ','ꄃ'=>'ꄃ','ꄄ'=>'ꄄ','ꄅ'=>'ꄅ','ꄆ'=>'ꄆ','ꄇ'=>'ꄇ','ꄈ'=>'ꄈ','ꄉ'=>'ꄉ','ꄊ'=>'ꄊ','ꄋ'=>'ꄋ','ꄌ'=>'ꄌ','ꄍ'=>'ꄍ','ꄎ'=>'ꄎ','ꄏ'=>'ꄏ','ꄐ'=>'ꄐ','ꄑ'=>'ꄑ','ꄒ'=>'ꄒ','ꄓ'=>'ꄓ','ꄔ'=>'ꄔ','ꄕ'=>'ꄕ','ꄖ'=>'ꄖ','ꄗ'=>'ꄗ','ꄘ'=>'ꄘ','ꄙ'=>'ꄙ','ꄚ'=>'ꄚ','ꄛ'=>'ꄛ','ꄜ'=>'ꄜ','ꄝ'=>'ꄝ','ꄞ'=>'ꄞ','ꄟ'=>'ꄟ','ꄠ'=>'ꄠ','ꄡ'=>'ꄡ','ꄢ'=>'ꄢ','ꄣ'=>'ꄣ','ꄤ'=>'ꄤ','ꄥ'=>'ꄥ','ꄦ'=>'ꄦ','ꄧ'=>'ꄧ','ꄨ'=>'ꄨ','ꄩ'=>'ꄩ','ꄪ'=>'ꄪ','ꄫ'=>'ꄫ','ꄬ'=>'ꄬ','ꄭ'=>'ꄭ','ꄮ'=>'ꄮ','ꄯ'=>'ꄯ','ꄰ'=>'ꄰ','ꄱ'=>'ꄱ','ꄲ'=>'ꄲ','ꄳ'=>'ꄳ','ꄴ'=>'ꄴ','ꄵ'=>'ꄵ','ꄶ'=>'ꄶ','ꄷ'=>'ꄷ','ꄸ'=>'ꄸ','ꄹ'=>'ꄹ','ꄺ'=>'ꄺ','ꄻ'=>'ꄻ','ꄼ'=>'ꄼ','ꄽ'=>'ꄽ','ꄾ'=>'ꄾ','ꄿ'=>'ꄿ','ꅀ'=>'ꅀ','ꅁ'=>'ꅁ','ꅂ'=>'ꅂ','ꅃ'=>'ꅃ','ꅄ'=>'ꅄ','ꅅ'=>'ꅅ','ꅆ'=>'ꅆ','ꅇ'=>'ꅇ','ꅈ'=>'ꅈ','ꅉ'=>'ꅉ','ꅊ'=>'ꅊ','ꅋ'=>'ꅋ','ꅌ'=>'ꅌ','ꅍ'=>'ꅍ','ꅎ'=>'ꅎ','ꅏ'=>'ꅏ','ꅐ'=>'ꅐ','ꅑ'=>'ꅑ','ꅒ'=>'ꅒ','ꅓ'=>'ꅓ','ꅔ'=>'ꅔ','ꅕ'=>'ꅕ','ꅖ'=>'ꅖ','ꅗ'=>'ꅗ','ꅘ'=>'ꅘ','ꅙ'=>'ꅙ','ꅚ'=>'ꅚ','ꅛ'=>'ꅛ','ꅜ'=>'ꅜ','ꅝ'=>'ꅝ','ꅞ'=>'ꅞ','ꅟ'=>'ꅟ','ꅠ'=>'ꅠ','ꅡ'=>'ꅡ','ꅢ'=>'ꅢ','ꅣ'=>'ꅣ','ꅤ'=>'ꅤ','ꅥ'=>'ꅥ','ꅦ'=>'ꅦ','ꅧ'=>'ꅧ','ꅨ'=>'ꅨ','ꅩ'=>'ꅩ','ꅪ'=>'ꅪ','ꅫ'=>'ꅫ','ꅬ'=>'ꅬ','ꅭ'=>'ꅭ','ꅮ'=>'ꅮ','ꅯ'=>'ꅯ','ꅰ'=>'ꅰ','ꅱ'=>'ꅱ','ꅲ'=>'ꅲ','ꅳ'=>'ꅳ','ꅴ'=>'ꅴ','ꅵ'=>'ꅵ','ꅶ'=>'ꅶ','ꅷ'=>'ꅷ','ꅸ'=>'ꅸ','ꅹ'=>'ꅹ','ꅺ'=>'ꅺ','ꅻ'=>'ꅻ','ꅼ'=>'ꅼ','ꅽ'=>'ꅽ','ꅾ'=>'ꅾ','ꅿ'=>'ꅿ','ꆀ'=>'ꆀ','ꆁ'=>'ꆁ','ꆂ'=>'ꆂ','ꆃ'=>'ꆃ','ꆄ'=>'ꆄ','ꆅ'=>'ꆅ','ꆆ'=>'ꆆ','ꆇ'=>'ꆇ','ꆈ'=>'ꆈ','ꆉ'=>'ꆉ','ꆊ'=>'ꆊ','ꆋ'=>'ꆋ','ꆌ'=>'ꆌ','ꆍ'=>'ꆍ','ꆎ'=>'ꆎ','ꆏ'=>'ꆏ','ꆐ'=>'ꆐ','ꆑ'=>'ꆑ','ꆒ'=>'ꆒ','ꆓ'=>'ꆓ','ꆔ'=>'ꆔ','ꆕ'=>'ꆕ','ꆖ'=>'ꆖ','ꆗ'=>'ꆗ','ꆘ'=>'ꆘ','ꆙ'=>'ꆙ','ꆚ'=>'ꆚ','ꆛ'=>'ꆛ','ꆜ'=>'ꆜ','ꆝ'=>'ꆝ','ꆞ'=>'ꆞ','ꆟ'=>'ꆟ','ꆠ'=>'ꆠ','ꆡ'=>'ꆡ','ꆢ'=>'ꆢ','ꆣ'=>'ꆣ','ꆤ'=>'ꆤ','ꆥ'=>'ꆥ','ꆦ'=>'ꆦ','ꆧ'=>'ꆧ','ꆨ'=>'ꆨ','ꆩ'=>'ꆩ','ꆪ'=>'ꆪ','ꆫ'=>'ꆫ','ꆬ'=>'ꆬ','ꆭ'=>'ꆭ','ꆮ'=>'ꆮ','ꆯ'=>'ꆯ','ꆰ'=>'ꆰ','ꆱ'=>'ꆱ','ꆲ'=>'ꆲ','ꆳ'=>'ꆳ','ꆴ'=>'ꆴ','ꆵ'=>'ꆵ','ꆶ'=>'ꆶ','ꆷ'=>'ꆷ','ꆸ'=>'ꆸ','ꆹ'=>'ꆹ','ꆺ'=>'ꆺ','ꆻ'=>'ꆻ','ꆼ'=>'ꆼ','ꆽ'=>'ꆽ','ꆾ'=>'ꆾ','ꆿ'=>'ꆿ','ꇀ'=>'ꇀ','ꇁ'=>'ꇁ','ꇂ'=>'ꇂ','ꇃ'=>'ꇃ','ꇄ'=>'ꇄ','ꇅ'=>'ꇅ','ꇆ'=>'ꇆ','ꇇ'=>'ꇇ','ꇈ'=>'ꇈ','ꇉ'=>'ꇉ','ꇊ'=>'ꇊ','ꇋ'=>'ꇋ','ꇌ'=>'ꇌ','ꇍ'=>'ꇍ','ꇎ'=>'ꇎ','ꇏ'=>'ꇏ','ꇐ'=>'ꇐ','ꇑ'=>'ꇑ','ꇒ'=>'ꇒ','ꇓ'=>'ꇓ','ꇔ'=>'ꇔ','ꇕ'=>'ꇕ','ꇖ'=>'ꇖ','ꇗ'=>'ꇗ','ꇘ'=>'ꇘ','ꇙ'=>'ꇙ','ꇚ'=>'ꇚ','ꇛ'=>'ꇛ','ꇜ'=>'ꇜ','ꇝ'=>'ꇝ','ꇞ'=>'ꇞ','ꇟ'=>'ꇟ','ꇠ'=>'ꇠ','ꇡ'=>'ꇡ','ꇢ'=>'ꇢ','ꇣ'=>'ꇣ','ꇤ'=>'ꇤ','ꇥ'=>'ꇥ','ꇦ'=>'ꇦ','ꇧ'=>'ꇧ','ꇨ'=>'ꇨ','ꇩ'=>'ꇩ','ꇪ'=>'ꇪ','ꇫ'=>'ꇫ','ꇬ'=>'ꇬ','ꇭ'=>'ꇭ','ꇮ'=>'ꇮ','ꇯ'=>'ꇯ','ꇰ'=>'ꇰ','ꇱ'=>'ꇱ','ꇲ'=>'ꇲ','ꇳ'=>'ꇳ','ꇴ'=>'ꇴ','ꇵ'=>'ꇵ','ꇶ'=>'ꇶ','ꇷ'=>'ꇷ','ꇸ'=>'ꇸ','ꇹ'=>'ꇹ','ꇺ'=>'ꇺ','ꇻ'=>'ꇻ','ꇼ'=>'ꇼ','ꇽ'=>'ꇽ','ꇾ'=>'ꇾ','ꇿ'=>'ꇿ','ꈀ'=>'ꈀ','ꈁ'=>'ꈁ','ꈂ'=>'ꈂ','ꈃ'=>'ꈃ','ꈄ'=>'ꈄ','ꈅ'=>'ꈅ','ꈆ'=>'ꈆ','ꈇ'=>'ꈇ','ꈈ'=>'ꈈ','ꈉ'=>'ꈉ','ꈊ'=>'ꈊ','ꈋ'=>'ꈋ','ꈌ'=>'ꈌ','ꈍ'=>'ꈍ','ꈎ'=>'ꈎ','ꈏ'=>'ꈏ','ꈐ'=>'ꈐ','ꈑ'=>'ꈑ','ꈒ'=>'ꈒ','ꈓ'=>'ꈓ','ꈔ'=>'ꈔ','ꈕ'=>'ꈕ','ꈖ'=>'ꈖ','ꈗ'=>'ꈗ','ꈘ'=>'ꈘ','ꈙ'=>'ꈙ','ꈚ'=>'ꈚ','ꈛ'=>'ꈛ','ꈜ'=>'ꈜ','ꈝ'=>'ꈝ','ꈞ'=>'ꈞ','ꈟ'=>'ꈟ','ꈠ'=>'ꈠ','ꈡ'=>'ꈡ','ꈢ'=>'ꈢ','ꈣ'=>'ꈣ','ꈤ'=>'ꈤ','ꈥ'=>'ꈥ','ꈦ'=>'ꈦ','ꈧ'=>'ꈧ','ꈨ'=>'ꈨ','ꈩ'=>'ꈩ','ꈪ'=>'ꈪ','ꈫ'=>'ꈫ','ꈬ'=>'ꈬ','ꈭ'=>'ꈭ','ꈮ'=>'ꈮ','ꈯ'=>'ꈯ','ꈰ'=>'ꈰ','ꈱ'=>'ꈱ','ꈲ'=>'ꈲ','ꈳ'=>'ꈳ','ꈴ'=>'ꈴ','ꈵ'=>'ꈵ','ꈶ'=>'ꈶ','ꈷ'=>'ꈷ','ꈸ'=>'ꈸ','ꈹ'=>'ꈹ','ꈺ'=>'ꈺ','ꈻ'=>'ꈻ','ꈼ'=>'ꈼ','ꈽ'=>'ꈽ','ꈾ'=>'ꈾ','ꈿ'=>'ꈿ','ꉀ'=>'ꉀ','ꉁ'=>'ꉁ','ꉂ'=>'ꉂ','ꉃ'=>'ꉃ','ꉄ'=>'ꉄ','ꉅ'=>'ꉅ','ꉆ'=>'ꉆ','ꉇ'=>'ꉇ','ꉈ'=>'ꉈ','ꉉ'=>'ꉉ','ꉊ'=>'ꉊ','ꉋ'=>'ꉋ','ꉌ'=>'ꉌ','ꉍ'=>'ꉍ','ꉎ'=>'ꉎ','ꉏ'=>'ꉏ','ꉐ'=>'ꉐ','ꉑ'=>'ꉑ','ꉒ'=>'ꉒ','ꉓ'=>'ꉓ','ꉔ'=>'ꉔ','ꉕ'=>'ꉕ','ꉖ'=>'ꉖ','ꉗ'=>'ꉗ','ꉘ'=>'ꉘ','ꉙ'=>'ꉙ','ꉚ'=>'ꉚ','ꉛ'=>'ꉛ','ꉜ'=>'ꉜ','ꉝ'=>'ꉝ','ꉞ'=>'ꉞ','ꉟ'=>'ꉟ','ꉠ'=>'ꉠ','ꉡ'=>'ꉡ','ꉢ'=>'ꉢ','ꉣ'=>'ꉣ','ꉤ'=>'ꉤ','ꉥ'=>'ꉥ','ꉦ'=>'ꉦ','ꉧ'=>'ꉧ','ꉨ'=>'ꉨ','ꉩ'=>'ꉩ','ꉪ'=>'ꉪ','ꉫ'=>'ꉫ','ꉬ'=>'ꉬ','ꉭ'=>'ꉭ','ꉮ'=>'ꉮ','ꉯ'=>'ꉯ','ꉰ'=>'ꉰ','ꉱ'=>'ꉱ','ꉲ'=>'ꉲ','ꉳ'=>'ꉳ','ꉴ'=>'ꉴ','ꉵ'=>'ꉵ','ꉶ'=>'ꉶ','ꉷ'=>'ꉷ','ꉸ'=>'ꉸ','ꉹ'=>'ꉹ','ꉺ'=>'ꉺ','ꉻ'=>'ꉻ','ꉼ'=>'ꉼ','ꉽ'=>'ꉽ','ꉾ'=>'ꉾ','ꉿ'=>'ꉿ','ꊀ'=>'ꊀ','ꊁ'=>'ꊁ','ꊂ'=>'ꊂ','ꊃ'=>'ꊃ','ꊄ'=>'ꊄ','ꊅ'=>'ꊅ','ꊆ'=>'ꊆ','ꊇ'=>'ꊇ','ꊈ'=>'ꊈ','ꊉ'=>'ꊉ','ꊊ'=>'ꊊ','ꊋ'=>'ꊋ','ꊌ'=>'ꊌ','ꊍ'=>'ꊍ','ꊎ'=>'ꊎ','ꊏ'=>'ꊏ','ꊐ'=>'ꊐ','ꊑ'=>'ꊑ','ꊒ'=>'ꊒ','ꊓ'=>'ꊓ','ꊔ'=>'ꊔ','ꊕ'=>'ꊕ','ꊖ'=>'ꊖ','ꊗ'=>'ꊗ','ꊘ'=>'ꊘ','ꊙ'=>'ꊙ','ꊚ'=>'ꊚ','ꊛ'=>'ꊛ','ꊜ'=>'ꊜ','ꊝ'=>'ꊝ','ꊞ'=>'ꊞ','ꊟ'=>'ꊟ','ꊠ'=>'ꊠ','ꊡ'=>'ꊡ','ꊢ'=>'ꊢ','ꊣ'=>'ꊣ','ꊤ'=>'ꊤ','ꊥ'=>'ꊥ','ꊦ'=>'ꊦ','ꊧ'=>'ꊧ','ꊨ'=>'ꊨ','ꊩ'=>'ꊩ','ꊪ'=>'ꊪ','ꊫ'=>'ꊫ','ꊬ'=>'ꊬ','ꊭ'=>'ꊭ','ꊮ'=>'ꊮ','ꊯ'=>'ꊯ','ꊰ'=>'ꊰ','ꊱ'=>'ꊱ','ꊲ'=>'ꊲ','ꊳ'=>'ꊳ','ꊴ'=>'ꊴ','ꊵ'=>'ꊵ','ꊶ'=>'ꊶ','ꊷ'=>'ꊷ','ꊸ'=>'ꊸ','ꊹ'=>'ꊹ','ꊺ'=>'ꊺ','ꊻ'=>'ꊻ','ꊼ'=>'ꊼ','ꊽ'=>'ꊽ','ꊾ'=>'ꊾ','ꊿ'=>'ꊿ','ꋀ'=>'ꋀ','ꋁ'=>'ꋁ','ꋂ'=>'ꋂ','ꋃ'=>'ꋃ','ꋄ'=>'ꋄ','ꋅ'=>'ꋅ','ꋆ'=>'ꋆ','ꋇ'=>'ꋇ','ꋈ'=>'ꋈ','ꋉ'=>'ꋉ','ꋊ'=>'ꋊ','ꋋ'=>'ꋋ','ꋌ'=>'ꋌ','ꋍ'=>'ꋍ','ꋎ'=>'ꋎ','ꋏ'=>'ꋏ','ꋐ'=>'ꋐ','ꋑ'=>'ꋑ','ꋒ'=>'ꋒ','ꋓ'=>'ꋓ','ꋔ'=>'ꋔ','ꋕ'=>'ꋕ','ꋖ'=>'ꋖ','ꋗ'=>'ꋗ','ꋘ'=>'ꋘ','ꋙ'=>'ꋙ','ꋚ'=>'ꋚ','ꋛ'=>'ꋛ','ꋜ'=>'ꋜ','ꋝ'=>'ꋝ','ꋞ'=>'ꋞ','ꋟ'=>'ꋟ','ꋠ'=>'ꋠ','ꋡ'=>'ꋡ','ꋢ'=>'ꋢ','ꋣ'=>'ꋣ','ꋤ'=>'ꋤ','ꋥ'=>'ꋥ','ꋦ'=>'ꋦ','ꋧ'=>'ꋧ','ꋨ'=>'ꋨ','ꋩ'=>'ꋩ','ꋪ'=>'ꋪ','ꋫ'=>'ꋫ','ꋬ'=>'ꋬ','ꋭ'=>'ꋭ','ꋮ'=>'ꋮ','ꋯ'=>'ꋯ','ꋰ'=>'ꋰ','ꋱ'=>'ꋱ','ꋲ'=>'ꋲ','ꋳ'=>'ꋳ','ꋴ'=>'ꋴ','ꋵ'=>'ꋵ','ꋶ'=>'ꋶ','ꋷ'=>'ꋷ','ꋸ'=>'ꋸ','ꋹ'=>'ꋹ','ꋺ'=>'ꋺ','ꋻ'=>'ꋻ','ꋼ'=>'ꋼ','ꋽ'=>'ꋽ','ꋾ'=>'ꋾ','ꋿ'=>'ꋿ','ꌀ'=>'ꌀ','ꌁ'=>'ꌁ','ꌂ'=>'ꌂ','ꌃ'=>'ꌃ','ꌄ'=>'ꌄ','ꌅ'=>'ꌅ','ꌆ'=>'ꌆ','ꌇ'=>'ꌇ','ꌈ'=>'ꌈ','ꌉ'=>'ꌉ','ꌊ'=>'ꌊ','ꌋ'=>'ꌋ','ꌌ'=>'ꌌ','ꌍ'=>'ꌍ','ꌎ'=>'ꌎ','ꌏ'=>'ꌏ','ꌐ'=>'ꌐ','ꌑ'=>'ꌑ','ꌒ'=>'ꌒ','ꌓ'=>'ꌓ','ꌔ'=>'ꌔ','ꌕ'=>'ꌕ','ꌖ'=>'ꌖ','ꌗ'=>'ꌗ','ꌘ'=>'ꌘ','ꌙ'=>'ꌙ','ꌚ'=>'ꌚ','ꌛ'=>'ꌛ','ꌜ'=>'ꌜ','ꌝ'=>'ꌝ','ꌞ'=>'ꌞ','ꌟ'=>'ꌟ','ꌠ'=>'ꌠ','ꌡ'=>'ꌡ','ꌢ'=>'ꌢ','ꌣ'=>'ꌣ','ꌤ'=>'ꌤ','ꌥ'=>'ꌥ','ꌦ'=>'ꌦ','ꌧ'=>'ꌧ','ꌨ'=>'ꌨ','ꌩ'=>'ꌩ','ꌪ'=>'ꌪ','ꌫ'=>'ꌫ','ꌬ'=>'ꌬ','ꌭ'=>'ꌭ','ꌮ'=>'ꌮ','ꌯ'=>'ꌯ','ꌰ'=>'ꌰ','ꌱ'=>'ꌱ','ꌲ'=>'ꌲ','ꌳ'=>'ꌳ','ꌴ'=>'ꌴ','ꌵ'=>'ꌵ','ꌶ'=>'ꌶ','ꌷ'=>'ꌷ','ꌸ'=>'ꌸ','ꌹ'=>'ꌹ','ꌺ'=>'ꌺ','ꌻ'=>'ꌻ','ꌼ'=>'ꌼ','ꌽ'=>'ꌽ','ꌾ'=>'ꌾ','ꌿ'=>'ꌿ','ꍀ'=>'ꍀ','ꍁ'=>'ꍁ','ꍂ'=>'ꍂ','ꍃ'=>'ꍃ','ꍄ'=>'ꍄ','ꍅ'=>'ꍅ','ꍆ'=>'ꍆ','ꍇ'=>'ꍇ','ꍈ'=>'ꍈ','ꍉ'=>'ꍉ','ꍊ'=>'ꍊ','ꍋ'=>'ꍋ','ꍌ'=>'ꍌ','ꍍ'=>'ꍍ','ꍎ'=>'ꍎ','ꍏ'=>'ꍏ','ꍐ'=>'ꍐ','ꍑ'=>'ꍑ','ꍒ'=>'ꍒ','ꍓ'=>'ꍓ','ꍔ'=>'ꍔ','ꍕ'=>'ꍕ','ꍖ'=>'ꍖ','ꍗ'=>'ꍗ','ꍘ'=>'ꍘ','ꍙ'=>'ꍙ','ꍚ'=>'ꍚ','ꍛ'=>'ꍛ','ꍜ'=>'ꍜ','ꍝ'=>'ꍝ','ꍞ'=>'ꍞ','ꍟ'=>'ꍟ','ꍠ'=>'ꍠ','ꍡ'=>'ꍡ','ꍢ'=>'ꍢ','ꍣ'=>'ꍣ','ꍤ'=>'ꍤ','ꍥ'=>'ꍥ','ꍦ'=>'ꍦ','ꍧ'=>'ꍧ','ꍨ'=>'ꍨ','ꍩ'=>'ꍩ','ꍪ'=>'ꍪ','ꍫ'=>'ꍫ','ꍬ'=>'ꍬ','ꍭ'=>'ꍭ','ꍮ'=>'ꍮ','ꍯ'=>'ꍯ','ꍰ'=>'ꍰ','ꍱ'=>'ꍱ','ꍲ'=>'ꍲ','ꍳ'=>'ꍳ','ꍴ'=>'ꍴ','ꍵ'=>'ꍵ','ꍶ'=>'ꍶ','ꍷ'=>'ꍷ','ꍸ'=>'ꍸ','ꍹ'=>'ꍹ','ꍺ'=>'ꍺ','ꍻ'=>'ꍻ','ꍼ'=>'ꍼ','ꍽ'=>'ꍽ','ꍾ'=>'ꍾ','ꍿ'=>'ꍿ','ꎀ'=>'ꎀ','ꎁ'=>'ꎁ','ꎂ'=>'ꎂ','ꎃ'=>'ꎃ','ꎄ'=>'ꎄ','ꎅ'=>'ꎅ','ꎆ'=>'ꎆ','ꎇ'=>'ꎇ','ꎈ'=>'ꎈ','ꎉ'=>'ꎉ','ꎊ'=>'ꎊ','ꎋ'=>'ꎋ','ꎌ'=>'ꎌ','ꎍ'=>'ꎍ','ꎎ'=>'ꎎ','ꎏ'=>'ꎏ','ꎐ'=>'ꎐ','ꎑ'=>'ꎑ','ꎒ'=>'ꎒ','ꎓ'=>'ꎓ','ꎔ'=>'ꎔ','ꎕ'=>'ꎕ','ꎖ'=>'ꎖ','ꎗ'=>'ꎗ','ꎘ'=>'ꎘ','ꎙ'=>'ꎙ','ꎚ'=>'ꎚ','ꎛ'=>'ꎛ','ꎜ'=>'ꎜ','ꎝ'=>'ꎝ','ꎞ'=>'ꎞ','ꎟ'=>'ꎟ','ꎠ'=>'ꎠ','ꎡ'=>'ꎡ','ꎢ'=>'ꎢ','ꎣ'=>'ꎣ','ꎤ'=>'ꎤ','ꎥ'=>'ꎥ','ꎦ'=>'ꎦ','ꎧ'=>'ꎧ','ꎨ'=>'ꎨ','ꎩ'=>'ꎩ','ꎪ'=>'ꎪ','ꎫ'=>'ꎫ','ꎬ'=>'ꎬ','ꎭ'=>'ꎭ','ꎮ'=>'ꎮ','ꎯ'=>'ꎯ','ꎰ'=>'ꎰ','ꎱ'=>'ꎱ','ꎲ'=>'ꎲ','ꎳ'=>'ꎳ','ꎴ'=>'ꎴ','ꎵ'=>'ꎵ','ꎶ'=>'ꎶ','ꎷ'=>'ꎷ','ꎸ'=>'ꎸ','ꎹ'=>'ꎹ','ꎺ'=>'ꎺ','ꎻ'=>'ꎻ','ꎼ'=>'ꎼ','ꎽ'=>'ꎽ','ꎾ'=>'ꎾ','ꎿ'=>'ꎿ','ꏀ'=>'ꏀ','ꏁ'=>'ꏁ','ꏂ'=>'ꏂ','ꏃ'=>'ꏃ','ꏄ'=>'ꏄ','ꏅ'=>'ꏅ','ꏆ'=>'ꏆ','ꏇ'=>'ꏇ','ꏈ'=>'ꏈ','ꏉ'=>'ꏉ','ꏊ'=>'ꏊ','ꏋ'=>'ꏋ','ꏌ'=>'ꏌ','ꏍ'=>'ꏍ','ꏎ'=>'ꏎ','ꏏ'=>'ꏏ','ꏐ'=>'ꏐ','ꏑ'=>'ꏑ','ꏒ'=>'ꏒ','ꏓ'=>'ꏓ','ꏔ'=>'ꏔ','ꏕ'=>'ꏕ','ꏖ'=>'ꏖ','ꏗ'=>'ꏗ','ꏘ'=>'ꏘ','ꏙ'=>'ꏙ','ꏚ'=>'ꏚ','ꏛ'=>'ꏛ','ꏜ'=>'ꏜ','ꏝ'=>'ꏝ','ꏞ'=>'ꏞ','ꏟ'=>'ꏟ','ꏠ'=>'ꏠ','ꏡ'=>'ꏡ','ꏢ'=>'ꏢ','ꏣ'=>'ꏣ','ꏤ'=>'ꏤ','ꏥ'=>'ꏥ','ꏦ'=>'ꏦ','ꏧ'=>'ꏧ','ꏨ'=>'ꏨ','ꏩ'=>'ꏩ','ꏪ'=>'ꏪ','ꏫ'=>'ꏫ','ꏬ'=>'ꏬ','ꏭ'=>'ꏭ','ꏮ'=>'ꏮ','ꏯ'=>'ꏯ','ꏰ'=>'ꏰ','ꏱ'=>'ꏱ','ꏲ'=>'ꏲ','ꏳ'=>'ꏳ','ꏴ'=>'ꏴ','ꏵ'=>'ꏵ','ꏶ'=>'ꏶ','ꏷ'=>'ꏷ','ꏸ'=>'ꏸ','ꏹ'=>'ꏹ','ꏺ'=>'ꏺ','ꏻ'=>'ꏻ','ꏼ'=>'ꏼ','ꏽ'=>'ꏽ','ꏾ'=>'ꏾ','ꏿ'=>'ꏿ','ꐀ'=>'ꐀ','ꐁ'=>'ꐁ','ꐂ'=>'ꐂ','ꐃ'=>'ꐃ','ꐄ'=>'ꐄ','ꐅ'=>'ꐅ','ꐆ'=>'ꐆ','ꐇ'=>'ꐇ','ꐈ'=>'ꐈ','ꐉ'=>'ꐉ','ꐊ'=>'ꐊ','ꐋ'=>'ꐋ','ꐌ'=>'ꐌ','ꐍ'=>'ꐍ','ꐎ'=>'ꐎ','ꐏ'=>'ꐏ','ꐐ'=>'ꐐ','ꐑ'=>'ꐑ','ꐒ'=>'ꐒ','ꐓ'=>'ꐓ','ꐔ'=>'ꐔ','ꐕ'=>'ꐕ','ꐖ'=>'ꐖ','ꐗ'=>'ꐗ','ꐘ'=>'ꐘ','ꐙ'=>'ꐙ','ꐚ'=>'ꐚ','ꐛ'=>'ꐛ','ꐜ'=>'ꐜ','ꐝ'=>'ꐝ','ꐞ'=>'ꐞ','ꐟ'=>'ꐟ','ꐠ'=>'ꐠ','ꐡ'=>'ꐡ','ꐢ'=>'ꐢ','ꐣ'=>'ꐣ','ꐤ'=>'ꐤ','ꐥ'=>'ꐥ','ꐦ'=>'ꐦ','ꐧ'=>'ꐧ','ꐨ'=>'ꐨ','ꐩ'=>'ꐩ','ꐪ'=>'ꐪ','ꐫ'=>'ꐫ','ꐬ'=>'ꐬ','ꐭ'=>'ꐭ','ꐮ'=>'ꐮ','ꐯ'=>'ꐯ','ꐰ'=>'ꐰ','ꐱ'=>'ꐱ','ꐲ'=>'ꐲ','ꐳ'=>'ꐳ','ꐴ'=>'ꐴ','ꐵ'=>'ꐵ','ꐶ'=>'ꐶ','ꐷ'=>'ꐷ','ꐸ'=>'ꐸ','ꐹ'=>'ꐹ','ꐺ'=>'ꐺ','ꐻ'=>'ꐻ','ꐼ'=>'ꐼ','ꐽ'=>'ꐽ','ꐾ'=>'ꐾ','ꐿ'=>'ꐿ','ꑀ'=>'ꑀ','ꑁ'=>'ꑁ','ꑂ'=>'ꑂ','ꑃ'=>'ꑃ','ꑄ'=>'ꑄ','ꑅ'=>'ꑅ','ꑆ'=>'ꑆ','ꑇ'=>'ꑇ','ꑈ'=>'ꑈ','ꑉ'=>'ꑉ','ꑊ'=>'ꑊ','ꑋ'=>'ꑋ','ꑌ'=>'ꑌ','ꑍ'=>'ꑍ','ꑎ'=>'ꑎ','ꑏ'=>'ꑏ','ꑐ'=>'ꑐ','ꑑ'=>'ꑑ','ꑒ'=>'ꑒ','ꑓ'=>'ꑓ','ꑔ'=>'ꑔ','ꑕ'=>'ꑕ','ꑖ'=>'ꑖ','ꑗ'=>'ꑗ','ꑘ'=>'ꑘ','ꑙ'=>'ꑙ','ꑚ'=>'ꑚ','ꑛ'=>'ꑛ','ꑜ'=>'ꑜ','ꑝ'=>'ꑝ','ꑞ'=>'ꑞ','ꑟ'=>'ꑟ','ꑠ'=>'ꑠ','ꑡ'=>'ꑡ','ꑢ'=>'ꑢ','ꑣ'=>'ꑣ','ꑤ'=>'ꑤ','ꑥ'=>'ꑥ','ꑦ'=>'ꑦ','ꑧ'=>'ꑧ','ꑨ'=>'ꑨ','ꑩ'=>'ꑩ','ꑪ'=>'ꑪ','ꑫ'=>'ꑫ','ꑬ'=>'ꑬ','ꑭ'=>'ꑭ','ꑮ'=>'ꑮ','ꑯ'=>'ꑯ','ꑰ'=>'ꑰ','ꑱ'=>'ꑱ','ꑲ'=>'ꑲ','ꑳ'=>'ꑳ','ꑴ'=>'ꑴ','ꑵ'=>'ꑵ','ꑶ'=>'ꑶ','ꑷ'=>'ꑷ','ꑸ'=>'ꑸ','ꑹ'=>'ꑹ','ꑺ'=>'ꑺ','ꑻ'=>'ꑻ','ꑼ'=>'ꑼ','ꑽ'=>'ꑽ','ꑾ'=>'ꑾ','ꑿ'=>'ꑿ','ꒀ'=>'ꒀ','ꒁ'=>'ꒁ','ꒂ'=>'ꒂ','ꒃ'=>'ꒃ','ꒄ'=>'ꒄ','ꒅ'=>'ꒅ','ꒆ'=>'ꒆ','ꒇ'=>'ꒇ','ꒈ'=>'ꒈ','ꒉ'=>'ꒉ','ꒊ'=>'ꒊ','ꒋ'=>'ꒋ','ꒌ'=>'ꒌ','ꜗ'=>'ꜗ','ꜘ'=>'ꜘ','ꜙ'=>'ꜙ','ꜚ'=>'ꜚ');
\ No newline at end of file +<?php return array('ꀀ'=>'ꀀ','ꀁ'=>'ꀁ','ꀂ'=>'ꀂ','ꀃ'=>'ꀃ','ꀄ'=>'ꀄ','ꀅ'=>'ꀅ','ꀆ'=>'ꀆ','ꀇ'=>'ꀇ','ꀈ'=>'ꀈ','ꀉ'=>'ꀉ','ꀊ'=>'ꀊ','ꀋ'=>'ꀋ','ꀌ'=>'ꀌ','ꀍ'=>'ꀍ','ꀎ'=>'ꀎ','ꀏ'=>'ꀏ','ꀐ'=>'ꀐ','ꀑ'=>'ꀑ','ꀒ'=>'ꀒ','ꀓ'=>'ꀓ','ꀔ'=>'ꀔ','ꀕ'=>'ꀕ','ꀖ'=>'ꀖ','ꀗ'=>'ꀗ','ꀘ'=>'ꀘ','ꀙ'=>'ꀙ','ꀚ'=>'ꀚ','ꀛ'=>'ꀛ','ꀜ'=>'ꀜ','ꀝ'=>'ꀝ','ꀞ'=>'ꀞ','ꀟ'=>'ꀟ','ꀠ'=>'ꀠ','ꀡ'=>'ꀡ','ꀢ'=>'ꀢ','ꀣ'=>'ꀣ','ꀤ'=>'ꀤ','ꀥ'=>'ꀥ','ꀦ'=>'ꀦ','ꀧ'=>'ꀧ','ꀨ'=>'ꀨ','ꀩ'=>'ꀩ','ꀪ'=>'ꀪ','ꀫ'=>'ꀫ','ꀬ'=>'ꀬ','ꀭ'=>'ꀭ','ꀮ'=>'ꀮ','ꀯ'=>'ꀯ','ꀰ'=>'ꀰ','ꀱ'=>'ꀱ','ꀲ'=>'ꀲ','ꀳ'=>'ꀳ','ꀴ'=>'ꀴ','ꀵ'=>'ꀵ','ꀶ'=>'ꀶ','ꀷ'=>'ꀷ','ꀸ'=>'ꀸ','ꀹ'=>'ꀹ','ꀺ'=>'ꀺ','ꀻ'=>'ꀻ','ꀼ'=>'ꀼ','ꀽ'=>'ꀽ','ꀾ'=>'ꀾ','ꀿ'=>'ꀿ','ꁀ'=>'ꁀ','ꁁ'=>'ꁁ','ꁂ'=>'ꁂ','ꁃ'=>'ꁃ','ꁄ'=>'ꁄ','ꁅ'=>'ꁅ','ꁆ'=>'ꁆ','ꁇ'=>'ꁇ','ꁈ'=>'ꁈ','ꁉ'=>'ꁉ','ꁊ'=>'ꁊ','ꁋ'=>'ꁋ','ꁌ'=>'ꁌ','ꁍ'=>'ꁍ','ꁎ'=>'ꁎ','ꁏ'=>'ꁏ','ꁐ'=>'ꁐ','ꁑ'=>'ꁑ','ꁒ'=>'ꁒ','ꁓ'=>'ꁓ','ꁔ'=>'ꁔ','ꁕ'=>'ꁕ','ꁖ'=>'ꁖ','ꁗ'=>'ꁗ','ꁘ'=>'ꁘ','ꁙ'=>'ꁙ','ꁚ'=>'ꁚ','ꁛ'=>'ꁛ','ꁜ'=>'ꁜ','ꁝ'=>'ꁝ','ꁞ'=>'ꁞ','ꁟ'=>'ꁟ','ꁠ'=>'ꁠ','ꁡ'=>'ꁡ','ꁢ'=>'ꁢ','ꁣ'=>'ꁣ','ꁤ'=>'ꁤ','ꁥ'=>'ꁥ','ꁦ'=>'ꁦ','ꁧ'=>'ꁧ','ꁨ'=>'ꁨ','ꁩ'=>'ꁩ','ꁪ'=>'ꁪ','ꁫ'=>'ꁫ','ꁬ'=>'ꁬ','ꁭ'=>'ꁭ','ꁮ'=>'ꁮ','ꁯ'=>'ꁯ','ꁰ'=>'ꁰ','ꁱ'=>'ꁱ','ꁲ'=>'ꁲ','ꁳ'=>'ꁳ','ꁴ'=>'ꁴ','ꁵ'=>'ꁵ','ꁶ'=>'ꁶ','ꁷ'=>'ꁷ','ꁸ'=>'ꁸ','ꁹ'=>'ꁹ','ꁺ'=>'ꁺ','ꁻ'=>'ꁻ','ꁼ'=>'ꁼ','ꁽ'=>'ꁽ','ꁾ'=>'ꁾ','ꁿ'=>'ꁿ','ꂀ'=>'ꂀ','ꂁ'=>'ꂁ','ꂂ'=>'ꂂ','ꂃ'=>'ꂃ','ꂄ'=>'ꂄ','ꂅ'=>'ꂅ','ꂆ'=>'ꂆ','ꂇ'=>'ꂇ','ꂈ'=>'ꂈ','ꂉ'=>'ꂉ','ꂊ'=>'ꂊ','ꂋ'=>'ꂋ','ꂌ'=>'ꂌ','ꂍ'=>'ꂍ','ꂎ'=>'ꂎ','ꂏ'=>'ꂏ','ꂐ'=>'ꂐ','ꂑ'=>'ꂑ','ꂒ'=>'ꂒ','ꂓ'=>'ꂓ','ꂔ'=>'ꂔ','ꂕ'=>'ꂕ','ꂖ'=>'ꂖ','ꂗ'=>'ꂗ','ꂘ'=>'ꂘ','ꂙ'=>'ꂙ','ꂚ'=>'ꂚ','ꂛ'=>'ꂛ','ꂜ'=>'ꂜ','ꂝ'=>'ꂝ','ꂞ'=>'ꂞ','ꂟ'=>'ꂟ','ꂠ'=>'ꂠ','ꂡ'=>'ꂡ','ꂢ'=>'ꂢ','ꂣ'=>'ꂣ','ꂤ'=>'ꂤ','ꂥ'=>'ꂥ','ꂦ'=>'ꂦ','ꂧ'=>'ꂧ','ꂨ'=>'ꂨ','ꂩ'=>'ꂩ','ꂪ'=>'ꂪ','ꂫ'=>'ꂫ','ꂬ'=>'ꂬ','ꂭ'=>'ꂭ','ꂮ'=>'ꂮ','ꂯ'=>'ꂯ','ꂰ'=>'ꂰ','ꂱ'=>'ꂱ','ꂲ'=>'ꂲ','ꂳ'=>'ꂳ','ꂴ'=>'ꂴ','ꂵ'=>'ꂵ','ꂶ'=>'ꂶ','ꂷ'=>'ꂷ','ꂸ'=>'ꂸ','ꂹ'=>'ꂹ','ꂺ'=>'ꂺ','ꂻ'=>'ꂻ','ꂼ'=>'ꂼ','ꂽ'=>'ꂽ','ꂾ'=>'ꂾ','ꂿ'=>'ꂿ','ꃀ'=>'ꃀ','ꃁ'=>'ꃁ','ꃂ'=>'ꃂ','ꃃ'=>'ꃃ','ꃄ'=>'ꃄ','ꃅ'=>'ꃅ','ꃆ'=>'ꃆ','ꃇ'=>'ꃇ','ꃈ'=>'ꃈ','ꃉ'=>'ꃉ','ꃊ'=>'ꃊ','ꃋ'=>'ꃋ','ꃌ'=>'ꃌ','ꃍ'=>'ꃍ','ꃎ'=>'ꃎ','ꃏ'=>'ꃏ','ꃐ'=>'ꃐ','ꃑ'=>'ꃑ','ꃒ'=>'ꃒ','ꃓ'=>'ꃓ','ꃔ'=>'ꃔ','ꃕ'=>'ꃕ','ꃖ'=>'ꃖ','ꃗ'=>'ꃗ','ꃘ'=>'ꃘ','ꃙ'=>'ꃙ','ꃚ'=>'ꃚ','ꃛ'=>'ꃛ','ꃜ'=>'ꃜ','ꃝ'=>'ꃝ','ꃞ'=>'ꃞ','ꃟ'=>'ꃟ','ꃠ'=>'ꃠ','ꃡ'=>'ꃡ','ꃢ'=>'ꃢ','ꃣ'=>'ꃣ','ꃤ'=>'ꃤ','ꃥ'=>'ꃥ','ꃦ'=>'ꃦ','ꃧ'=>'ꃧ','ꃨ'=>'ꃨ','ꃩ'=>'ꃩ','ꃪ'=>'ꃪ','ꃫ'=>'ꃫ','ꃬ'=>'ꃬ','ꃭ'=>'ꃭ','ꃮ'=>'ꃮ','ꃯ'=>'ꃯ','ꃰ'=>'ꃰ','ꃱ'=>'ꃱ','ꃲ'=>'ꃲ','ꃳ'=>'ꃳ','ꃴ'=>'ꃴ','ꃵ'=>'ꃵ','ꃶ'=>'ꃶ','ꃷ'=>'ꃷ','ꃸ'=>'ꃸ','ꃹ'=>'ꃹ','ꃺ'=>'ꃺ','ꃻ'=>'ꃻ','ꃼ'=>'ꃼ','ꃽ'=>'ꃽ','ꃾ'=>'ꃾ','ꃿ'=>'ꃿ','ꄀ'=>'ꄀ','ꄁ'=>'ꄁ','ꄂ'=>'ꄂ','ꄃ'=>'ꄃ','ꄄ'=>'ꄄ','ꄅ'=>'ꄅ','ꄆ'=>'ꄆ','ꄇ'=>'ꄇ','ꄈ'=>'ꄈ','ꄉ'=>'ꄉ','ꄊ'=>'ꄊ','ꄋ'=>'ꄋ','ꄌ'=>'ꄌ','ꄍ'=>'ꄍ','ꄎ'=>'ꄎ','ꄏ'=>'ꄏ','ꄐ'=>'ꄐ','ꄑ'=>'ꄑ','ꄒ'=>'ꄒ','ꄓ'=>'ꄓ','ꄔ'=>'ꄔ','ꄕ'=>'ꄕ','ꄖ'=>'ꄖ','ꄗ'=>'ꄗ','ꄘ'=>'ꄘ','ꄙ'=>'ꄙ','ꄚ'=>'ꄚ','ꄛ'=>'ꄛ','ꄜ'=>'ꄜ','ꄝ'=>'ꄝ','ꄞ'=>'ꄞ','ꄟ'=>'ꄟ','ꄠ'=>'ꄠ','ꄡ'=>'ꄡ','ꄢ'=>'ꄢ','ꄣ'=>'ꄣ','ꄤ'=>'ꄤ','ꄥ'=>'ꄥ','ꄦ'=>'ꄦ','ꄧ'=>'ꄧ','ꄨ'=>'ꄨ','ꄩ'=>'ꄩ','ꄪ'=>'ꄪ','ꄫ'=>'ꄫ','ꄬ'=>'ꄬ','ꄭ'=>'ꄭ','ꄮ'=>'ꄮ','ꄯ'=>'ꄯ','ꄰ'=>'ꄰ','ꄱ'=>'ꄱ','ꄲ'=>'ꄲ','ꄳ'=>'ꄳ','ꄴ'=>'ꄴ','ꄵ'=>'ꄵ','ꄶ'=>'ꄶ','ꄷ'=>'ꄷ','ꄸ'=>'ꄸ','ꄹ'=>'ꄹ','ꄺ'=>'ꄺ','ꄻ'=>'ꄻ','ꄼ'=>'ꄼ','ꄽ'=>'ꄽ','ꄾ'=>'ꄾ','ꄿ'=>'ꄿ','ꅀ'=>'ꅀ','ꅁ'=>'ꅁ','ꅂ'=>'ꅂ','ꅃ'=>'ꅃ','ꅄ'=>'ꅄ','ꅅ'=>'ꅅ','ꅆ'=>'ꅆ','ꅇ'=>'ꅇ','ꅈ'=>'ꅈ','ꅉ'=>'ꅉ','ꅊ'=>'ꅊ','ꅋ'=>'ꅋ','ꅌ'=>'ꅌ','ꅍ'=>'ꅍ','ꅎ'=>'ꅎ','ꅏ'=>'ꅏ','ꅐ'=>'ꅐ','ꅑ'=>'ꅑ','ꅒ'=>'ꅒ','ꅓ'=>'ꅓ','ꅔ'=>'ꅔ','ꅕ'=>'ꅕ','ꅖ'=>'ꅖ','ꅗ'=>'ꅗ','ꅘ'=>'ꅘ','ꅙ'=>'ꅙ','ꅚ'=>'ꅚ','ꅛ'=>'ꅛ','ꅜ'=>'ꅜ','ꅝ'=>'ꅝ','ꅞ'=>'ꅞ','ꅟ'=>'ꅟ','ꅠ'=>'ꅠ','ꅡ'=>'ꅡ','ꅢ'=>'ꅢ','ꅣ'=>'ꅣ','ꅤ'=>'ꅤ','ꅥ'=>'ꅥ','ꅦ'=>'ꅦ','ꅧ'=>'ꅧ','ꅨ'=>'ꅨ','ꅩ'=>'ꅩ','ꅪ'=>'ꅪ','ꅫ'=>'ꅫ','ꅬ'=>'ꅬ','ꅭ'=>'ꅭ','ꅮ'=>'ꅮ','ꅯ'=>'ꅯ','ꅰ'=>'ꅰ','ꅱ'=>'ꅱ','ꅲ'=>'ꅲ','ꅳ'=>'ꅳ','ꅴ'=>'ꅴ','ꅵ'=>'ꅵ','ꅶ'=>'ꅶ','ꅷ'=>'ꅷ','ꅸ'=>'ꅸ','ꅹ'=>'ꅹ','ꅺ'=>'ꅺ','ꅻ'=>'ꅻ','ꅼ'=>'ꅼ','ꅽ'=>'ꅽ','ꅾ'=>'ꅾ','ꅿ'=>'ꅿ','ꆀ'=>'ꆀ','ꆁ'=>'ꆁ','ꆂ'=>'ꆂ','ꆃ'=>'ꆃ','ꆄ'=>'ꆄ','ꆅ'=>'ꆅ','ꆆ'=>'ꆆ','ꆇ'=>'ꆇ','ꆈ'=>'ꆈ','ꆉ'=>'ꆉ','ꆊ'=>'ꆊ','ꆋ'=>'ꆋ','ꆌ'=>'ꆌ','ꆍ'=>'ꆍ','ꆎ'=>'ꆎ','ꆏ'=>'ꆏ','ꆐ'=>'ꆐ','ꆑ'=>'ꆑ','ꆒ'=>'ꆒ','ꆓ'=>'ꆓ','ꆔ'=>'ꆔ','ꆕ'=>'ꆕ','ꆖ'=>'ꆖ','ꆗ'=>'ꆗ','ꆘ'=>'ꆘ','ꆙ'=>'ꆙ','ꆚ'=>'ꆚ','ꆛ'=>'ꆛ','ꆜ'=>'ꆜ','ꆝ'=>'ꆝ','ꆞ'=>'ꆞ','ꆟ'=>'ꆟ','ꆠ'=>'ꆠ','ꆡ'=>'ꆡ','ꆢ'=>'ꆢ','ꆣ'=>'ꆣ','ꆤ'=>'ꆤ','ꆥ'=>'ꆥ','ꆦ'=>'ꆦ','ꆧ'=>'ꆧ','ꆨ'=>'ꆨ','ꆩ'=>'ꆩ','ꆪ'=>'ꆪ','ꆫ'=>'ꆫ','ꆬ'=>'ꆬ','ꆭ'=>'ꆭ','ꆮ'=>'ꆮ','ꆯ'=>'ꆯ','ꆰ'=>'ꆰ','ꆱ'=>'ꆱ','ꆲ'=>'ꆲ','ꆳ'=>'ꆳ','ꆴ'=>'ꆴ','ꆵ'=>'ꆵ','ꆶ'=>'ꆶ','ꆷ'=>'ꆷ','ꆸ'=>'ꆸ','ꆹ'=>'ꆹ','ꆺ'=>'ꆺ','ꆻ'=>'ꆻ','ꆼ'=>'ꆼ','ꆽ'=>'ꆽ','ꆾ'=>'ꆾ','ꆿ'=>'ꆿ','ꇀ'=>'ꇀ','ꇁ'=>'ꇁ','ꇂ'=>'ꇂ','ꇃ'=>'ꇃ','ꇄ'=>'ꇄ','ꇅ'=>'ꇅ','ꇆ'=>'ꇆ','ꇇ'=>'ꇇ','ꇈ'=>'ꇈ','ꇉ'=>'ꇉ','ꇊ'=>'ꇊ','ꇋ'=>'ꇋ','ꇌ'=>'ꇌ','ꇍ'=>'ꇍ','ꇎ'=>'ꇎ','ꇏ'=>'ꇏ','ꇐ'=>'ꇐ','ꇑ'=>'ꇑ','ꇒ'=>'ꇒ','ꇓ'=>'ꇓ','ꇔ'=>'ꇔ','ꇕ'=>'ꇕ','ꇖ'=>'ꇖ','ꇗ'=>'ꇗ','ꇘ'=>'ꇘ','ꇙ'=>'ꇙ','ꇚ'=>'ꇚ','ꇛ'=>'ꇛ','ꇜ'=>'ꇜ','ꇝ'=>'ꇝ','ꇞ'=>'ꇞ','ꇟ'=>'ꇟ','ꇠ'=>'ꇠ','ꇡ'=>'ꇡ','ꇢ'=>'ꇢ','ꇣ'=>'ꇣ','ꇤ'=>'ꇤ','ꇥ'=>'ꇥ','ꇦ'=>'ꇦ','ꇧ'=>'ꇧ','ꇨ'=>'ꇨ','ꇩ'=>'ꇩ','ꇪ'=>'ꇪ','ꇫ'=>'ꇫ','ꇬ'=>'ꇬ','ꇭ'=>'ꇭ','ꇮ'=>'ꇮ','ꇯ'=>'ꇯ','ꇰ'=>'ꇰ','ꇱ'=>'ꇱ','ꇲ'=>'ꇲ','ꇳ'=>'ꇳ','ꇴ'=>'ꇴ','ꇵ'=>'ꇵ','ꇶ'=>'ꇶ','ꇷ'=>'ꇷ','ꇸ'=>'ꇸ','ꇹ'=>'ꇹ','ꇺ'=>'ꇺ','ꇻ'=>'ꇻ','ꇼ'=>'ꇼ','ꇽ'=>'ꇽ','ꇾ'=>'ꇾ','ꇿ'=>'ꇿ','ꈀ'=>'ꈀ','ꈁ'=>'ꈁ','ꈂ'=>'ꈂ','ꈃ'=>'ꈃ','ꈄ'=>'ꈄ','ꈅ'=>'ꈅ','ꈆ'=>'ꈆ','ꈇ'=>'ꈇ','ꈈ'=>'ꈈ','ꈉ'=>'ꈉ','ꈊ'=>'ꈊ','ꈋ'=>'ꈋ','ꈌ'=>'ꈌ','ꈍ'=>'ꈍ','ꈎ'=>'ꈎ','ꈏ'=>'ꈏ','ꈐ'=>'ꈐ','ꈑ'=>'ꈑ','ꈒ'=>'ꈒ','ꈓ'=>'ꈓ','ꈔ'=>'ꈔ','ꈕ'=>'ꈕ','ꈖ'=>'ꈖ','ꈗ'=>'ꈗ','ꈘ'=>'ꈘ','ꈙ'=>'ꈙ','ꈚ'=>'ꈚ','ꈛ'=>'ꈛ','ꈜ'=>'ꈜ','ꈝ'=>'ꈝ','ꈞ'=>'ꈞ','ꈟ'=>'ꈟ','ꈠ'=>'ꈠ','ꈡ'=>'ꈡ','ꈢ'=>'ꈢ','ꈣ'=>'ꈣ','ꈤ'=>'ꈤ','ꈥ'=>'ꈥ','ꈦ'=>'ꈦ','ꈧ'=>'ꈧ','ꈨ'=>'ꈨ','ꈩ'=>'ꈩ','ꈪ'=>'ꈪ','ꈫ'=>'ꈫ','ꈬ'=>'ꈬ','ꈭ'=>'ꈭ','ꈮ'=>'ꈮ','ꈯ'=>'ꈯ','ꈰ'=>'ꈰ','ꈱ'=>'ꈱ','ꈲ'=>'ꈲ','ꈳ'=>'ꈳ','ꈴ'=>'ꈴ','ꈵ'=>'ꈵ','ꈶ'=>'ꈶ','ꈷ'=>'ꈷ','ꈸ'=>'ꈸ','ꈹ'=>'ꈹ','ꈺ'=>'ꈺ','ꈻ'=>'ꈻ','ꈼ'=>'ꈼ','ꈽ'=>'ꈽ','ꈾ'=>'ꈾ','ꈿ'=>'ꈿ','ꉀ'=>'ꉀ','ꉁ'=>'ꉁ','ꉂ'=>'ꉂ','ꉃ'=>'ꉃ','ꉄ'=>'ꉄ','ꉅ'=>'ꉅ','ꉆ'=>'ꉆ','ꉇ'=>'ꉇ','ꉈ'=>'ꉈ','ꉉ'=>'ꉉ','ꉊ'=>'ꉊ','ꉋ'=>'ꉋ','ꉌ'=>'ꉌ','ꉍ'=>'ꉍ','ꉎ'=>'ꉎ','ꉏ'=>'ꉏ','ꉐ'=>'ꉐ','ꉑ'=>'ꉑ','ꉒ'=>'ꉒ','ꉓ'=>'ꉓ','ꉔ'=>'ꉔ','ꉕ'=>'ꉕ','ꉖ'=>'ꉖ','ꉗ'=>'ꉗ','ꉘ'=>'ꉘ','ꉙ'=>'ꉙ','ꉚ'=>'ꉚ','ꉛ'=>'ꉛ','ꉜ'=>'ꉜ','ꉝ'=>'ꉝ','ꉞ'=>'ꉞ','ꉟ'=>'ꉟ','ꉠ'=>'ꉠ','ꉡ'=>'ꉡ','ꉢ'=>'ꉢ','ꉣ'=>'ꉣ','ꉤ'=>'ꉤ','ꉥ'=>'ꉥ','ꉦ'=>'ꉦ','ꉧ'=>'ꉧ','ꉨ'=>'ꉨ','ꉩ'=>'ꉩ','ꉪ'=>'ꉪ','ꉫ'=>'ꉫ','ꉬ'=>'ꉬ','ꉭ'=>'ꉭ','ꉮ'=>'ꉮ','ꉯ'=>'ꉯ','ꉰ'=>'ꉰ','ꉱ'=>'ꉱ','ꉲ'=>'ꉲ','ꉳ'=>'ꉳ','ꉴ'=>'ꉴ','ꉵ'=>'ꉵ','ꉶ'=>'ꉶ','ꉷ'=>'ꉷ','ꉸ'=>'ꉸ','ꉹ'=>'ꉹ','ꉺ'=>'ꉺ','ꉻ'=>'ꉻ','ꉼ'=>'ꉼ','ꉽ'=>'ꉽ','ꉾ'=>'ꉾ','ꉿ'=>'ꉿ','ꊀ'=>'ꊀ','ꊁ'=>'ꊁ','ꊂ'=>'ꊂ','ꊃ'=>'ꊃ','ꊄ'=>'ꊄ','ꊅ'=>'ꊅ','ꊆ'=>'ꊆ','ꊇ'=>'ꊇ','ꊈ'=>'ꊈ','ꊉ'=>'ꊉ','ꊊ'=>'ꊊ','ꊋ'=>'ꊋ','ꊌ'=>'ꊌ','ꊍ'=>'ꊍ','ꊎ'=>'ꊎ','ꊏ'=>'ꊏ','ꊐ'=>'ꊐ','ꊑ'=>'ꊑ','ꊒ'=>'ꊒ','ꊓ'=>'ꊓ','ꊔ'=>'ꊔ','ꊕ'=>'ꊕ','ꊖ'=>'ꊖ','ꊗ'=>'ꊗ','ꊘ'=>'ꊘ','ꊙ'=>'ꊙ','ꊚ'=>'ꊚ','ꊛ'=>'ꊛ','ꊜ'=>'ꊜ','ꊝ'=>'ꊝ','ꊞ'=>'ꊞ','ꊟ'=>'ꊟ','ꊠ'=>'ꊠ','ꊡ'=>'ꊡ','ꊢ'=>'ꊢ','ꊣ'=>'ꊣ','ꊤ'=>'ꊤ','ꊥ'=>'ꊥ','ꊦ'=>'ꊦ','ꊧ'=>'ꊧ','ꊨ'=>'ꊨ','ꊩ'=>'ꊩ','ꊪ'=>'ꊪ','ꊫ'=>'ꊫ','ꊬ'=>'ꊬ','ꊭ'=>'ꊭ','ꊮ'=>'ꊮ','ꊯ'=>'ꊯ','ꊰ'=>'ꊰ','ꊱ'=>'ꊱ','ꊲ'=>'ꊲ','ꊳ'=>'ꊳ','ꊴ'=>'ꊴ','ꊵ'=>'ꊵ','ꊶ'=>'ꊶ','ꊷ'=>'ꊷ','ꊸ'=>'ꊸ','ꊹ'=>'ꊹ','ꊺ'=>'ꊺ','ꊻ'=>'ꊻ','ꊼ'=>'ꊼ','ꊽ'=>'ꊽ','ꊾ'=>'ꊾ','ꊿ'=>'ꊿ','ꋀ'=>'ꋀ','ꋁ'=>'ꋁ','ꋂ'=>'ꋂ','ꋃ'=>'ꋃ','ꋄ'=>'ꋄ','ꋅ'=>'ꋅ','ꋆ'=>'ꋆ','ꋇ'=>'ꋇ','ꋈ'=>'ꋈ','ꋉ'=>'ꋉ','ꋊ'=>'ꋊ','ꋋ'=>'ꋋ','ꋌ'=>'ꋌ','ꋍ'=>'ꋍ','ꋎ'=>'ꋎ','ꋏ'=>'ꋏ','ꋐ'=>'ꋐ','ꋑ'=>'ꋑ','ꋒ'=>'ꋒ','ꋓ'=>'ꋓ','ꋔ'=>'ꋔ','ꋕ'=>'ꋕ','ꋖ'=>'ꋖ','ꋗ'=>'ꋗ','ꋘ'=>'ꋘ','ꋙ'=>'ꋙ','ꋚ'=>'ꋚ','ꋛ'=>'ꋛ','ꋜ'=>'ꋜ','ꋝ'=>'ꋝ','ꋞ'=>'ꋞ','ꋟ'=>'ꋟ','ꋠ'=>'ꋠ','ꋡ'=>'ꋡ','ꋢ'=>'ꋢ','ꋣ'=>'ꋣ','ꋤ'=>'ꋤ','ꋥ'=>'ꋥ','ꋦ'=>'ꋦ','ꋧ'=>'ꋧ','ꋨ'=>'ꋨ','ꋩ'=>'ꋩ','ꋪ'=>'ꋪ','ꋫ'=>'ꋫ','ꋬ'=>'ꋬ','ꋭ'=>'ꋭ','ꋮ'=>'ꋮ','ꋯ'=>'ꋯ','ꋰ'=>'ꋰ','ꋱ'=>'ꋱ','ꋲ'=>'ꋲ','ꋳ'=>'ꋳ','ꋴ'=>'ꋴ','ꋵ'=>'ꋵ','ꋶ'=>'ꋶ','ꋷ'=>'ꋷ','ꋸ'=>'ꋸ','ꋹ'=>'ꋹ','ꋺ'=>'ꋺ','ꋻ'=>'ꋻ','ꋼ'=>'ꋼ','ꋽ'=>'ꋽ','ꋾ'=>'ꋾ','ꋿ'=>'ꋿ','ꌀ'=>'ꌀ','ꌁ'=>'ꌁ','ꌂ'=>'ꌂ','ꌃ'=>'ꌃ','ꌄ'=>'ꌄ','ꌅ'=>'ꌅ','ꌆ'=>'ꌆ','ꌇ'=>'ꌇ','ꌈ'=>'ꌈ','ꌉ'=>'ꌉ','ꌊ'=>'ꌊ','ꌋ'=>'ꌋ','ꌌ'=>'ꌌ','ꌍ'=>'ꌍ','ꌎ'=>'ꌎ','ꌏ'=>'ꌏ','ꌐ'=>'ꌐ','ꌑ'=>'ꌑ','ꌒ'=>'ꌒ','ꌓ'=>'ꌓ','ꌔ'=>'ꌔ','ꌕ'=>'ꌕ','ꌖ'=>'ꌖ','ꌗ'=>'ꌗ','ꌘ'=>'ꌘ','ꌙ'=>'ꌙ','ꌚ'=>'ꌚ','ꌛ'=>'ꌛ','ꌜ'=>'ꌜ','ꌝ'=>'ꌝ','ꌞ'=>'ꌞ','ꌟ'=>'ꌟ','ꌠ'=>'ꌠ','ꌡ'=>'ꌡ','ꌢ'=>'ꌢ','ꌣ'=>'ꌣ','ꌤ'=>'ꌤ','ꌥ'=>'ꌥ','ꌦ'=>'ꌦ','ꌧ'=>'ꌧ','ꌨ'=>'ꌨ','ꌩ'=>'ꌩ','ꌪ'=>'ꌪ','ꌫ'=>'ꌫ','ꌬ'=>'ꌬ','ꌭ'=>'ꌭ','ꌮ'=>'ꌮ','ꌯ'=>'ꌯ','ꌰ'=>'ꌰ','ꌱ'=>'ꌱ','ꌲ'=>'ꌲ','ꌳ'=>'ꌳ','ꌴ'=>'ꌴ','ꌵ'=>'ꌵ','ꌶ'=>'ꌶ','ꌷ'=>'ꌷ','ꌸ'=>'ꌸ','ꌹ'=>'ꌹ','ꌺ'=>'ꌺ','ꌻ'=>'ꌻ','ꌼ'=>'ꌼ','ꌽ'=>'ꌽ','ꌾ'=>'ꌾ','ꌿ'=>'ꌿ','ꍀ'=>'ꍀ','ꍁ'=>'ꍁ','ꍂ'=>'ꍂ','ꍃ'=>'ꍃ','ꍄ'=>'ꍄ','ꍅ'=>'ꍅ','ꍆ'=>'ꍆ','ꍇ'=>'ꍇ','ꍈ'=>'ꍈ','ꍉ'=>'ꍉ','ꍊ'=>'ꍊ','ꍋ'=>'ꍋ','ꍌ'=>'ꍌ','ꍍ'=>'ꍍ','ꍎ'=>'ꍎ','ꍏ'=>'ꍏ','ꍐ'=>'ꍐ','ꍑ'=>'ꍑ','ꍒ'=>'ꍒ','ꍓ'=>'ꍓ','ꍔ'=>'ꍔ','ꍕ'=>'ꍕ','ꍖ'=>'ꍖ','ꍗ'=>'ꍗ','ꍘ'=>'ꍘ','ꍙ'=>'ꍙ','ꍚ'=>'ꍚ','ꍛ'=>'ꍛ','ꍜ'=>'ꍜ','ꍝ'=>'ꍝ','ꍞ'=>'ꍞ','ꍟ'=>'ꍟ','ꍠ'=>'ꍠ','ꍡ'=>'ꍡ','ꍢ'=>'ꍢ','ꍣ'=>'ꍣ','ꍤ'=>'ꍤ','ꍥ'=>'ꍥ','ꍦ'=>'ꍦ','ꍧ'=>'ꍧ','ꍨ'=>'ꍨ','ꍩ'=>'ꍩ','ꍪ'=>'ꍪ','ꍫ'=>'ꍫ','ꍬ'=>'ꍬ','ꍭ'=>'ꍭ','ꍮ'=>'ꍮ','ꍯ'=>'ꍯ','ꍰ'=>'ꍰ','ꍱ'=>'ꍱ','ꍲ'=>'ꍲ','ꍳ'=>'ꍳ','ꍴ'=>'ꍴ','ꍵ'=>'ꍵ','ꍶ'=>'ꍶ','ꍷ'=>'ꍷ','ꍸ'=>'ꍸ','ꍹ'=>'ꍹ','ꍺ'=>'ꍺ','ꍻ'=>'ꍻ','ꍼ'=>'ꍼ','ꍽ'=>'ꍽ','ꍾ'=>'ꍾ','ꍿ'=>'ꍿ','ꎀ'=>'ꎀ','ꎁ'=>'ꎁ','ꎂ'=>'ꎂ','ꎃ'=>'ꎃ','ꎄ'=>'ꎄ','ꎅ'=>'ꎅ','ꎆ'=>'ꎆ','ꎇ'=>'ꎇ','ꎈ'=>'ꎈ','ꎉ'=>'ꎉ','ꎊ'=>'ꎊ','ꎋ'=>'ꎋ','ꎌ'=>'ꎌ','ꎍ'=>'ꎍ','ꎎ'=>'ꎎ','ꎏ'=>'ꎏ','ꎐ'=>'ꎐ','ꎑ'=>'ꎑ','ꎒ'=>'ꎒ','ꎓ'=>'ꎓ','ꎔ'=>'ꎔ','ꎕ'=>'ꎕ','ꎖ'=>'ꎖ','ꎗ'=>'ꎗ','ꎘ'=>'ꎘ','ꎙ'=>'ꎙ','ꎚ'=>'ꎚ','ꎛ'=>'ꎛ','ꎜ'=>'ꎜ','ꎝ'=>'ꎝ','ꎞ'=>'ꎞ','ꎟ'=>'ꎟ','ꎠ'=>'ꎠ','ꎡ'=>'ꎡ','ꎢ'=>'ꎢ','ꎣ'=>'ꎣ','ꎤ'=>'ꎤ','ꎥ'=>'ꎥ','ꎦ'=>'ꎦ','ꎧ'=>'ꎧ','ꎨ'=>'ꎨ','ꎩ'=>'ꎩ','ꎪ'=>'ꎪ','ꎫ'=>'ꎫ','ꎬ'=>'ꎬ','ꎭ'=>'ꎭ','ꎮ'=>'ꎮ','ꎯ'=>'ꎯ','ꎰ'=>'ꎰ','ꎱ'=>'ꎱ','ꎲ'=>'ꎲ','ꎳ'=>'ꎳ','ꎴ'=>'ꎴ','ꎵ'=>'ꎵ','ꎶ'=>'ꎶ','ꎷ'=>'ꎷ','ꎸ'=>'ꎸ','ꎹ'=>'ꎹ','ꎺ'=>'ꎺ','ꎻ'=>'ꎻ','ꎼ'=>'ꎼ','ꎽ'=>'ꎽ','ꎾ'=>'ꎾ','ꎿ'=>'ꎿ','ꏀ'=>'ꏀ','ꏁ'=>'ꏁ','ꏂ'=>'ꏂ','ꏃ'=>'ꏃ','ꏄ'=>'ꏄ','ꏅ'=>'ꏅ','ꏆ'=>'ꏆ','ꏇ'=>'ꏇ','ꏈ'=>'ꏈ','ꏉ'=>'ꏉ','ꏊ'=>'ꏊ','ꏋ'=>'ꏋ','ꏌ'=>'ꏌ','ꏍ'=>'ꏍ','ꏎ'=>'ꏎ','ꏏ'=>'ꏏ','ꏐ'=>'ꏐ','ꏑ'=>'ꏑ','ꏒ'=>'ꏒ','ꏓ'=>'ꏓ','ꏔ'=>'ꏔ','ꏕ'=>'ꏕ','ꏖ'=>'ꏖ','ꏗ'=>'ꏗ','ꏘ'=>'ꏘ','ꏙ'=>'ꏙ','ꏚ'=>'ꏚ','ꏛ'=>'ꏛ','ꏜ'=>'ꏜ','ꏝ'=>'ꏝ','ꏞ'=>'ꏞ','ꏟ'=>'ꏟ','ꏠ'=>'ꏠ','ꏡ'=>'ꏡ','ꏢ'=>'ꏢ','ꏣ'=>'ꏣ','ꏤ'=>'ꏤ','ꏥ'=>'ꏥ','ꏦ'=>'ꏦ','ꏧ'=>'ꏧ','ꏨ'=>'ꏨ','ꏩ'=>'ꏩ','ꏪ'=>'ꏪ','ꏫ'=>'ꏫ','ꏬ'=>'ꏬ','ꏭ'=>'ꏭ','ꏮ'=>'ꏮ','ꏯ'=>'ꏯ','ꏰ'=>'ꏰ','ꏱ'=>'ꏱ','ꏲ'=>'ꏲ','ꏳ'=>'ꏳ','ꏴ'=>'ꏴ','ꏵ'=>'ꏵ','ꏶ'=>'ꏶ','ꏷ'=>'ꏷ','ꏸ'=>'ꏸ','ꏹ'=>'ꏹ','ꏺ'=>'ꏺ','ꏻ'=>'ꏻ','ꏼ'=>'ꏼ','ꏽ'=>'ꏽ','ꏾ'=>'ꏾ','ꏿ'=>'ꏿ','ꐀ'=>'ꐀ','ꐁ'=>'ꐁ','ꐂ'=>'ꐂ','ꐃ'=>'ꐃ','ꐄ'=>'ꐄ','ꐅ'=>'ꐅ','ꐆ'=>'ꐆ','ꐇ'=>'ꐇ','ꐈ'=>'ꐈ','ꐉ'=>'ꐉ','ꐊ'=>'ꐊ','ꐋ'=>'ꐋ','ꐌ'=>'ꐌ','ꐍ'=>'ꐍ','ꐎ'=>'ꐎ','ꐏ'=>'ꐏ','ꐐ'=>'ꐐ','ꐑ'=>'ꐑ','ꐒ'=>'ꐒ','ꐓ'=>'ꐓ','ꐔ'=>'ꐔ','ꐕ'=>'ꐕ','ꐖ'=>'ꐖ','ꐗ'=>'ꐗ','ꐘ'=>'ꐘ','ꐙ'=>'ꐙ','ꐚ'=>'ꐚ','ꐛ'=>'ꐛ','ꐜ'=>'ꐜ','ꐝ'=>'ꐝ','ꐞ'=>'ꐞ','ꐟ'=>'ꐟ','ꐠ'=>'ꐠ','ꐡ'=>'ꐡ','ꐢ'=>'ꐢ','ꐣ'=>'ꐣ','ꐤ'=>'ꐤ','ꐥ'=>'ꐥ','ꐦ'=>'ꐦ','ꐧ'=>'ꐧ','ꐨ'=>'ꐨ','ꐩ'=>'ꐩ','ꐪ'=>'ꐪ','ꐫ'=>'ꐫ','ꐬ'=>'ꐬ','ꐭ'=>'ꐭ','ꐮ'=>'ꐮ','ꐯ'=>'ꐯ','ꐰ'=>'ꐰ','ꐱ'=>'ꐱ','ꐲ'=>'ꐲ','ꐳ'=>'ꐳ','ꐴ'=>'ꐴ','ꐵ'=>'ꐵ','ꐶ'=>'ꐶ','ꐷ'=>'ꐷ','ꐸ'=>'ꐸ','ꐹ'=>'ꐹ','ꐺ'=>'ꐺ','ꐻ'=>'ꐻ','ꐼ'=>'ꐼ','ꐽ'=>'ꐽ','ꐾ'=>'ꐾ','ꐿ'=>'ꐿ','ꑀ'=>'ꑀ','ꑁ'=>'ꑁ','ꑂ'=>'ꑂ','ꑃ'=>'ꑃ','ꑄ'=>'ꑄ','ꑅ'=>'ꑅ','ꑆ'=>'ꑆ','ꑇ'=>'ꑇ','ꑈ'=>'ꑈ','ꑉ'=>'ꑉ','ꑊ'=>'ꑊ','ꑋ'=>'ꑋ','ꑌ'=>'ꑌ','ꑍ'=>'ꑍ','ꑎ'=>'ꑎ','ꑏ'=>'ꑏ','ꑐ'=>'ꑐ','ꑑ'=>'ꑑ','ꑒ'=>'ꑒ','ꑓ'=>'ꑓ','ꑔ'=>'ꑔ','ꑕ'=>'ꑕ','ꑖ'=>'ꑖ','ꑗ'=>'ꑗ','ꑘ'=>'ꑘ','ꑙ'=>'ꑙ','ꑚ'=>'ꑚ','ꑛ'=>'ꑛ','ꑜ'=>'ꑜ','ꑝ'=>'ꑝ','ꑞ'=>'ꑞ','ꑟ'=>'ꑟ','ꑠ'=>'ꑠ','ꑡ'=>'ꑡ','ꑢ'=>'ꑢ','ꑣ'=>'ꑣ','ꑤ'=>'ꑤ','ꑥ'=>'ꑥ','ꑦ'=>'ꑦ','ꑧ'=>'ꑧ','ꑨ'=>'ꑨ','ꑩ'=>'ꑩ','ꑪ'=>'ꑪ','ꑫ'=>'ꑫ','ꑬ'=>'ꑬ','ꑭ'=>'ꑭ','ꑮ'=>'ꑮ','ꑯ'=>'ꑯ','ꑰ'=>'ꑰ','ꑱ'=>'ꑱ','ꑲ'=>'ꑲ','ꑳ'=>'ꑳ','ꑴ'=>'ꑴ','ꑵ'=>'ꑵ','ꑶ'=>'ꑶ','ꑷ'=>'ꑷ','ꑸ'=>'ꑸ','ꑹ'=>'ꑹ','ꑺ'=>'ꑺ','ꑻ'=>'ꑻ','ꑼ'=>'ꑼ','ꑽ'=>'ꑽ','ꑾ'=>'ꑾ','ꑿ'=>'ꑿ','ꒀ'=>'ꒀ','ꒁ'=>'ꒁ','ꒂ'=>'ꒂ','ꒃ'=>'ꒃ','ꒄ'=>'ꒄ','ꒅ'=>'ꒅ','ꒆ'=>'ꒆ','ꒇ'=>'ꒇ','ꒈ'=>'ꒈ','ꒉ'=>'ꒉ','ꒊ'=>'ꒊ','ꒋ'=>'ꒋ','ꒌ'=>'ꒌ','ꜗ'=>'ꜗ','ꜘ'=>'ꜘ','ꜙ'=>'ꜙ','ꜚ'=>'ꜚ'); diff --git a/phpBB/includes/utf/data/search_indexer_21.php b/phpBB/includes/utf/data/search_indexer_21.php index 7fc3e4dc09..34994b47d7 100644 --- a/phpBB/includes/utf/data/search_indexer_21.php +++ b/phpBB/includes/utf/data/search_indexer_21.php @@ -1 +1 @@ -<?php return array('ꠀ'=>'ꠀ','ꠁ'=>'ꠁ','ꠂ'=>'ꠂ','ꠃ'=>'ꠃ','ꠄ'=>'ꠄ','ꠅ'=>'ꠅ','꠆'=>'꠆','ꠇ'=>'ꠇ','ꠈ'=>'ꠈ','ꠉ'=>'ꠉ','ꠊ'=>'ꠊ','ꠋ'=>'ꠋ','ꠌ'=>'ꠌ','ꠍ'=>'ꠍ','ꠎ'=>'ꠎ','ꠏ'=>'ꠏ','ꠐ'=>'ꠐ','ꠑ'=>'ꠑ','ꠒ'=>'ꠒ','ꠓ'=>'ꠓ','ꠔ'=>'ꠔ','ꠕ'=>'ꠕ','ꠖ'=>'ꠖ','ꠗ'=>'ꠗ','ꠘ'=>'ꠘ','ꠙ'=>'ꠙ','ꠚ'=>'ꠚ','ꠛ'=>'ꠛ','ꠜ'=>'ꠜ','ꠝ'=>'ꠝ','ꠞ'=>'ꠞ','ꠟ'=>'ꠟ','ꠠ'=>'ꠠ','ꠡ'=>'ꠡ','ꠢ'=>'ꠢ','ꠣ'=>'ꠣ','ꠤ'=>'ꠤ','ꠥ'=>'ꠥ','ꠦ'=>'ꠦ','ꠧ'=>'ꠧ','ꡀ'=>'ꡀ','ꡁ'=>'ꡁ','ꡂ'=>'ꡂ','ꡃ'=>'ꡃ','ꡄ'=>'ꡄ','ꡅ'=>'ꡅ','ꡆ'=>'ꡆ','ꡇ'=>'ꡇ','ꡈ'=>'ꡈ','ꡉ'=>'ꡉ','ꡊ'=>'ꡊ','ꡋ'=>'ꡋ','ꡌ'=>'ꡌ','ꡍ'=>'ꡍ','ꡎ'=>'ꡎ','ꡏ'=>'ꡏ','ꡐ'=>'ꡐ','ꡑ'=>'ꡑ','ꡒ'=>'ꡒ','ꡓ'=>'ꡓ','ꡔ'=>'ꡔ','ꡕ'=>'ꡕ','ꡖ'=>'ꡖ','ꡗ'=>'ꡗ','ꡘ'=>'ꡘ','ꡙ'=>'ꡙ','ꡚ'=>'ꡚ','ꡛ'=>'ꡛ','ꡜ'=>'ꡜ','ꡝ'=>'ꡝ','ꡞ'=>'ꡞ','ꡟ'=>'ꡟ','ꡠ'=>'ꡠ','ꡡ'=>'ꡡ','ꡢ'=>'ꡢ','ꡣ'=>'ꡣ','ꡤ'=>'ꡤ','ꡥ'=>'ꡥ','ꡦ'=>'ꡦ','ꡧ'=>'ꡧ','ꡨ'=>'ꡨ','ꡩ'=>'ꡩ','ꡪ'=>'ꡪ','ꡫ'=>'ꡫ','ꡬ'=>'ꡬ','ꡭ'=>'ꡭ','ꡮ'=>'ꡮ','ꡯ'=>'ꡯ','ꡰ'=>'ꡰ','ꡱ'=>'ꡱ','ꡲ'=>'ꡲ','ꡳ'=>'ꡳ','가'=>'가');
\ No newline at end of file +<?php return array('ꠀ'=>'ꠀ','ꠁ'=>'ꠁ','ꠂ'=>'ꠂ','ꠃ'=>'ꠃ','ꠄ'=>'ꠄ','ꠅ'=>'ꠅ','꠆'=>'꠆','ꠇ'=>'ꠇ','ꠈ'=>'ꠈ','ꠉ'=>'ꠉ','ꠊ'=>'ꠊ','ꠋ'=>'ꠋ','ꠌ'=>'ꠌ','ꠍ'=>'ꠍ','ꠎ'=>'ꠎ','ꠏ'=>'ꠏ','ꠐ'=>'ꠐ','ꠑ'=>'ꠑ','ꠒ'=>'ꠒ','ꠓ'=>'ꠓ','ꠔ'=>'ꠔ','ꠕ'=>'ꠕ','ꠖ'=>'ꠖ','ꠗ'=>'ꠗ','ꠘ'=>'ꠘ','ꠙ'=>'ꠙ','ꠚ'=>'ꠚ','ꠛ'=>'ꠛ','ꠜ'=>'ꠜ','ꠝ'=>'ꠝ','ꠞ'=>'ꠞ','ꠟ'=>'ꠟ','ꠠ'=>'ꠠ','ꠡ'=>'ꠡ','ꠢ'=>'ꠢ','ꠣ'=>'ꠣ','ꠤ'=>'ꠤ','ꠥ'=>'ꠥ','ꠦ'=>'ꠦ','ꠧ'=>'ꠧ','ꡀ'=>'ꡀ','ꡁ'=>'ꡁ','ꡂ'=>'ꡂ','ꡃ'=>'ꡃ','ꡄ'=>'ꡄ','ꡅ'=>'ꡅ','ꡆ'=>'ꡆ','ꡇ'=>'ꡇ','ꡈ'=>'ꡈ','ꡉ'=>'ꡉ','ꡊ'=>'ꡊ','ꡋ'=>'ꡋ','ꡌ'=>'ꡌ','ꡍ'=>'ꡍ','ꡎ'=>'ꡎ','ꡏ'=>'ꡏ','ꡐ'=>'ꡐ','ꡑ'=>'ꡑ','ꡒ'=>'ꡒ','ꡓ'=>'ꡓ','ꡔ'=>'ꡔ','ꡕ'=>'ꡕ','ꡖ'=>'ꡖ','ꡗ'=>'ꡗ','ꡘ'=>'ꡘ','ꡙ'=>'ꡙ','ꡚ'=>'ꡚ','ꡛ'=>'ꡛ','ꡜ'=>'ꡜ','ꡝ'=>'ꡝ','ꡞ'=>'ꡞ','ꡟ'=>'ꡟ','ꡠ'=>'ꡠ','ꡡ'=>'ꡡ','ꡢ'=>'ꡢ','ꡣ'=>'ꡣ','ꡤ'=>'ꡤ','ꡥ'=>'ꡥ','ꡦ'=>'ꡦ','ꡧ'=>'ꡧ','ꡨ'=>'ꡨ','ꡩ'=>'ꡩ','ꡪ'=>'ꡪ','ꡫ'=>'ꡫ','ꡬ'=>'ꡬ','ꡭ'=>'ꡭ','ꡮ'=>'ꡮ','ꡯ'=>'ꡯ','ꡰ'=>'ꡰ','ꡱ'=>'ꡱ','ꡲ'=>'ꡲ','ꡳ'=>'ꡳ','가'=>'가'); diff --git a/phpBB/includes/utf/data/search_indexer_26.php b/phpBB/includes/utf/data/search_indexer_26.php index b8718bd608..444ab96ba8 100644 --- a/phpBB/includes/utf/data/search_indexer_26.php +++ b/phpBB/includes/utf/data/search_indexer_26.php @@ -1 +1 @@ -<?php return array('힣'=>'힣');
\ No newline at end of file +<?php return array('힣'=>'힣'); diff --git a/phpBB/includes/utf/data/search_indexer_3.php b/phpBB/includes/utf/data/search_indexer_3.php index 41798c9e86..ceab762ca9 100644 --- a/phpBB/includes/utf/data/search_indexer_3.php +++ b/phpBB/includes/utf/data/search_indexer_3.php @@ -1 +1 @@ -<?php return array('᠋'=>'᠋','᠌'=>'᠌','᠍'=>'᠍','᠐'=>'0','᠑'=>'1','᠒'=>'2','᠓'=>'3','᠔'=>'4','᠕'=>'5','᠖'=>'6','᠗'=>'7','᠘'=>'8','᠙'=>'9','ᠠ'=>'ᠠ','ᠡ'=>'ᠡ','ᠢ'=>'ᠢ','ᠣ'=>'ᠣ','ᠤ'=>'ᠤ','ᠥ'=>'ᠥ','ᠦ'=>'ᠦ','ᠧ'=>'ᠧ','ᠨ'=>'ᠨ','ᠩ'=>'ᠩ','ᠪ'=>'ᠪ','ᠫ'=>'ᠫ','ᠬ'=>'ᠬ','ᠭ'=>'ᠭ','ᠮ'=>'ᠮ','ᠯ'=>'ᠯ','ᠰ'=>'ᠰ','ᠱ'=>'ᠱ','ᠲ'=>'ᠲ','ᠳ'=>'ᠳ','ᠴ'=>'ᠴ','ᠵ'=>'ᠵ','ᠶ'=>'ᠶ','ᠷ'=>'ᠷ','ᠸ'=>'ᠸ','ᠹ'=>'ᠹ','ᠺ'=>'ᠺ','ᠻ'=>'ᠻ','ᠼ'=>'ᠼ','ᠽ'=>'ᠽ','ᠾ'=>'ᠾ','ᠿ'=>'ᠿ','ᡀ'=>'ᡀ','ᡁ'=>'ᡁ','ᡂ'=>'ᡂ','ᡃ'=>'ᡃ','ᡄ'=>'ᡄ','ᡅ'=>'ᡅ','ᡆ'=>'ᡆ','ᡇ'=>'ᡇ','ᡈ'=>'ᡈ','ᡉ'=>'ᡉ','ᡊ'=>'ᡊ','ᡋ'=>'ᡋ','ᡌ'=>'ᡌ','ᡍ'=>'ᡍ','ᡎ'=>'ᡎ','ᡏ'=>'ᡏ','ᡐ'=>'ᡐ','ᡑ'=>'ᡑ','ᡒ'=>'ᡒ','ᡓ'=>'ᡓ','ᡔ'=>'ᡔ','ᡕ'=>'ᡕ','ᡖ'=>'ᡖ','ᡗ'=>'ᡗ','ᡘ'=>'ᡘ','ᡙ'=>'ᡙ','ᡚ'=>'ᡚ','ᡛ'=>'ᡛ','ᡜ'=>'ᡜ','ᡝ'=>'ᡝ','ᡞ'=>'ᡞ','ᡟ'=>'ᡟ','ᡠ'=>'ᡠ','ᡡ'=>'ᡡ','ᡢ'=>'ᡢ','ᡣ'=>'ᡣ','ᡤ'=>'ᡤ','ᡥ'=>'ᡥ','ᡦ'=>'ᡦ','ᡧ'=>'ᡧ','ᡨ'=>'ᡨ','ᡩ'=>'ᡩ','ᡪ'=>'ᡪ','ᡫ'=>'ᡫ','ᡬ'=>'ᡬ','ᡭ'=>'ᡭ','ᡮ'=>'ᡮ','ᡯ'=>'ᡯ','ᡰ'=>'ᡰ','ᡱ'=>'ᡱ','ᡲ'=>'ᡲ','ᡳ'=>'ᡳ','ᡴ'=>'ᡴ','ᡵ'=>'ᡵ','ᡶ'=>'ᡶ','ᡷ'=>'ᡷ','ᢀ'=>'ᢀ','ᢁ'=>'ᢁ','ᢂ'=>'ᢂ','ᢃ'=>'ᢃ','ᢄ'=>'ᢄ','ᢅ'=>'ᢅ','ᢆ'=>'ᢆ','ᢇ'=>'ᢇ','ᢈ'=>'ᢈ','ᢉ'=>'ᢉ','ᢊ'=>'ᢊ','ᢋ'=>'ᢋ','ᢌ'=>'ᢌ','ᢍ'=>'ᢍ','ᢎ'=>'ᢎ','ᢏ'=>'ᢏ','ᢐ'=>'ᢐ','ᢑ'=>'ᢑ','ᢒ'=>'ᢒ','ᢓ'=>'ᢓ','ᢔ'=>'ᢔ','ᢕ'=>'ᢕ','ᢖ'=>'ᢖ','ᢗ'=>'ᢗ','ᢘ'=>'ᢘ','ᢙ'=>'ᢙ','ᢚ'=>'ᢚ','ᢛ'=>'ᢛ','ᢜ'=>'ᢜ','ᢝ'=>'ᢝ','ᢞ'=>'ᢞ','ᢟ'=>'ᢟ','ᢠ'=>'ᢠ','ᢡ'=>'ᢡ','ᢢ'=>'ᢢ','ᢣ'=>'ᢣ','ᢤ'=>'ᢤ','ᢥ'=>'ᢥ','ᢦ'=>'ᢦ','ᢧ'=>'ᢧ','ᢨ'=>'ᢨ','ᢩ'=>'ᢩ','ᤀ'=>'ᤀ','ᤁ'=>'ᤁ','ᤂ'=>'ᤂ','ᤃ'=>'ᤃ','ᤄ'=>'ᤄ','ᤅ'=>'ᤅ','ᤆ'=>'ᤆ','ᤇ'=>'ᤇ','ᤈ'=>'ᤈ','ᤉ'=>'ᤉ','ᤊ'=>'ᤊ','ᤋ'=>'ᤋ','ᤌ'=>'ᤌ','ᤍ'=>'ᤍ','ᤎ'=>'ᤎ','ᤏ'=>'ᤏ','ᤐ'=>'ᤐ','ᤑ'=>'ᤑ','ᤒ'=>'ᤒ','ᤓ'=>'ᤓ','ᤔ'=>'ᤔ','ᤕ'=>'ᤕ','ᤖ'=>'ᤖ','ᤗ'=>'ᤗ','ᤘ'=>'ᤘ','ᤙ'=>'ᤙ','ᤚ'=>'ᤚ','ᤛ'=>'ᤛ','ᤜ'=>'ᤜ','ᤠ'=>'ᤠ','ᤡ'=>'ᤡ','ᤢ'=>'ᤢ','ᤣ'=>'ᤣ','ᤤ'=>'ᤤ','ᤥ'=>'ᤥ','ᤦ'=>'ᤦ','ᤧ'=>'ᤧ','ᤨ'=>'ᤨ','ᤩ'=>'ᤩ','ᤪ'=>'ᤪ','ᤫ'=>'ᤫ','ᤰ'=>'ᤰ','ᤱ'=>'ᤱ','ᤲ'=>'ᤲ','ᤳ'=>'ᤳ','ᤴ'=>'ᤴ','ᤵ'=>'ᤵ','ᤶ'=>'ᤶ','ᤷ'=>'ᤷ','ᤸ'=>'ᤸ','᤹'=>'᤹','᤺'=>'᤺','᤻'=>'᤻','᥆'=>'0','᥇'=>'1','᥈'=>'2','᥉'=>'3','᥊'=>'4','᥋'=>'5','᥌'=>'6','᥍'=>'7','᥎'=>'8','᥏'=>'9','ᥐ'=>'ᥐ','ᥑ'=>'ᥑ','ᥒ'=>'ᥒ','ᥓ'=>'ᥓ','ᥔ'=>'ᥔ','ᥕ'=>'ᥕ','ᥖ'=>'ᥖ','ᥗ'=>'ᥗ','ᥘ'=>'ᥘ','ᥙ'=>'ᥙ','ᥚ'=>'ᥚ','ᥛ'=>'ᥛ','ᥜ'=>'ᥜ','ᥝ'=>'ᥝ','ᥞ'=>'ᥞ','ᥟ'=>'ᥟ','ᥠ'=>'ᥠ','ᥡ'=>'ᥡ','ᥢ'=>'ᥢ','ᥣ'=>'ᥣ','ᥤ'=>'ᥤ','ᥥ'=>'ᥥ','ᥦ'=>'ᥦ','ᥧ'=>'ᥧ','ᥨ'=>'ᥨ','ᥩ'=>'ᥩ','ᥪ'=>'ᥪ','ᥫ'=>'ᥫ','ᥬ'=>'ᥬ','ᥭ'=>'ᥭ','ᥰ'=>'ᥰ','ᥱ'=>'ᥱ','ᥲ'=>'ᥲ','ᥳ'=>'ᥳ','ᥴ'=>'ᥴ','ᦀ'=>'ᦀ','ᦁ'=>'ᦁ','ᦂ'=>'ᦂ','ᦃ'=>'ᦃ','ᦄ'=>'ᦄ','ᦅ'=>'ᦅ','ᦆ'=>'ᦆ','ᦇ'=>'ᦇ','ᦈ'=>'ᦈ','ᦉ'=>'ᦉ','ᦊ'=>'ᦊ','ᦋ'=>'ᦋ','ᦌ'=>'ᦌ','ᦍ'=>'ᦍ','ᦎ'=>'ᦎ','ᦏ'=>'ᦏ','ᦐ'=>'ᦐ','ᦑ'=>'ᦑ','ᦒ'=>'ᦒ','ᦓ'=>'ᦓ','ᦔ'=>'ᦔ','ᦕ'=>'ᦕ','ᦖ'=>'ᦖ','ᦗ'=>'ᦗ','ᦘ'=>'ᦘ','ᦙ'=>'ᦙ','ᦚ'=>'ᦚ','ᦛ'=>'ᦛ','ᦜ'=>'ᦜ','ᦝ'=>'ᦝ','ᦞ'=>'ᦞ','ᦟ'=>'ᦟ','ᦠ'=>'ᦠ','ᦡ'=>'ᦡ','ᦢ'=>'ᦢ','ᦣ'=>'ᦣ','ᦤ'=>'ᦤ','ᦥ'=>'ᦥ','ᦦ'=>'ᦦ','ᦧ'=>'ᦧ','ᦨ'=>'ᦨ','ᦩ'=>'ᦩ','ᦰ'=>'ᦰ','ᦱ'=>'ᦱ','ᦲ'=>'ᦲ','ᦳ'=>'ᦳ','ᦴ'=>'ᦴ','ᦵ'=>'ᦵ','ᦶ'=>'ᦶ','ᦷ'=>'ᦷ','ᦸ'=>'ᦸ','ᦹ'=>'ᦹ','ᦺ'=>'ᦺ','ᦻ'=>'ᦻ','ᦼ'=>'ᦼ','ᦽ'=>'ᦽ','ᦾ'=>'ᦾ','ᦿ'=>'ᦿ','ᧀ'=>'ᧀ','ᧁ'=>'ᧁ','ᧂ'=>'ᧂ','ᧃ'=>'ᧃ','ᧄ'=>'ᧄ','ᧅ'=>'ᧅ','ᧆ'=>'ᧆ','ᧇ'=>'ᧇ','ᧈ'=>'ᧈ','ᧉ'=>'ᧉ','᧐'=>'0','᧑'=>'1','᧒'=>'2','᧓'=>'3','᧔'=>'4','᧕'=>'5','᧖'=>'6','᧗'=>'7','᧘'=>'8','᧙'=>'9','ᨀ'=>'ᨀ','ᨁ'=>'ᨁ','ᨂ'=>'ᨂ','ᨃ'=>'ᨃ','ᨄ'=>'ᨄ','ᨅ'=>'ᨅ','ᨆ'=>'ᨆ','ᨇ'=>'ᨇ','ᨈ'=>'ᨈ','ᨉ'=>'ᨉ','ᨊ'=>'ᨊ','ᨋ'=>'ᨋ','ᨌ'=>'ᨌ','ᨍ'=>'ᨍ','ᨎ'=>'ᨎ','ᨏ'=>'ᨏ','ᨐ'=>'ᨐ','ᨑ'=>'ᨑ','ᨒ'=>'ᨒ','ᨓ'=>'ᨓ','ᨔ'=>'ᨔ','ᨕ'=>'ᨕ','ᨖ'=>'ᨖ','ᨗ'=>'ᨗ','ᨘ'=>'ᨘ','ᨙ'=>'ᨙ','ᨚ'=>'ᨚ','ᨛ'=>'ᨛ','ᬀ'=>'ᬀ','ᬁ'=>'ᬁ','ᬂ'=>'ᬂ','ᬃ'=>'ᬃ','ᬄ'=>'ᬄ','ᬅ'=>'ᬅ','ᬆ'=>'ᬆ','ᬇ'=>'ᬇ','ᬈ'=>'ᬈ','ᬉ'=>'ᬉ','ᬊ'=>'ᬊ','ᬋ'=>'ᬋ','ᬌ'=>'ᬌ','ᬍ'=>'ᬍ','ᬎ'=>'ᬎ','ᬏ'=>'ᬏ','ᬐ'=>'ᬐ','ᬑ'=>'ᬑ','ᬒ'=>'ᬒ','ᬓ'=>'ᬓ','ᬔ'=>'ᬔ','ᬕ'=>'ᬕ','ᬖ'=>'ᬖ','ᬗ'=>'ᬗ','ᬘ'=>'ᬘ','ᬙ'=>'ᬙ','ᬚ'=>'ᬚ','ᬛ'=>'ᬛ','ᬜ'=>'ᬜ','ᬝ'=>'ᬝ','ᬞ'=>'ᬞ','ᬟ'=>'ᬟ','ᬠ'=>'ᬠ','ᬡ'=>'ᬡ','ᬢ'=>'ᬢ','ᬣ'=>'ᬣ','ᬤ'=>'ᬤ','ᬥ'=>'ᬥ','ᬦ'=>'ᬦ','ᬧ'=>'ᬧ','ᬨ'=>'ᬨ','ᬩ'=>'ᬩ','ᬪ'=>'ᬪ','ᬫ'=>'ᬫ','ᬬ'=>'ᬬ','ᬭ'=>'ᬭ','ᬮ'=>'ᬮ','ᬯ'=>'ᬯ','ᬰ'=>'ᬰ','ᬱ'=>'ᬱ','ᬲ'=>'ᬲ','ᬳ'=>'ᬳ','᬴'=>'᬴','ᬵ'=>'ᬵ','ᬶ'=>'ᬶ','ᬷ'=>'ᬷ','ᬸ'=>'ᬸ','ᬹ'=>'ᬹ','ᬺ'=>'ᬺ','ᬻ'=>'ᬻ','ᬼ'=>'ᬼ','ᬽ'=>'ᬽ','ᬾ'=>'ᬾ','ᬿ'=>'ᬿ','ᭀ'=>'ᭀ','ᭁ'=>'ᭁ','ᭂ'=>'ᭂ','ᭃ'=>'ᭃ','᭄'=>'᭄','ᭅ'=>'ᭅ','ᭆ'=>'ᭆ','ᭇ'=>'ᭇ','ᭈ'=>'ᭈ','ᭉ'=>'ᭉ','ᭊ'=>'ᭊ','ᭋ'=>'ᭋ','᭐'=>'0','᭑'=>'1','᭒'=>'2','᭓'=>'3','᭔'=>'4','᭕'=>'5','᭖'=>'6','᭗'=>'7','᭘'=>'8','᭙'=>'9','᭫'=>'᭫','᭬'=>'᭬','᭭'=>'᭭','᭮'=>'᭮','᭯'=>'᭯','᭰'=>'᭰','᭱'=>'᭱','᭲'=>'᭲','᭳'=>'᭳','ᴀ'=>'ᴀ','ᴁ'=>'ᴁ','ᴂ'=>'ᴂ','ᴃ'=>'ᴃ','ᴄ'=>'ᴄ','ᴅ'=>'ᴅ','ᴆ'=>'ᴆ','ᴇ'=>'ᴇ','ᴈ'=>'ᴈ','ᴉ'=>'ᴉ','ᴊ'=>'ᴊ','ᴋ'=>'ᴋ','ᴌ'=>'ᴌ','ᴍ'=>'ᴍ','ᴎ'=>'ᴎ','ᴏ'=>'ᴏ','ᴐ'=>'ᴐ','ᴑ'=>'ᴑ','ᴒ'=>'ᴒ','ᴓ'=>'ᴓ','ᴔ'=>'ᴔ','ᴕ'=>'ᴕ','ᴖ'=>'ᴖ','ᴗ'=>'ᴗ','ᴘ'=>'ᴘ','ᴙ'=>'ᴙ','ᴚ'=>'ᴚ','ᴛ'=>'ᴛ','ᴜ'=>'ᴜ','ᴝ'=>'ᴝ','ᴞ'=>'ᴞ','ᴟ'=>'ᴟ','ᴠ'=>'ᴠ','ᴡ'=>'ᴡ','ᴢ'=>'ᴢ','ᴣ'=>'ᴣ','ᴤ'=>'ᴤ','ᴥ'=>'ᴥ','ᴦ'=>'ᴦ','ᴧ'=>'ᴧ','ᴨ'=>'ᴨ','ᴩ'=>'ᴩ','ᴪ'=>'ᴪ','ᴫ'=>'ᴫ','ᴬ'=>'ᴬ','ᴭ'=>'ᴭ','ᴮ'=>'ᴮ','ᴯ'=>'ᴯ','ᴰ'=>'ᴰ','ᴱ'=>'ᴱ','ᴲ'=>'ᴲ','ᴳ'=>'ᴳ','ᴴ'=>'ᴴ','ᴵ'=>'ᴵ','ᴶ'=>'ᴶ','ᴷ'=>'ᴷ','ᴸ'=>'ᴸ','ᴹ'=>'ᴹ','ᴺ'=>'ᴺ','ᴻ'=>'ᴻ','ᴼ'=>'ᴼ','ᴽ'=>'ᴽ','ᴾ'=>'ᴾ','ᴿ'=>'ᴿ','ᵀ'=>'ᵀ','ᵁ'=>'ᵁ','ᵂ'=>'ᵂ','ᵃ'=>'ᵃ','ᵄ'=>'ᵄ','ᵅ'=>'ᵅ','ᵆ'=>'ᵆ','ᵇ'=>'ᵇ','ᵈ'=>'ᵈ','ᵉ'=>'ᵉ','ᵊ'=>'ᵊ','ᵋ'=>'ᵋ','ᵌ'=>'ᵌ','ᵍ'=>'ᵍ','ᵎ'=>'ᵎ','ᵏ'=>'ᵏ','ᵐ'=>'ᵐ','ᵑ'=>'ᵑ','ᵒ'=>'ᵒ','ᵓ'=>'ᵓ','ᵔ'=>'ᵔ','ᵕ'=>'ᵕ','ᵖ'=>'ᵖ','ᵗ'=>'ᵗ','ᵘ'=>'ᵘ','ᵙ'=>'ᵙ','ᵚ'=>'ᵚ','ᵛ'=>'ᵛ','ᵜ'=>'ᵜ','ᵝ'=>'ᵝ','ᵞ'=>'ᵞ','ᵟ'=>'ᵟ','ᵠ'=>'ᵠ','ᵡ'=>'ᵡ','ᵢ'=>'ᵢ','ᵣ'=>'ᵣ','ᵤ'=>'ᵤ','ᵥ'=>'ᵥ','ᵦ'=>'ᵦ','ᵧ'=>'ᵧ','ᵨ'=>'ᵨ','ᵩ'=>'ᵩ','ᵪ'=>'ᵪ','ᵫ'=>'ue','ᵬ'=>'ᵬ','ᵭ'=>'ᵭ','ᵮ'=>'ᵮ','ᵯ'=>'ᵯ','ᵰ'=>'ᵰ','ᵱ'=>'ᵱ','ᵲ'=>'ᵲ','ᵳ'=>'ᵳ','ᵴ'=>'ᵴ','ᵵ'=>'ᵵ','ᵶ'=>'ᵶ','ᵷ'=>'ᵷ','ᵸ'=>'ᵸ','ᵹ'=>'ᵹ','ᵺ'=>'ᵺ','ᵻ'=>'ᵻ','ᵼ'=>'ᵼ','ᵽ'=>'ᵽ','ᵾ'=>'ᵾ','ᵿ'=>'ᵿ','ᶀ'=>'ᶀ','ᶁ'=>'ᶁ','ᶂ'=>'ᶂ','ᶃ'=>'ᶃ','ᶄ'=>'ᶄ','ᶅ'=>'ᶅ','ᶆ'=>'ᶆ','ᶇ'=>'ᶇ','ᶈ'=>'ᶈ','ᶉ'=>'ᶉ','ᶊ'=>'ᶊ','ᶋ'=>'ᶋ','ᶌ'=>'ᶌ','ᶍ'=>'ᶍ','ᶎ'=>'ᶎ','ᶏ'=>'ᶏ','ᶐ'=>'ᶐ','ᶑ'=>'ᶑ','ᶒ'=>'ᶒ','ᶓ'=>'ᶓ','ᶔ'=>'ᶔ','ᶕ'=>'ᶕ','ᶖ'=>'ᶖ','ᶗ'=>'ᶗ','ᶘ'=>'ᶘ','ᶙ'=>'ᶙ','ᶚ'=>'ᶚ','ᶛ'=>'ᶛ','ᶜ'=>'ᶜ','ᶝ'=>'ᶝ','ᶞ'=>'ᶞ','ᶟ'=>'ᶟ','ᶠ'=>'ᶠ','ᶡ'=>'ᶡ','ᶢ'=>'ᶢ','ᶣ'=>'ᶣ','ᶤ'=>'ᶤ','ᶥ'=>'ᶥ','ᶦ'=>'ᶦ','ᶧ'=>'ᶧ','ᶨ'=>'ᶨ','ᶩ'=>'ᶩ','ᶪ'=>'ᶪ','ᶫ'=>'ᶫ','ᶬ'=>'ᶬ','ᶭ'=>'ᶭ','ᶮ'=>'ᶮ','ᶯ'=>'ᶯ','ᶰ'=>'ᶰ','ᶱ'=>'ᶱ','ᶲ'=>'ᶲ','ᶳ'=>'ᶳ','ᶴ'=>'ᶴ','ᶵ'=>'ᶵ','ᶶ'=>'ᶶ','ᶷ'=>'ᶷ','ᶸ'=>'ᶸ','ᶹ'=>'ᶹ','ᶺ'=>'ᶺ','ᶻ'=>'ᶻ','ᶼ'=>'ᶼ','ᶽ'=>'ᶽ','ᶾ'=>'ᶾ','ᶿ'=>'ᶿ','᷀'=>'᷀','᷁'=>'᷁','᷂'=>'᷂','᷃'=>'᷃','᷄'=>'᷄','᷅'=>'᷅','᷆'=>'᷆','᷇'=>'᷇','᷈'=>'᷈','᷉'=>'᷉','᷊'=>'᷊','᷾'=>'᷾','᷿'=>'᷿','Ḁ'=>'ḁ','ḁ'=>'ḁ','Ḃ'=>'ḃ','ḃ'=>'ḃ','Ḅ'=>'ḅ','ḅ'=>'ḅ','Ḇ'=>'ḇ','ḇ'=>'ḇ','Ḉ'=>'ḉ','ḉ'=>'ḉ','Ḋ'=>'ḋ','ḋ'=>'ḋ','Ḍ'=>'ḍ','ḍ'=>'ḍ','Ḏ'=>'ḏ','ḏ'=>'ḏ','Ḑ'=>'ḑ','ḑ'=>'ḑ','Ḓ'=>'ḓ','ḓ'=>'ḓ','Ḕ'=>'ḕ','ḕ'=>'ḕ','Ḗ'=>'ḗ','ḗ'=>'ḗ','Ḙ'=>'ḙ','ḙ'=>'ḙ','Ḛ'=>'ḛ','ḛ'=>'ḛ','Ḝ'=>'ḝ','ḝ'=>'ḝ','Ḟ'=>'ḟ','ḟ'=>'ḟ','Ḡ'=>'ḡ','ḡ'=>'ḡ','Ḣ'=>'ḣ','ḣ'=>'ḣ','Ḥ'=>'ḥ','ḥ'=>'ḥ','Ḧ'=>'ḧ','ḧ'=>'ḧ','Ḩ'=>'ḩ','ḩ'=>'ḩ','Ḫ'=>'ḫ','ḫ'=>'ḫ','Ḭ'=>'ḭ','ḭ'=>'ḭ','Ḯ'=>'ḯ','ḯ'=>'ḯ','Ḱ'=>'ḱ','ḱ'=>'ḱ','Ḳ'=>'ḳ','ḳ'=>'ḳ','Ḵ'=>'ḵ','ḵ'=>'ḵ','Ḷ'=>'ḷ','ḷ'=>'ḷ','Ḹ'=>'ḹ','ḹ'=>'ḹ','Ḻ'=>'ḻ','ḻ'=>'ḻ','Ḽ'=>'ḽ','ḽ'=>'ḽ','Ḿ'=>'ḿ','ḿ'=>'ḿ','Ṁ'=>'ṁ','ṁ'=>'ṁ','Ṃ'=>'ṃ','ṃ'=>'ṃ','Ṅ'=>'ṅ','ṅ'=>'ṅ','Ṇ'=>'ṇ','ṇ'=>'ṇ','Ṉ'=>'ṉ','ṉ'=>'ṉ','Ṋ'=>'ṋ','ṋ'=>'ṋ','Ṍ'=>'ṍ','ṍ'=>'ṍ','Ṏ'=>'ṏ','ṏ'=>'ṏ','Ṑ'=>'ṑ','ṑ'=>'ṑ','Ṓ'=>'ṓ','ṓ'=>'ṓ','Ṕ'=>'ṕ','ṕ'=>'ṕ','Ṗ'=>'ṗ','ṗ'=>'ṗ','Ṙ'=>'ṙ','ṙ'=>'ṙ','Ṛ'=>'ṛ','ṛ'=>'ṛ','Ṝ'=>'ṝ','ṝ'=>'ṝ','Ṟ'=>'ṟ','ṟ'=>'ṟ','Ṡ'=>'ṡ','ṡ'=>'ṡ','Ṣ'=>'ṣ','ṣ'=>'ṣ','Ṥ'=>'ṥ','ṥ'=>'ṥ','Ṧ'=>'ṧ','ṧ'=>'ṧ','Ṩ'=>'ṩ','ṩ'=>'ṩ','Ṫ'=>'ṫ','ṫ'=>'ṫ','Ṭ'=>'ṭ','ṭ'=>'ṭ','Ṯ'=>'ṯ','ṯ'=>'ṯ','Ṱ'=>'ṱ','ṱ'=>'ṱ','Ṳ'=>'ṳ','ṳ'=>'ṳ','Ṵ'=>'ṵ','ṵ'=>'ṵ','Ṷ'=>'ṷ','ṷ'=>'ṷ','Ṹ'=>'ṹ','ṹ'=>'ṹ','Ṻ'=>'ṻ','ṻ'=>'ṻ','Ṽ'=>'ṽ','ṽ'=>'ṽ','Ṿ'=>'ṿ','ṿ'=>'ṿ','Ẁ'=>'ẁ','ẁ'=>'ẁ','Ẃ'=>'ẃ','ẃ'=>'ẃ','Ẅ'=>'ẅ','ẅ'=>'ẅ','Ẇ'=>'ẇ','ẇ'=>'ẇ','Ẉ'=>'ẉ','ẉ'=>'ẉ','Ẋ'=>'ẋ','ẋ'=>'ẋ','Ẍ'=>'ẍ','ẍ'=>'ẍ','Ẏ'=>'ẏ','ẏ'=>'ẏ','Ẑ'=>'ẑ','ẑ'=>'ẑ','Ẓ'=>'ẓ','ẓ'=>'ẓ','Ẕ'=>'ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẚ'=>'ẚ','ẛ'=>'ẛ','Ạ'=>'ạ','ạ'=>'ạ','Ả'=>'ả','ả'=>'ả','Ấ'=>'ấ','ấ'=>'ấ','Ầ'=>'ầ','ầ'=>'ầ','Ẩ'=>'ẩ','ẩ'=>'ẩ','Ẫ'=>'ẫ','ẫ'=>'ẫ','Ậ'=>'ậ','ậ'=>'ậ','Ắ'=>'ắ','ắ'=>'ắ','Ằ'=>'ằ','ằ'=>'ằ','Ẳ'=>'ẳ','ẳ'=>'ẳ','Ẵ'=>'ẵ','ẵ'=>'ẵ','Ặ'=>'ặ','ặ'=>'ặ','Ẹ'=>'ẹ','ẹ'=>'ẹ','Ẻ'=>'ẻ','ẻ'=>'ẻ','Ẽ'=>'ẽ','ẽ'=>'ẽ','Ế'=>'ế','ế'=>'ế','Ề'=>'ề','ề'=>'ề','Ể'=>'ể','ể'=>'ể','Ễ'=>'ễ','ễ'=>'ễ','Ệ'=>'ệ','ệ'=>'ệ','Ỉ'=>'ỉ','ỉ'=>'ỉ','Ị'=>'ị','ị'=>'ị','Ọ'=>'ọ','ọ'=>'ọ','Ỏ'=>'ỏ','ỏ'=>'ỏ','Ố'=>'ố','ố'=>'ố','Ồ'=>'ồ','ồ'=>'ồ','Ổ'=>'ổ','ổ'=>'ổ','Ỗ'=>'ỗ','ỗ'=>'ỗ','Ộ'=>'ộ','ộ'=>'ộ','Ớ'=>'ớ','ớ'=>'ớ','Ờ'=>'ờ','ờ'=>'ờ','Ở'=>'ở','ở'=>'ở','Ỡ'=>'ỡ','ỡ'=>'ỡ','Ợ'=>'ợ','ợ'=>'ợ','Ụ'=>'ụ','ụ'=>'ụ','Ủ'=>'ủ','ủ'=>'ủ','Ứ'=>'ứ','ứ'=>'ứ','Ừ'=>'ừ','ừ'=>'ừ','Ử'=>'ử','ử'=>'ử','Ữ'=>'ữ','ữ'=>'ữ','Ự'=>'ự','ự'=>'ự','Ỳ'=>'ỳ','ỳ'=>'ỳ','Ỵ'=>'ỵ','ỵ'=>'ỵ','Ỷ'=>'ỷ','ỷ'=>'ỷ','Ỹ'=>'ỹ','ỹ'=>'ỹ','ἀ'=>'ἀ','ἁ'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἄ','ἅ'=>'ἅ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'ἀ','Ἁ'=>'ἁ','Ἂ'=>'ἂ','Ἃ'=>'ἃ','Ἄ'=>'ἄ','Ἅ'=>'ἅ','Ἆ'=>'ἆ','Ἇ'=>'ἇ','ἐ'=>'ἐ','ἑ'=>'ἑ','ἒ'=>'ἒ','ἓ'=>'ἓ','ἔ'=>'ἔ','ἕ'=>'ἕ','Ἐ'=>'ἐ','Ἑ'=>'ἑ','Ἒ'=>'ἒ','Ἓ'=>'ἓ','Ἔ'=>'ἔ','Ἕ'=>'ἕ','ἠ'=>'ἠ','ἡ'=>'ἡ','ἢ'=>'ἢ','ἣ'=>'ἣ','ἤ'=>'ἤ','ἥ'=>'ἥ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'ἠ','Ἡ'=>'ἡ','Ἢ'=>'ἢ','Ἣ'=>'ἣ','Ἤ'=>'ἤ','Ἥ'=>'ἥ','Ἦ'=>'ἦ','Ἧ'=>'ἧ','ἰ'=>'ἰ','ἱ'=>'ἱ','ἲ'=>'ἲ','ἳ'=>'ἳ','ἴ'=>'ἴ','ἵ'=>'ἵ','ἶ'=>'ἶ','ἷ'=>'ἷ','Ἰ'=>'ἰ','Ἱ'=>'ἱ','Ἲ'=>'ἲ','Ἳ'=>'ἳ','Ἴ'=>'ἴ','Ἵ'=>'ἵ','Ἶ'=>'ἶ','Ἷ'=>'ἷ','ὀ'=>'ὀ','ὁ'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὄ','ὅ'=>'ὅ','Ὀ'=>'ὀ','Ὁ'=>'ὁ','Ὂ'=>'ὂ','Ὃ'=>'ὃ','Ὄ'=>'ὄ','Ὅ'=>'ὅ','ὐ'=>'ὐ','ὑ'=>'ὑ','ὒ'=>'ὒ','ὓ'=>'ὓ','ὔ'=>'ὔ','ὕ'=>'ὕ','ὖ'=>'ὖ','ὗ'=>'ὗ','Ὑ'=>'ὑ','Ὓ'=>'ὓ','Ὕ'=>'ὕ','Ὗ'=>'ὗ','ὠ'=>'ὠ','ὡ'=>'ὡ','ὢ'=>'ὢ','ὣ'=>'ὣ','ὤ'=>'ὤ','ὥ'=>'ὥ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'ὠ','Ὡ'=>'ὡ','Ὢ'=>'ὢ','Ὣ'=>'ὣ','Ὤ'=>'ὤ','Ὥ'=>'ὥ','Ὦ'=>'ὦ','Ὧ'=>'ὧ','ὰ'=>'ὰ','ά'=>'ά','ὲ'=>'ὲ','έ'=>'έ','ὴ'=>'ὴ','ή'=>'ή','ὶ'=>'ὶ','ί'=>'ί','ὸ'=>'ὸ','ό'=>'ό','ὺ'=>'ὺ','ύ'=>'ύ','ὼ'=>'ὼ','ώ'=>'ώ','ᾀ'=>'ᾀ','ᾁ'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ᾄ','ᾅ'=>'ᾅ','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾀ','ᾉ'=>'ᾁ','ᾊ'=>'ᾂ','ᾋ'=>'ᾃ','ᾌ'=>'ᾄ','ᾍ'=>'ᾅ','ᾎ'=>'ᾆ','ᾏ'=>'ᾇ','ᾐ'=>'ᾐ','ᾑ'=>'ᾑ','ᾒ'=>'ᾒ','ᾓ'=>'ᾓ','ᾔ'=>'ᾔ','ᾕ'=>'ᾕ','ᾖ'=>'ᾖ','ᾗ'=>'ᾗ','ᾘ'=>'ᾐ','ᾙ'=>'ᾑ','ᾚ'=>'ᾒ','ᾛ'=>'ᾓ','ᾜ'=>'ᾔ','ᾝ'=>'ᾕ','ᾞ'=>'ᾖ','ᾟ'=>'ᾗ','ᾠ'=>'ᾠ','ᾡ'=>'ᾡ','ᾢ'=>'ᾢ','ᾣ'=>'ᾣ','ᾤ'=>'ᾤ','ᾥ'=>'ᾥ','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾠ','ᾩ'=>'ᾡ','ᾪ'=>'ᾢ','ᾫ'=>'ᾣ','ᾬ'=>'ᾤ','ᾭ'=>'ᾥ','ᾮ'=>'ᾦ','ᾯ'=>'ᾧ','ᾰ'=>'ᾰ','ᾱ'=>'ᾱ','ᾲ'=>'ᾲ','ᾳ'=>'ᾳ','ᾴ'=>'ᾴ','ᾶ'=>'ᾶ','ᾷ'=>'ᾷ','Ᾰ'=>'ᾰ','Ᾱ'=>'ᾱ','Ὰ'=>'ὰ','Ά'=>'ά','ᾼ'=>'ᾳ','ι'=>'ι','ῂ'=>'ῂ','ῃ'=>'ῃ','ῄ'=>'ῄ','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'ὲ','Έ'=>'έ','Ὴ'=>'ὴ','Ή'=>'ή','ῌ'=>'ῃ','ῐ'=>'ῐ','ῑ'=>'ῑ','ῒ'=>'ῒ','ΐ'=>'ΐ','ῖ'=>'ῖ','ῗ'=>'ῗ','Ῐ'=>'ῐ','Ῑ'=>'ῑ','Ὶ'=>'ὶ','Ί'=>'ί','ῠ'=>'ῠ','ῡ'=>'ῡ','ῢ'=>'ῢ','ΰ'=>'ΰ','ῤ'=>'ῤ','ῥ'=>'ῥ','ῦ'=>'ῦ','ῧ'=>'ῧ','Ῠ'=>'ῠ','Ῡ'=>'ῡ','Ὺ'=>'ὺ','Ύ'=>'ύ','Ῥ'=>'ῥ','ῲ'=>'ῲ','ῳ'=>'ῳ','ῴ'=>'ῴ','ῶ'=>'ῶ','ῷ'=>'ῷ','Ὸ'=>'ὸ','Ό'=>'ό','Ὼ'=>'ὼ','Ώ'=>'ώ','ῼ'=>'ῳ');
\ No newline at end of file +<?php return array('᠋'=>'᠋','᠌'=>'᠌','᠍'=>'᠍','᠐'=>'0','᠑'=>'1','᠒'=>'2','᠓'=>'3','᠔'=>'4','᠕'=>'5','᠖'=>'6','᠗'=>'7','᠘'=>'8','᠙'=>'9','ᠠ'=>'ᠠ','ᠡ'=>'ᠡ','ᠢ'=>'ᠢ','ᠣ'=>'ᠣ','ᠤ'=>'ᠤ','ᠥ'=>'ᠥ','ᠦ'=>'ᠦ','ᠧ'=>'ᠧ','ᠨ'=>'ᠨ','ᠩ'=>'ᠩ','ᠪ'=>'ᠪ','ᠫ'=>'ᠫ','ᠬ'=>'ᠬ','ᠭ'=>'ᠭ','ᠮ'=>'ᠮ','ᠯ'=>'ᠯ','ᠰ'=>'ᠰ','ᠱ'=>'ᠱ','ᠲ'=>'ᠲ','ᠳ'=>'ᠳ','ᠴ'=>'ᠴ','ᠵ'=>'ᠵ','ᠶ'=>'ᠶ','ᠷ'=>'ᠷ','ᠸ'=>'ᠸ','ᠹ'=>'ᠹ','ᠺ'=>'ᠺ','ᠻ'=>'ᠻ','ᠼ'=>'ᠼ','ᠽ'=>'ᠽ','ᠾ'=>'ᠾ','ᠿ'=>'ᠿ','ᡀ'=>'ᡀ','ᡁ'=>'ᡁ','ᡂ'=>'ᡂ','ᡃ'=>'ᡃ','ᡄ'=>'ᡄ','ᡅ'=>'ᡅ','ᡆ'=>'ᡆ','ᡇ'=>'ᡇ','ᡈ'=>'ᡈ','ᡉ'=>'ᡉ','ᡊ'=>'ᡊ','ᡋ'=>'ᡋ','ᡌ'=>'ᡌ','ᡍ'=>'ᡍ','ᡎ'=>'ᡎ','ᡏ'=>'ᡏ','ᡐ'=>'ᡐ','ᡑ'=>'ᡑ','ᡒ'=>'ᡒ','ᡓ'=>'ᡓ','ᡔ'=>'ᡔ','ᡕ'=>'ᡕ','ᡖ'=>'ᡖ','ᡗ'=>'ᡗ','ᡘ'=>'ᡘ','ᡙ'=>'ᡙ','ᡚ'=>'ᡚ','ᡛ'=>'ᡛ','ᡜ'=>'ᡜ','ᡝ'=>'ᡝ','ᡞ'=>'ᡞ','ᡟ'=>'ᡟ','ᡠ'=>'ᡠ','ᡡ'=>'ᡡ','ᡢ'=>'ᡢ','ᡣ'=>'ᡣ','ᡤ'=>'ᡤ','ᡥ'=>'ᡥ','ᡦ'=>'ᡦ','ᡧ'=>'ᡧ','ᡨ'=>'ᡨ','ᡩ'=>'ᡩ','ᡪ'=>'ᡪ','ᡫ'=>'ᡫ','ᡬ'=>'ᡬ','ᡭ'=>'ᡭ','ᡮ'=>'ᡮ','ᡯ'=>'ᡯ','ᡰ'=>'ᡰ','ᡱ'=>'ᡱ','ᡲ'=>'ᡲ','ᡳ'=>'ᡳ','ᡴ'=>'ᡴ','ᡵ'=>'ᡵ','ᡶ'=>'ᡶ','ᡷ'=>'ᡷ','ᢀ'=>'ᢀ','ᢁ'=>'ᢁ','ᢂ'=>'ᢂ','ᢃ'=>'ᢃ','ᢄ'=>'ᢄ','ᢅ'=>'ᢅ','ᢆ'=>'ᢆ','ᢇ'=>'ᢇ','ᢈ'=>'ᢈ','ᢉ'=>'ᢉ','ᢊ'=>'ᢊ','ᢋ'=>'ᢋ','ᢌ'=>'ᢌ','ᢍ'=>'ᢍ','ᢎ'=>'ᢎ','ᢏ'=>'ᢏ','ᢐ'=>'ᢐ','ᢑ'=>'ᢑ','ᢒ'=>'ᢒ','ᢓ'=>'ᢓ','ᢔ'=>'ᢔ','ᢕ'=>'ᢕ','ᢖ'=>'ᢖ','ᢗ'=>'ᢗ','ᢘ'=>'ᢘ','ᢙ'=>'ᢙ','ᢚ'=>'ᢚ','ᢛ'=>'ᢛ','ᢜ'=>'ᢜ','ᢝ'=>'ᢝ','ᢞ'=>'ᢞ','ᢟ'=>'ᢟ','ᢠ'=>'ᢠ','ᢡ'=>'ᢡ','ᢢ'=>'ᢢ','ᢣ'=>'ᢣ','ᢤ'=>'ᢤ','ᢥ'=>'ᢥ','ᢦ'=>'ᢦ','ᢧ'=>'ᢧ','ᢨ'=>'ᢨ','ᢩ'=>'ᢩ','ᤀ'=>'ᤀ','ᤁ'=>'ᤁ','ᤂ'=>'ᤂ','ᤃ'=>'ᤃ','ᤄ'=>'ᤄ','ᤅ'=>'ᤅ','ᤆ'=>'ᤆ','ᤇ'=>'ᤇ','ᤈ'=>'ᤈ','ᤉ'=>'ᤉ','ᤊ'=>'ᤊ','ᤋ'=>'ᤋ','ᤌ'=>'ᤌ','ᤍ'=>'ᤍ','ᤎ'=>'ᤎ','ᤏ'=>'ᤏ','ᤐ'=>'ᤐ','ᤑ'=>'ᤑ','ᤒ'=>'ᤒ','ᤓ'=>'ᤓ','ᤔ'=>'ᤔ','ᤕ'=>'ᤕ','ᤖ'=>'ᤖ','ᤗ'=>'ᤗ','ᤘ'=>'ᤘ','ᤙ'=>'ᤙ','ᤚ'=>'ᤚ','ᤛ'=>'ᤛ','ᤜ'=>'ᤜ','ᤠ'=>'ᤠ','ᤡ'=>'ᤡ','ᤢ'=>'ᤢ','ᤣ'=>'ᤣ','ᤤ'=>'ᤤ','ᤥ'=>'ᤥ','ᤦ'=>'ᤦ','ᤧ'=>'ᤧ','ᤨ'=>'ᤨ','ᤩ'=>'ᤩ','ᤪ'=>'ᤪ','ᤫ'=>'ᤫ','ᤰ'=>'ᤰ','ᤱ'=>'ᤱ','ᤲ'=>'ᤲ','ᤳ'=>'ᤳ','ᤴ'=>'ᤴ','ᤵ'=>'ᤵ','ᤶ'=>'ᤶ','ᤷ'=>'ᤷ','ᤸ'=>'ᤸ','᤹'=>'᤹','᤺'=>'᤺','᤻'=>'᤻','᥆'=>'0','᥇'=>'1','᥈'=>'2','᥉'=>'3','᥊'=>'4','᥋'=>'5','᥌'=>'6','᥍'=>'7','᥎'=>'8','᥏'=>'9','ᥐ'=>'ᥐ','ᥑ'=>'ᥑ','ᥒ'=>'ᥒ','ᥓ'=>'ᥓ','ᥔ'=>'ᥔ','ᥕ'=>'ᥕ','ᥖ'=>'ᥖ','ᥗ'=>'ᥗ','ᥘ'=>'ᥘ','ᥙ'=>'ᥙ','ᥚ'=>'ᥚ','ᥛ'=>'ᥛ','ᥜ'=>'ᥜ','ᥝ'=>'ᥝ','ᥞ'=>'ᥞ','ᥟ'=>'ᥟ','ᥠ'=>'ᥠ','ᥡ'=>'ᥡ','ᥢ'=>'ᥢ','ᥣ'=>'ᥣ','ᥤ'=>'ᥤ','ᥥ'=>'ᥥ','ᥦ'=>'ᥦ','ᥧ'=>'ᥧ','ᥨ'=>'ᥨ','ᥩ'=>'ᥩ','ᥪ'=>'ᥪ','ᥫ'=>'ᥫ','ᥬ'=>'ᥬ','ᥭ'=>'ᥭ','ᥰ'=>'ᥰ','ᥱ'=>'ᥱ','ᥲ'=>'ᥲ','ᥳ'=>'ᥳ','ᥴ'=>'ᥴ','ᦀ'=>'ᦀ','ᦁ'=>'ᦁ','ᦂ'=>'ᦂ','ᦃ'=>'ᦃ','ᦄ'=>'ᦄ','ᦅ'=>'ᦅ','ᦆ'=>'ᦆ','ᦇ'=>'ᦇ','ᦈ'=>'ᦈ','ᦉ'=>'ᦉ','ᦊ'=>'ᦊ','ᦋ'=>'ᦋ','ᦌ'=>'ᦌ','ᦍ'=>'ᦍ','ᦎ'=>'ᦎ','ᦏ'=>'ᦏ','ᦐ'=>'ᦐ','ᦑ'=>'ᦑ','ᦒ'=>'ᦒ','ᦓ'=>'ᦓ','ᦔ'=>'ᦔ','ᦕ'=>'ᦕ','ᦖ'=>'ᦖ','ᦗ'=>'ᦗ','ᦘ'=>'ᦘ','ᦙ'=>'ᦙ','ᦚ'=>'ᦚ','ᦛ'=>'ᦛ','ᦜ'=>'ᦜ','ᦝ'=>'ᦝ','ᦞ'=>'ᦞ','ᦟ'=>'ᦟ','ᦠ'=>'ᦠ','ᦡ'=>'ᦡ','ᦢ'=>'ᦢ','ᦣ'=>'ᦣ','ᦤ'=>'ᦤ','ᦥ'=>'ᦥ','ᦦ'=>'ᦦ','ᦧ'=>'ᦧ','ᦨ'=>'ᦨ','ᦩ'=>'ᦩ','ᦰ'=>'ᦰ','ᦱ'=>'ᦱ','ᦲ'=>'ᦲ','ᦳ'=>'ᦳ','ᦴ'=>'ᦴ','ᦵ'=>'ᦵ','ᦶ'=>'ᦶ','ᦷ'=>'ᦷ','ᦸ'=>'ᦸ','ᦹ'=>'ᦹ','ᦺ'=>'ᦺ','ᦻ'=>'ᦻ','ᦼ'=>'ᦼ','ᦽ'=>'ᦽ','ᦾ'=>'ᦾ','ᦿ'=>'ᦿ','ᧀ'=>'ᧀ','ᧁ'=>'ᧁ','ᧂ'=>'ᧂ','ᧃ'=>'ᧃ','ᧄ'=>'ᧄ','ᧅ'=>'ᧅ','ᧆ'=>'ᧆ','ᧇ'=>'ᧇ','ᧈ'=>'ᧈ','ᧉ'=>'ᧉ','᧐'=>'0','᧑'=>'1','᧒'=>'2','᧓'=>'3','᧔'=>'4','᧕'=>'5','᧖'=>'6','᧗'=>'7','᧘'=>'8','᧙'=>'9','ᨀ'=>'ᨀ','ᨁ'=>'ᨁ','ᨂ'=>'ᨂ','ᨃ'=>'ᨃ','ᨄ'=>'ᨄ','ᨅ'=>'ᨅ','ᨆ'=>'ᨆ','ᨇ'=>'ᨇ','ᨈ'=>'ᨈ','ᨉ'=>'ᨉ','ᨊ'=>'ᨊ','ᨋ'=>'ᨋ','ᨌ'=>'ᨌ','ᨍ'=>'ᨍ','ᨎ'=>'ᨎ','ᨏ'=>'ᨏ','ᨐ'=>'ᨐ','ᨑ'=>'ᨑ','ᨒ'=>'ᨒ','ᨓ'=>'ᨓ','ᨔ'=>'ᨔ','ᨕ'=>'ᨕ','ᨖ'=>'ᨖ','ᨗ'=>'ᨗ','ᨘ'=>'ᨘ','ᨙ'=>'ᨙ','ᨚ'=>'ᨚ','ᨛ'=>'ᨛ','ᬀ'=>'ᬀ','ᬁ'=>'ᬁ','ᬂ'=>'ᬂ','ᬃ'=>'ᬃ','ᬄ'=>'ᬄ','ᬅ'=>'ᬅ','ᬆ'=>'ᬆ','ᬇ'=>'ᬇ','ᬈ'=>'ᬈ','ᬉ'=>'ᬉ','ᬊ'=>'ᬊ','ᬋ'=>'ᬋ','ᬌ'=>'ᬌ','ᬍ'=>'ᬍ','ᬎ'=>'ᬎ','ᬏ'=>'ᬏ','ᬐ'=>'ᬐ','ᬑ'=>'ᬑ','ᬒ'=>'ᬒ','ᬓ'=>'ᬓ','ᬔ'=>'ᬔ','ᬕ'=>'ᬕ','ᬖ'=>'ᬖ','ᬗ'=>'ᬗ','ᬘ'=>'ᬘ','ᬙ'=>'ᬙ','ᬚ'=>'ᬚ','ᬛ'=>'ᬛ','ᬜ'=>'ᬜ','ᬝ'=>'ᬝ','ᬞ'=>'ᬞ','ᬟ'=>'ᬟ','ᬠ'=>'ᬠ','ᬡ'=>'ᬡ','ᬢ'=>'ᬢ','ᬣ'=>'ᬣ','ᬤ'=>'ᬤ','ᬥ'=>'ᬥ','ᬦ'=>'ᬦ','ᬧ'=>'ᬧ','ᬨ'=>'ᬨ','ᬩ'=>'ᬩ','ᬪ'=>'ᬪ','ᬫ'=>'ᬫ','ᬬ'=>'ᬬ','ᬭ'=>'ᬭ','ᬮ'=>'ᬮ','ᬯ'=>'ᬯ','ᬰ'=>'ᬰ','ᬱ'=>'ᬱ','ᬲ'=>'ᬲ','ᬳ'=>'ᬳ','᬴'=>'᬴','ᬵ'=>'ᬵ','ᬶ'=>'ᬶ','ᬷ'=>'ᬷ','ᬸ'=>'ᬸ','ᬹ'=>'ᬹ','ᬺ'=>'ᬺ','ᬻ'=>'ᬻ','ᬼ'=>'ᬼ','ᬽ'=>'ᬽ','ᬾ'=>'ᬾ','ᬿ'=>'ᬿ','ᭀ'=>'ᭀ','ᭁ'=>'ᭁ','ᭂ'=>'ᭂ','ᭃ'=>'ᭃ','᭄'=>'᭄','ᭅ'=>'ᭅ','ᭆ'=>'ᭆ','ᭇ'=>'ᭇ','ᭈ'=>'ᭈ','ᭉ'=>'ᭉ','ᭊ'=>'ᭊ','ᭋ'=>'ᭋ','᭐'=>'0','᭑'=>'1','᭒'=>'2','᭓'=>'3','᭔'=>'4','᭕'=>'5','᭖'=>'6','᭗'=>'7','᭘'=>'8','᭙'=>'9','᭫'=>'᭫','᭬'=>'᭬','᭭'=>'᭭','᭮'=>'᭮','᭯'=>'᭯','᭰'=>'᭰','᭱'=>'᭱','᭲'=>'᭲','᭳'=>'᭳','ᴀ'=>'ᴀ','ᴁ'=>'ᴁ','ᴂ'=>'ᴂ','ᴃ'=>'ᴃ','ᴄ'=>'ᴄ','ᴅ'=>'ᴅ','ᴆ'=>'ᴆ','ᴇ'=>'ᴇ','ᴈ'=>'ᴈ','ᴉ'=>'ᴉ','ᴊ'=>'ᴊ','ᴋ'=>'ᴋ','ᴌ'=>'ᴌ','ᴍ'=>'ᴍ','ᴎ'=>'ᴎ','ᴏ'=>'ᴏ','ᴐ'=>'ᴐ','ᴑ'=>'ᴑ','ᴒ'=>'ᴒ','ᴓ'=>'ᴓ','ᴔ'=>'ᴔ','ᴕ'=>'ᴕ','ᴖ'=>'ᴖ','ᴗ'=>'ᴗ','ᴘ'=>'ᴘ','ᴙ'=>'ᴙ','ᴚ'=>'ᴚ','ᴛ'=>'ᴛ','ᴜ'=>'ᴜ','ᴝ'=>'ᴝ','ᴞ'=>'ᴞ','ᴟ'=>'ᴟ','ᴠ'=>'ᴠ','ᴡ'=>'ᴡ','ᴢ'=>'ᴢ','ᴣ'=>'ᴣ','ᴤ'=>'ᴤ','ᴥ'=>'ᴥ','ᴦ'=>'ᴦ','ᴧ'=>'ᴧ','ᴨ'=>'ᴨ','ᴩ'=>'ᴩ','ᴪ'=>'ᴪ','ᴫ'=>'ᴫ','ᴬ'=>'ᴬ','ᴭ'=>'ᴭ','ᴮ'=>'ᴮ','ᴯ'=>'ᴯ','ᴰ'=>'ᴰ','ᴱ'=>'ᴱ','ᴲ'=>'ᴲ','ᴳ'=>'ᴳ','ᴴ'=>'ᴴ','ᴵ'=>'ᴵ','ᴶ'=>'ᴶ','ᴷ'=>'ᴷ','ᴸ'=>'ᴸ','ᴹ'=>'ᴹ','ᴺ'=>'ᴺ','ᴻ'=>'ᴻ','ᴼ'=>'ᴼ','ᴽ'=>'ᴽ','ᴾ'=>'ᴾ','ᴿ'=>'ᴿ','ᵀ'=>'ᵀ','ᵁ'=>'ᵁ','ᵂ'=>'ᵂ','ᵃ'=>'ᵃ','ᵄ'=>'ᵄ','ᵅ'=>'ᵅ','ᵆ'=>'ᵆ','ᵇ'=>'ᵇ','ᵈ'=>'ᵈ','ᵉ'=>'ᵉ','ᵊ'=>'ᵊ','ᵋ'=>'ᵋ','ᵌ'=>'ᵌ','ᵍ'=>'ᵍ','ᵎ'=>'ᵎ','ᵏ'=>'ᵏ','ᵐ'=>'ᵐ','ᵑ'=>'ᵑ','ᵒ'=>'ᵒ','ᵓ'=>'ᵓ','ᵔ'=>'ᵔ','ᵕ'=>'ᵕ','ᵖ'=>'ᵖ','ᵗ'=>'ᵗ','ᵘ'=>'ᵘ','ᵙ'=>'ᵙ','ᵚ'=>'ᵚ','ᵛ'=>'ᵛ','ᵜ'=>'ᵜ','ᵝ'=>'ᵝ','ᵞ'=>'ᵞ','ᵟ'=>'ᵟ','ᵠ'=>'ᵠ','ᵡ'=>'ᵡ','ᵢ'=>'ᵢ','ᵣ'=>'ᵣ','ᵤ'=>'ᵤ','ᵥ'=>'ᵥ','ᵦ'=>'ᵦ','ᵧ'=>'ᵧ','ᵨ'=>'ᵨ','ᵩ'=>'ᵩ','ᵪ'=>'ᵪ','ᵫ'=>'ue','ᵬ'=>'ᵬ','ᵭ'=>'ᵭ','ᵮ'=>'ᵮ','ᵯ'=>'ᵯ','ᵰ'=>'ᵰ','ᵱ'=>'ᵱ','ᵲ'=>'ᵲ','ᵳ'=>'ᵳ','ᵴ'=>'ᵴ','ᵵ'=>'ᵵ','ᵶ'=>'ᵶ','ᵷ'=>'ᵷ','ᵸ'=>'ᵸ','ᵹ'=>'ᵹ','ᵺ'=>'ᵺ','ᵻ'=>'ᵻ','ᵼ'=>'ᵼ','ᵽ'=>'ᵽ','ᵾ'=>'ᵾ','ᵿ'=>'ᵿ','ᶀ'=>'ᶀ','ᶁ'=>'ᶁ','ᶂ'=>'ᶂ','ᶃ'=>'ᶃ','ᶄ'=>'ᶄ','ᶅ'=>'ᶅ','ᶆ'=>'ᶆ','ᶇ'=>'ᶇ','ᶈ'=>'ᶈ','ᶉ'=>'ᶉ','ᶊ'=>'ᶊ','ᶋ'=>'ᶋ','ᶌ'=>'ᶌ','ᶍ'=>'ᶍ','ᶎ'=>'ᶎ','ᶏ'=>'ᶏ','ᶐ'=>'ᶐ','ᶑ'=>'ᶑ','ᶒ'=>'ᶒ','ᶓ'=>'ᶓ','ᶔ'=>'ᶔ','ᶕ'=>'ᶕ','ᶖ'=>'ᶖ','ᶗ'=>'ᶗ','ᶘ'=>'ᶘ','ᶙ'=>'ᶙ','ᶚ'=>'ᶚ','ᶛ'=>'ᶛ','ᶜ'=>'ᶜ','ᶝ'=>'ᶝ','ᶞ'=>'ᶞ','ᶟ'=>'ᶟ','ᶠ'=>'ᶠ','ᶡ'=>'ᶡ','ᶢ'=>'ᶢ','ᶣ'=>'ᶣ','ᶤ'=>'ᶤ','ᶥ'=>'ᶥ','ᶦ'=>'ᶦ','ᶧ'=>'ᶧ','ᶨ'=>'ᶨ','ᶩ'=>'ᶩ','ᶪ'=>'ᶪ','ᶫ'=>'ᶫ','ᶬ'=>'ᶬ','ᶭ'=>'ᶭ','ᶮ'=>'ᶮ','ᶯ'=>'ᶯ','ᶰ'=>'ᶰ','ᶱ'=>'ᶱ','ᶲ'=>'ᶲ','ᶳ'=>'ᶳ','ᶴ'=>'ᶴ','ᶵ'=>'ᶵ','ᶶ'=>'ᶶ','ᶷ'=>'ᶷ','ᶸ'=>'ᶸ','ᶹ'=>'ᶹ','ᶺ'=>'ᶺ','ᶻ'=>'ᶻ','ᶼ'=>'ᶼ','ᶽ'=>'ᶽ','ᶾ'=>'ᶾ','ᶿ'=>'ᶿ','᷀'=>'᷀','᷁'=>'᷁','᷂'=>'᷂','᷃'=>'᷃','᷄'=>'᷄','᷅'=>'᷅','᷆'=>'᷆','᷇'=>'᷇','᷈'=>'᷈','᷉'=>'᷉','᷊'=>'᷊','᷾'=>'᷾','᷿'=>'᷿','Ḁ'=>'ḁ','ḁ'=>'ḁ','Ḃ'=>'ḃ','ḃ'=>'ḃ','Ḅ'=>'ḅ','ḅ'=>'ḅ','Ḇ'=>'ḇ','ḇ'=>'ḇ','Ḉ'=>'ḉ','ḉ'=>'ḉ','Ḋ'=>'ḋ','ḋ'=>'ḋ','Ḍ'=>'ḍ','ḍ'=>'ḍ','Ḏ'=>'ḏ','ḏ'=>'ḏ','Ḑ'=>'ḑ','ḑ'=>'ḑ','Ḓ'=>'ḓ','ḓ'=>'ḓ','Ḕ'=>'ḕ','ḕ'=>'ḕ','Ḗ'=>'ḗ','ḗ'=>'ḗ','Ḙ'=>'ḙ','ḙ'=>'ḙ','Ḛ'=>'ḛ','ḛ'=>'ḛ','Ḝ'=>'ḝ','ḝ'=>'ḝ','Ḟ'=>'ḟ','ḟ'=>'ḟ','Ḡ'=>'ḡ','ḡ'=>'ḡ','Ḣ'=>'ḣ','ḣ'=>'ḣ','Ḥ'=>'ḥ','ḥ'=>'ḥ','Ḧ'=>'ḧ','ḧ'=>'ḧ','Ḩ'=>'ḩ','ḩ'=>'ḩ','Ḫ'=>'ḫ','ḫ'=>'ḫ','Ḭ'=>'ḭ','ḭ'=>'ḭ','Ḯ'=>'ḯ','ḯ'=>'ḯ','Ḱ'=>'ḱ','ḱ'=>'ḱ','Ḳ'=>'ḳ','ḳ'=>'ḳ','Ḵ'=>'ḵ','ḵ'=>'ḵ','Ḷ'=>'ḷ','ḷ'=>'ḷ','Ḹ'=>'ḹ','ḹ'=>'ḹ','Ḻ'=>'ḻ','ḻ'=>'ḻ','Ḽ'=>'ḽ','ḽ'=>'ḽ','Ḿ'=>'ḿ','ḿ'=>'ḿ','Ṁ'=>'ṁ','ṁ'=>'ṁ','Ṃ'=>'ṃ','ṃ'=>'ṃ','Ṅ'=>'ṅ','ṅ'=>'ṅ','Ṇ'=>'ṇ','ṇ'=>'ṇ','Ṉ'=>'ṉ','ṉ'=>'ṉ','Ṋ'=>'ṋ','ṋ'=>'ṋ','Ṍ'=>'ṍ','ṍ'=>'ṍ','Ṏ'=>'ṏ','ṏ'=>'ṏ','Ṑ'=>'ṑ','ṑ'=>'ṑ','Ṓ'=>'ṓ','ṓ'=>'ṓ','Ṕ'=>'ṕ','ṕ'=>'ṕ','Ṗ'=>'ṗ','ṗ'=>'ṗ','Ṙ'=>'ṙ','ṙ'=>'ṙ','Ṛ'=>'ṛ','ṛ'=>'ṛ','Ṝ'=>'ṝ','ṝ'=>'ṝ','Ṟ'=>'ṟ','ṟ'=>'ṟ','Ṡ'=>'ṡ','ṡ'=>'ṡ','Ṣ'=>'ṣ','ṣ'=>'ṣ','Ṥ'=>'ṥ','ṥ'=>'ṥ','Ṧ'=>'ṧ','ṧ'=>'ṧ','Ṩ'=>'ṩ','ṩ'=>'ṩ','Ṫ'=>'ṫ','ṫ'=>'ṫ','Ṭ'=>'ṭ','ṭ'=>'ṭ','Ṯ'=>'ṯ','ṯ'=>'ṯ','Ṱ'=>'ṱ','ṱ'=>'ṱ','Ṳ'=>'ṳ','ṳ'=>'ṳ','Ṵ'=>'ṵ','ṵ'=>'ṵ','Ṷ'=>'ṷ','ṷ'=>'ṷ','Ṹ'=>'ṹ','ṹ'=>'ṹ','Ṻ'=>'ṻ','ṻ'=>'ṻ','Ṽ'=>'ṽ','ṽ'=>'ṽ','Ṿ'=>'ṿ','ṿ'=>'ṿ','Ẁ'=>'ẁ','ẁ'=>'ẁ','Ẃ'=>'ẃ','ẃ'=>'ẃ','Ẅ'=>'ẅ','ẅ'=>'ẅ','Ẇ'=>'ẇ','ẇ'=>'ẇ','Ẉ'=>'ẉ','ẉ'=>'ẉ','Ẋ'=>'ẋ','ẋ'=>'ẋ','Ẍ'=>'ẍ','ẍ'=>'ẍ','Ẏ'=>'ẏ','ẏ'=>'ẏ','Ẑ'=>'ẑ','ẑ'=>'ẑ','Ẓ'=>'ẓ','ẓ'=>'ẓ','Ẕ'=>'ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẚ'=>'ẚ','ẛ'=>'ẛ','Ạ'=>'ạ','ạ'=>'ạ','Ả'=>'ả','ả'=>'ả','Ấ'=>'ấ','ấ'=>'ấ','Ầ'=>'ầ','ầ'=>'ầ','Ẩ'=>'ẩ','ẩ'=>'ẩ','Ẫ'=>'ẫ','ẫ'=>'ẫ','Ậ'=>'ậ','ậ'=>'ậ','Ắ'=>'ắ','ắ'=>'ắ','Ằ'=>'ằ','ằ'=>'ằ','Ẳ'=>'ẳ','ẳ'=>'ẳ','Ẵ'=>'ẵ','ẵ'=>'ẵ','Ặ'=>'ặ','ặ'=>'ặ','Ẹ'=>'ẹ','ẹ'=>'ẹ','Ẻ'=>'ẻ','ẻ'=>'ẻ','Ẽ'=>'ẽ','ẽ'=>'ẽ','Ế'=>'ế','ế'=>'ế','Ề'=>'ề','ề'=>'ề','Ể'=>'ể','ể'=>'ể','Ễ'=>'ễ','ễ'=>'ễ','Ệ'=>'ệ','ệ'=>'ệ','Ỉ'=>'ỉ','ỉ'=>'ỉ','Ị'=>'ị','ị'=>'ị','Ọ'=>'ọ','ọ'=>'ọ','Ỏ'=>'ỏ','ỏ'=>'ỏ','Ố'=>'ố','ố'=>'ố','Ồ'=>'ồ','ồ'=>'ồ','Ổ'=>'ổ','ổ'=>'ổ','Ỗ'=>'ỗ','ỗ'=>'ỗ','Ộ'=>'ộ','ộ'=>'ộ','Ớ'=>'ớ','ớ'=>'ớ','Ờ'=>'ờ','ờ'=>'ờ','Ở'=>'ở','ở'=>'ở','Ỡ'=>'ỡ','ỡ'=>'ỡ','Ợ'=>'ợ','ợ'=>'ợ','Ụ'=>'ụ','ụ'=>'ụ','Ủ'=>'ủ','ủ'=>'ủ','Ứ'=>'ứ','ứ'=>'ứ','Ừ'=>'ừ','ừ'=>'ừ','Ử'=>'ử','ử'=>'ử','Ữ'=>'ữ','ữ'=>'ữ','Ự'=>'ự','ự'=>'ự','Ỳ'=>'ỳ','ỳ'=>'ỳ','Ỵ'=>'ỵ','ỵ'=>'ỵ','Ỷ'=>'ỷ','ỷ'=>'ỷ','Ỹ'=>'ỹ','ỹ'=>'ỹ','ἀ'=>'ἀ','ἁ'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἄ','ἅ'=>'ἅ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'ἀ','Ἁ'=>'ἁ','Ἂ'=>'ἂ','Ἃ'=>'ἃ','Ἄ'=>'ἄ','Ἅ'=>'ἅ','Ἆ'=>'ἆ','Ἇ'=>'ἇ','ἐ'=>'ἐ','ἑ'=>'ἑ','ἒ'=>'ἒ','ἓ'=>'ἓ','ἔ'=>'ἔ','ἕ'=>'ἕ','Ἐ'=>'ἐ','Ἑ'=>'ἑ','Ἒ'=>'ἒ','Ἓ'=>'ἓ','Ἔ'=>'ἔ','Ἕ'=>'ἕ','ἠ'=>'ἠ','ἡ'=>'ἡ','ἢ'=>'ἢ','ἣ'=>'ἣ','ἤ'=>'ἤ','ἥ'=>'ἥ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'ἠ','Ἡ'=>'ἡ','Ἢ'=>'ἢ','Ἣ'=>'ἣ','Ἤ'=>'ἤ','Ἥ'=>'ἥ','Ἦ'=>'ἦ','Ἧ'=>'ἧ','ἰ'=>'ἰ','ἱ'=>'ἱ','ἲ'=>'ἲ','ἳ'=>'ἳ','ἴ'=>'ἴ','ἵ'=>'ἵ','ἶ'=>'ἶ','ἷ'=>'ἷ','Ἰ'=>'ἰ','Ἱ'=>'ἱ','Ἲ'=>'ἲ','Ἳ'=>'ἳ','Ἴ'=>'ἴ','Ἵ'=>'ἵ','Ἶ'=>'ἶ','Ἷ'=>'ἷ','ὀ'=>'ὀ','ὁ'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὄ','ὅ'=>'ὅ','Ὀ'=>'ὀ','Ὁ'=>'ὁ','Ὂ'=>'ὂ','Ὃ'=>'ὃ','Ὄ'=>'ὄ','Ὅ'=>'ὅ','ὐ'=>'ὐ','ὑ'=>'ὑ','ὒ'=>'ὒ','ὓ'=>'ὓ','ὔ'=>'ὔ','ὕ'=>'ὕ','ὖ'=>'ὖ','ὗ'=>'ὗ','Ὑ'=>'ὑ','Ὓ'=>'ὓ','Ὕ'=>'ὕ','Ὗ'=>'ὗ','ὠ'=>'ὠ','ὡ'=>'ὡ','ὢ'=>'ὢ','ὣ'=>'ὣ','ὤ'=>'ὤ','ὥ'=>'ὥ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'ὠ','Ὡ'=>'ὡ','Ὢ'=>'ὢ','Ὣ'=>'ὣ','Ὤ'=>'ὤ','Ὥ'=>'ὥ','Ὦ'=>'ὦ','Ὧ'=>'ὧ','ὰ'=>'ὰ','ά'=>'ά','ὲ'=>'ὲ','έ'=>'έ','ὴ'=>'ὴ','ή'=>'ή','ὶ'=>'ὶ','ί'=>'ί','ὸ'=>'ὸ','ό'=>'ό','ὺ'=>'ὺ','ύ'=>'ύ','ὼ'=>'ὼ','ώ'=>'ώ','ᾀ'=>'ᾀ','ᾁ'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ᾄ','ᾅ'=>'ᾅ','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾀ','ᾉ'=>'ᾁ','ᾊ'=>'ᾂ','ᾋ'=>'ᾃ','ᾌ'=>'ᾄ','ᾍ'=>'ᾅ','ᾎ'=>'ᾆ','ᾏ'=>'ᾇ','ᾐ'=>'ᾐ','ᾑ'=>'ᾑ','ᾒ'=>'ᾒ','ᾓ'=>'ᾓ','ᾔ'=>'ᾔ','ᾕ'=>'ᾕ','ᾖ'=>'ᾖ','ᾗ'=>'ᾗ','ᾘ'=>'ᾐ','ᾙ'=>'ᾑ','ᾚ'=>'ᾒ','ᾛ'=>'ᾓ','ᾜ'=>'ᾔ','ᾝ'=>'ᾕ','ᾞ'=>'ᾖ','ᾟ'=>'ᾗ','ᾠ'=>'ᾠ','ᾡ'=>'ᾡ','ᾢ'=>'ᾢ','ᾣ'=>'ᾣ','ᾤ'=>'ᾤ','ᾥ'=>'ᾥ','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾠ','ᾩ'=>'ᾡ','ᾪ'=>'ᾢ','ᾫ'=>'ᾣ','ᾬ'=>'ᾤ','ᾭ'=>'ᾥ','ᾮ'=>'ᾦ','ᾯ'=>'ᾧ','ᾰ'=>'ᾰ','ᾱ'=>'ᾱ','ᾲ'=>'ᾲ','ᾳ'=>'ᾳ','ᾴ'=>'ᾴ','ᾶ'=>'ᾶ','ᾷ'=>'ᾷ','Ᾰ'=>'ᾰ','Ᾱ'=>'ᾱ','Ὰ'=>'ὰ','Ά'=>'ά','ᾼ'=>'ᾳ','ι'=>'ι','ῂ'=>'ῂ','ῃ'=>'ῃ','ῄ'=>'ῄ','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'ὲ','Έ'=>'έ','Ὴ'=>'ὴ','Ή'=>'ή','ῌ'=>'ῃ','ῐ'=>'ῐ','ῑ'=>'ῑ','ῒ'=>'ῒ','ΐ'=>'ΐ','ῖ'=>'ῖ','ῗ'=>'ῗ','Ῐ'=>'ῐ','Ῑ'=>'ῑ','Ὶ'=>'ὶ','Ί'=>'ί','ῠ'=>'ῠ','ῡ'=>'ῡ','ῢ'=>'ῢ','ΰ'=>'ΰ','ῤ'=>'ῤ','ῥ'=>'ῥ','ῦ'=>'ῦ','ῧ'=>'ῧ','Ῠ'=>'ῠ','Ῡ'=>'ῡ','Ὺ'=>'ὺ','Ύ'=>'ύ','Ῥ'=>'ῥ','ῲ'=>'ῲ','ῳ'=>'ῳ','ῴ'=>'ῴ','ῶ'=>'ῶ','ῷ'=>'ῷ','Ὸ'=>'ὸ','Ό'=>'ό','Ὼ'=>'ὼ','Ώ'=>'ώ','ῼ'=>'ῳ'); diff --git a/phpBB/includes/utf/data/search_indexer_31.php b/phpBB/includes/utf/data/search_indexer_31.php index 191365a313..85961d36fc 100644 --- a/phpBB/includes/utf/data/search_indexer_31.php +++ b/phpBB/includes/utf/data/search_indexer_31.php @@ -1 +1 @@ -<?php return array('豈'=>'豈','更'=>'更','車'=>'車','賈'=>'賈','滑'=>'滑','串'=>'串','句'=>'句','龜'=>'龜','龜'=>'龜','契'=>'契','金'=>'金','喇'=>'喇','奈'=>'奈','懶'=>'懶','癩'=>'癩','羅'=>'羅','蘿'=>'蘿','螺'=>'螺','裸'=>'裸','邏'=>'邏','樂'=>'樂','洛'=>'洛','烙'=>'烙','珞'=>'珞','落'=>'落','酪'=>'酪','駱'=>'駱','亂'=>'亂','卵'=>'卵','欄'=>'欄','爛'=>'爛','蘭'=>'蘭','鸞'=>'鸞','嵐'=>'嵐','濫'=>'濫','藍'=>'藍','襤'=>'襤','拉'=>'拉','臘'=>'臘','蠟'=>'蠟','廊'=>'廊','朗'=>'朗','浪'=>'浪','狼'=>'狼','郎'=>'郎','來'=>'來','冷'=>'冷','勞'=>'勞','擄'=>'擄','櫓'=>'櫓','爐'=>'爐','盧'=>'盧','老'=>'老','蘆'=>'蘆','虜'=>'虜','路'=>'路','露'=>'露','魯'=>'魯','鷺'=>'鷺','碌'=>'碌','祿'=>'祿','綠'=>'綠','菉'=>'菉','錄'=>'錄','鹿'=>'鹿','論'=>'論','壟'=>'壟','弄'=>'弄','籠'=>'籠','聾'=>'聾','牢'=>'牢','磊'=>'磊','賂'=>'賂','雷'=>'雷','壘'=>'壘','屢'=>'屢','樓'=>'樓','淚'=>'淚','漏'=>'漏','累'=>'累','縷'=>'縷','陋'=>'陋','勒'=>'勒','肋'=>'肋','凜'=>'凜','凌'=>'凌','稜'=>'稜','綾'=>'綾','菱'=>'菱','陵'=>'陵','讀'=>'讀','拏'=>'拏','樂'=>'樂','諾'=>'諾','丹'=>'丹','寧'=>'寧','怒'=>'怒','率'=>'率','異'=>'異','北'=>'北','磻'=>'磻','便'=>'便','復'=>'復','不'=>'不','泌'=>'泌','數'=>'數','索'=>'索','參'=>'參','塞'=>'塞','省'=>'省','葉'=>'葉','說'=>'說','殺'=>'殺','辰'=>'辰','沈'=>'沈','拾'=>'拾','若'=>'若','掠'=>'掠','略'=>'略','亮'=>'亮','兩'=>'兩','凉'=>'凉','梁'=>'梁','糧'=>'糧','良'=>'良','諒'=>'諒','量'=>'量','勵'=>'勵','呂'=>'呂','女'=>'女','廬'=>'廬','旅'=>'旅','濾'=>'濾','礪'=>'礪','閭'=>'閭','驪'=>'驪','麗'=>'麗','黎'=>'黎','力'=>'力','曆'=>'曆','歷'=>'歷','轢'=>'轢','年'=>'年','憐'=>'憐','戀'=>'戀','撚'=>'撚','漣'=>'漣','煉'=>'煉','璉'=>'璉','秊'=>'秊','練'=>'練','聯'=>'聯','輦'=>'輦','蓮'=>'蓮','連'=>'連','鍊'=>'鍊','列'=>'列','劣'=>'劣','咽'=>'咽','烈'=>'烈','裂'=>'裂','說'=>'說','廉'=>'廉','念'=>'念','捻'=>'捻','殮'=>'殮','簾'=>'簾','獵'=>'獵','令'=>'令','囹'=>'囹','寧'=>'寧','嶺'=>'嶺','怜'=>'怜','玲'=>'玲','瑩'=>'瑩','羚'=>'羚','聆'=>'聆','鈴'=>'鈴','零'=>'零','靈'=>'靈','領'=>'領','例'=>'例','禮'=>'禮','醴'=>'醴','隸'=>'隸','惡'=>'惡','了'=>'了','僚'=>'僚','寮'=>'寮','尿'=>'尿','料'=>'料','樂'=>'樂','燎'=>'燎','療'=>'療','蓼'=>'蓼','遼'=>'遼','龍'=>'龍','暈'=>'暈','阮'=>'阮','劉'=>'劉','杻'=>'杻','柳'=>'柳','流'=>'流','溜'=>'溜','琉'=>'琉','留'=>'留','硫'=>'硫','紐'=>'紐','類'=>'類','六'=>'六','戮'=>'戮','陸'=>'陸','倫'=>'倫','崙'=>'崙','淪'=>'淪','輪'=>'輪','律'=>'律','慄'=>'慄','栗'=>'栗','率'=>'率','隆'=>'隆','利'=>'利','吏'=>'吏','履'=>'履','易'=>'易','李'=>'李','梨'=>'梨','泥'=>'泥','理'=>'理','痢'=>'痢','罹'=>'罹','裏'=>'裏','裡'=>'裡','里'=>'里','離'=>'離','匿'=>'匿','溺'=>'溺','吝'=>'吝','燐'=>'燐','璘'=>'璘','藺'=>'藺','隣'=>'隣','鱗'=>'鱗','麟'=>'麟','林'=>'林','淋'=>'淋','臨'=>'臨','立'=>'立','笠'=>'笠','粒'=>'粒','狀'=>'狀','炙'=>'炙','識'=>'識','什'=>'什','茶'=>'茶','刺'=>'刺','切'=>'切','度'=>'度','拓'=>'拓','糖'=>'糖','宅'=>'宅','洞'=>'洞','暴'=>'暴','輻'=>'輻','行'=>'行','降'=>'降','見'=>'見','廓'=>'廓','兀'=>'兀','嗀'=>'嗀','﨎'=>'﨎','﨏'=>'﨏','塚'=>'塚','﨑'=>'﨑','晴'=>'晴','﨓'=>'﨓','﨔'=>'﨔','凞'=>'凞','猪'=>'猪','益'=>'益','礼'=>'礼','神'=>'神','祥'=>'祥','福'=>'福','靖'=>'靖','精'=>'精','羽'=>'羽','﨟'=>'﨟','蘒'=>'蘒','﨡'=>'﨡','諸'=>'諸','﨣'=>'﨣','﨤'=>'﨤','逸'=>'逸','都'=>'都','﨧'=>'﨧','﨨'=>'﨨','﨩'=>'﨩','飯'=>'飯','飼'=>'飼','館'=>'館','鶴'=>'鶴','侮'=>'侮','僧'=>'僧','免'=>'免','勉'=>'勉','勤'=>'勤','卑'=>'卑','喝'=>'喝','嘆'=>'嘆','器'=>'器','塀'=>'塀','墨'=>'墨','層'=>'層','屮'=>'屮','悔'=>'悔','慨'=>'慨','憎'=>'憎','懲'=>'懲','敏'=>'敏','既'=>'既','暑'=>'暑','梅'=>'梅','海'=>'海','渚'=>'渚','漢'=>'漢','煮'=>'煮','爫'=>'爫','琢'=>'琢','碑'=>'碑','社'=>'社','祉'=>'祉','祈'=>'祈','祐'=>'祐','祖'=>'祖','祝'=>'祝','禍'=>'禍','禎'=>'禎','穀'=>'穀','突'=>'突','節'=>'節','練'=>'練','縉'=>'縉','繁'=>'繁','署'=>'署','者'=>'者','臭'=>'臭','艹'=>'艹','艹'=>'艹','著'=>'著','褐'=>'褐','視'=>'視','謁'=>'謁','謹'=>'謹','賓'=>'賓','贈'=>'贈','辶'=>'辶','逸'=>'逸','難'=>'難','響'=>'響','頻'=>'頻','並'=>'並','况'=>'况','全'=>'全','侀'=>'侀','充'=>'充','冀'=>'冀','勇'=>'勇','勺'=>'勺','喝'=>'喝','啕'=>'啕','喙'=>'喙','嗢'=>'嗢','塚'=>'塚','墳'=>'墳','奄'=>'奄','奔'=>'奔','婢'=>'婢','嬨'=>'嬨','廒'=>'廒','廙'=>'廙','彩'=>'彩','徭'=>'徭','惘'=>'惘','慎'=>'慎','愈'=>'愈','憎'=>'憎','慠'=>'慠','懲'=>'懲','戴'=>'戴','揄'=>'揄','搜'=>'搜','摒'=>'摒','敖'=>'敖','晴'=>'晴','朗'=>'朗','望'=>'望','杖'=>'杖','歹'=>'歹','殺'=>'殺','流'=>'流','滛'=>'滛','滋'=>'滋','漢'=>'漢','瀞'=>'瀞','煮'=>'煮','瞧'=>'瞧','爵'=>'爵','犯'=>'犯','猪'=>'猪','瑱'=>'瑱','甆'=>'甆','画'=>'画','瘝'=>'瘝','瘟'=>'瘟','益'=>'益','盛'=>'盛','直'=>'直','睊'=>'睊','着'=>'着','磌'=>'磌','窱'=>'窱','節'=>'節','类'=>'类','絛'=>'絛','練'=>'練','缾'=>'缾','者'=>'者','荒'=>'荒','華'=>'華','蝹'=>'蝹','襁'=>'襁','覆'=>'覆','視'=>'視','調'=>'調','諸'=>'諸','請'=>'請','謁'=>'謁','諾'=>'諾','諭'=>'諭','謹'=>'謹','變'=>'變','贈'=>'贈','輸'=>'輸','遲'=>'遲','醙'=>'醙','鉶'=>'鉶','陼'=>'陼','難'=>'難','靖'=>'靖','韛'=>'韛','響'=>'響','頋'=>'頋','頻'=>'頻','鬒'=>'鬒','龜'=>'龜','𢡊'=>'𢡊','𢡄'=>'𢡄','𣏕'=>'𣏕','㮝'=>'㮝','䀘'=>'䀘','䀹'=>'䀹','𥉉'=>'𥉉','𥳐'=>'𥳐','𧻓'=>'𧻓','齃'=>'齃','龎'=>'龎','ff'=>'ff','fi'=>'fi','fl'=>'fl','ffi'=>'ffi','ffl'=>'ffl','ſt'=>'ſt','st'=>'st','ﬓ'=>'ﬓ','ﬔ'=>'ﬔ','ﬕ'=>'ﬕ','ﬖ'=>'ﬖ','ﬗ'=>'ﬗ','יִ'=>'יִ','ﬞ'=>'ﬞ','ײַ'=>'ײַ','ﬠ'=>'ﬠ','ﬡ'=>'ﬡ','ﬢ'=>'ﬢ','ﬣ'=>'ﬣ','ﬤ'=>'ﬤ','ﬥ'=>'ﬥ','ﬦ'=>'ﬦ','ﬧ'=>'ﬧ','ﬨ'=>'ﬨ','שׁ'=>'שׁ','שׂ'=>'שׂ','שּׁ'=>'שּׁ','שּׂ'=>'שּׂ','אַ'=>'אַ','אָ'=>'אָ','אּ'=>'אּ','בּ'=>'בּ','גּ'=>'גּ','דּ'=>'דּ','הּ'=>'הּ','וּ'=>'וּ','זּ'=>'זּ','טּ'=>'טּ','יּ'=>'יּ','ךּ'=>'ךּ','כּ'=>'כּ','לּ'=>'לּ','מּ'=>'מּ','נּ'=>'נּ','סּ'=>'סּ','ףּ'=>'ףּ','פּ'=>'פּ','צּ'=>'צּ','קּ'=>'קּ','רּ'=>'רּ','שּ'=>'שּ','תּ'=>'תּ','וֹ'=>'וֹ','בֿ'=>'בֿ','כֿ'=>'כֿ','פֿ'=>'פֿ','ﭏ'=>'ﭏ','ﭐ'=>'ﭐ','ﭑ'=>'ﭑ','ﭒ'=>'ﭒ','ﭓ'=>'ﭓ','ﭔ'=>'ﭔ','ﭕ'=>'ﭕ','ﭖ'=>'ﭖ','ﭗ'=>'ﭗ','ﭘ'=>'ﭘ','ﭙ'=>'ﭙ','ﭚ'=>'ﭚ','ﭛ'=>'ﭛ','ﭜ'=>'ﭜ','ﭝ'=>'ﭝ','ﭞ'=>'ﭞ','ﭟ'=>'ﭟ','ﭠ'=>'ﭠ','ﭡ'=>'ﭡ','ﭢ'=>'ﭢ','ﭣ'=>'ﭣ','ﭤ'=>'ﭤ','ﭥ'=>'ﭥ','ﭦ'=>'ﭦ','ﭧ'=>'ﭧ','ﭨ'=>'ﭨ','ﭩ'=>'ﭩ','ﭪ'=>'ﭪ','ﭫ'=>'ﭫ','ﭬ'=>'ﭬ','ﭭ'=>'ﭭ','ﭮ'=>'ﭮ','ﭯ'=>'ﭯ','ﭰ'=>'ﭰ','ﭱ'=>'ﭱ','ﭲ'=>'ﭲ','ﭳ'=>'ﭳ','ﭴ'=>'ﭴ','ﭵ'=>'ﭵ','ﭶ'=>'ﭶ','ﭷ'=>'ﭷ','ﭸ'=>'ﭸ','ﭹ'=>'ﭹ','ﭺ'=>'ﭺ','ﭻ'=>'ﭻ','ﭼ'=>'ﭼ','ﭽ'=>'ﭽ','ﭾ'=>'ﭾ','ﭿ'=>'ﭿ','ﮀ'=>'ﮀ','ﮁ'=>'ﮁ','ﮂ'=>'ﮂ','ﮃ'=>'ﮃ','ﮄ'=>'ﮄ','ﮅ'=>'ﮅ','ﮆ'=>'ﮆ','ﮇ'=>'ﮇ','ﮈ'=>'ﮈ','ﮉ'=>'ﮉ','ﮊ'=>'ﮊ','ﮋ'=>'ﮋ','ﮌ'=>'ﮌ','ﮍ'=>'ﮍ','ﮎ'=>'ﮎ','ﮏ'=>'ﮏ','ﮐ'=>'ﮐ','ﮑ'=>'ﮑ','ﮒ'=>'ﮒ','ﮓ'=>'ﮓ','ﮔ'=>'ﮔ','ﮕ'=>'ﮕ','ﮖ'=>'ﮖ','ﮗ'=>'ﮗ','ﮘ'=>'ﮘ','ﮙ'=>'ﮙ','ﮚ'=>'ﮚ','ﮛ'=>'ﮛ','ﮜ'=>'ﮜ','ﮝ'=>'ﮝ','ﮞ'=>'ﮞ','ﮟ'=>'ﮟ','ﮠ'=>'ﮠ','ﮡ'=>'ﮡ','ﮢ'=>'ﮢ','ﮣ'=>'ﮣ','ﮤ'=>'ﮤ','ﮥ'=>'ﮥ','ﮦ'=>'ﮦ','ﮧ'=>'ﮧ','ﮨ'=>'ﮨ','ﮩ'=>'ﮩ','ﮪ'=>'ﮪ','ﮫ'=>'ﮫ','ﮬ'=>'ﮬ','ﮭ'=>'ﮭ','ﮮ'=>'ﮮ','ﮯ'=>'ﮯ','ﮰ'=>'ﮰ','ﮱ'=>'ﮱ','ﯓ'=>'ﯓ','ﯔ'=>'ﯔ','ﯕ'=>'ﯕ','ﯖ'=>'ﯖ','ﯗ'=>'ﯗ','ﯘ'=>'ﯘ','ﯙ'=>'ﯙ','ﯚ'=>'ﯚ','ﯛ'=>'ﯛ','ﯜ'=>'ﯜ','ﯝ'=>'ﯝ','ﯞ'=>'ﯞ','ﯟ'=>'ﯟ','ﯠ'=>'ﯠ','ﯡ'=>'ﯡ','ﯢ'=>'ﯢ','ﯣ'=>'ﯣ','ﯤ'=>'ﯤ','ﯥ'=>'ﯥ','ﯦ'=>'ﯦ','ﯧ'=>'ﯧ','ﯨ'=>'ﯨ','ﯩ'=>'ﯩ','ﯪ'=>'ﯪ','ﯫ'=>'ﯫ','ﯬ'=>'ﯬ','ﯭ'=>'ﯭ','ﯮ'=>'ﯮ','ﯯ'=>'ﯯ','ﯰ'=>'ﯰ','ﯱ'=>'ﯱ','ﯲ'=>'ﯲ','ﯳ'=>'ﯳ','ﯴ'=>'ﯴ','ﯵ'=>'ﯵ','ﯶ'=>'ﯶ','ﯷ'=>'ﯷ','ﯸ'=>'ﯸ','ﯹ'=>'ﯹ','ﯺ'=>'ﯺ','ﯻ'=>'ﯻ','ﯼ'=>'ﯼ','ﯽ'=>'ﯽ','ﯾ'=>'ﯾ','ﯿ'=>'ﯿ','ﰀ'=>'ﰀ','ﰁ'=>'ﰁ','ﰂ'=>'ﰂ','ﰃ'=>'ﰃ','ﰄ'=>'ﰄ','ﰅ'=>'ﰅ','ﰆ'=>'ﰆ','ﰇ'=>'ﰇ','ﰈ'=>'ﰈ','ﰉ'=>'ﰉ','ﰊ'=>'ﰊ','ﰋ'=>'ﰋ','ﰌ'=>'ﰌ','ﰍ'=>'ﰍ','ﰎ'=>'ﰎ','ﰏ'=>'ﰏ','ﰐ'=>'ﰐ','ﰑ'=>'ﰑ','ﰒ'=>'ﰒ','ﰓ'=>'ﰓ','ﰔ'=>'ﰔ','ﰕ'=>'ﰕ','ﰖ'=>'ﰖ','ﰗ'=>'ﰗ','ﰘ'=>'ﰘ','ﰙ'=>'ﰙ','ﰚ'=>'ﰚ','ﰛ'=>'ﰛ','ﰜ'=>'ﰜ','ﰝ'=>'ﰝ','ﰞ'=>'ﰞ','ﰟ'=>'ﰟ','ﰠ'=>'ﰠ','ﰡ'=>'ﰡ','ﰢ'=>'ﰢ','ﰣ'=>'ﰣ','ﰤ'=>'ﰤ','ﰥ'=>'ﰥ','ﰦ'=>'ﰦ','ﰧ'=>'ﰧ','ﰨ'=>'ﰨ','ﰩ'=>'ﰩ','ﰪ'=>'ﰪ','ﰫ'=>'ﰫ','ﰬ'=>'ﰬ','ﰭ'=>'ﰭ','ﰮ'=>'ﰮ','ﰯ'=>'ﰯ','ﰰ'=>'ﰰ','ﰱ'=>'ﰱ','ﰲ'=>'ﰲ','ﰳ'=>'ﰳ','ﰴ'=>'ﰴ','ﰵ'=>'ﰵ','ﰶ'=>'ﰶ','ﰷ'=>'ﰷ','ﰸ'=>'ﰸ','ﰹ'=>'ﰹ','ﰺ'=>'ﰺ','ﰻ'=>'ﰻ','ﰼ'=>'ﰼ','ﰽ'=>'ﰽ','ﰾ'=>'ﰾ','ﰿ'=>'ﰿ','ﱀ'=>'ﱀ','ﱁ'=>'ﱁ','ﱂ'=>'ﱂ','ﱃ'=>'ﱃ','ﱄ'=>'ﱄ','ﱅ'=>'ﱅ','ﱆ'=>'ﱆ','ﱇ'=>'ﱇ','ﱈ'=>'ﱈ','ﱉ'=>'ﱉ','ﱊ'=>'ﱊ','ﱋ'=>'ﱋ','ﱌ'=>'ﱌ','ﱍ'=>'ﱍ','ﱎ'=>'ﱎ','ﱏ'=>'ﱏ','ﱐ'=>'ﱐ','ﱑ'=>'ﱑ','ﱒ'=>'ﱒ','ﱓ'=>'ﱓ','ﱔ'=>'ﱔ','ﱕ'=>'ﱕ','ﱖ'=>'ﱖ','ﱗ'=>'ﱗ','ﱘ'=>'ﱘ','ﱙ'=>'ﱙ','ﱚ'=>'ﱚ','ﱛ'=>'ﱛ','ﱜ'=>'ﱜ','ﱝ'=>'ﱝ','ﱞ'=>'ﱞ','ﱟ'=>'ﱟ','ﱠ'=>'ﱠ','ﱡ'=>'ﱡ','ﱢ'=>'ﱢ','ﱣ'=>'ﱣ','ﱤ'=>'ﱤ','ﱥ'=>'ﱥ','ﱦ'=>'ﱦ','ﱧ'=>'ﱧ','ﱨ'=>'ﱨ','ﱩ'=>'ﱩ','ﱪ'=>'ﱪ','ﱫ'=>'ﱫ','ﱬ'=>'ﱬ','ﱭ'=>'ﱭ','ﱮ'=>'ﱮ','ﱯ'=>'ﱯ','ﱰ'=>'ﱰ','ﱱ'=>'ﱱ','ﱲ'=>'ﱲ','ﱳ'=>'ﱳ','ﱴ'=>'ﱴ','ﱵ'=>'ﱵ','ﱶ'=>'ﱶ','ﱷ'=>'ﱷ','ﱸ'=>'ﱸ','ﱹ'=>'ﱹ','ﱺ'=>'ﱺ','ﱻ'=>'ﱻ','ﱼ'=>'ﱼ','ﱽ'=>'ﱽ','ﱾ'=>'ﱾ','ﱿ'=>'ﱿ','ﲀ'=>'ﲀ','ﲁ'=>'ﲁ','ﲂ'=>'ﲂ','ﲃ'=>'ﲃ','ﲄ'=>'ﲄ','ﲅ'=>'ﲅ','ﲆ'=>'ﲆ','ﲇ'=>'ﲇ','ﲈ'=>'ﲈ','ﲉ'=>'ﲉ','ﲊ'=>'ﲊ','ﲋ'=>'ﲋ','ﲌ'=>'ﲌ','ﲍ'=>'ﲍ','ﲎ'=>'ﲎ','ﲏ'=>'ﲏ','ﲐ'=>'ﲐ','ﲑ'=>'ﲑ','ﲒ'=>'ﲒ','ﲓ'=>'ﲓ','ﲔ'=>'ﲔ','ﲕ'=>'ﲕ','ﲖ'=>'ﲖ','ﲗ'=>'ﲗ','ﲘ'=>'ﲘ','ﲙ'=>'ﲙ','ﲚ'=>'ﲚ','ﲛ'=>'ﲛ','ﲜ'=>'ﲜ','ﲝ'=>'ﲝ','ﲞ'=>'ﲞ','ﲟ'=>'ﲟ','ﲠ'=>'ﲠ','ﲡ'=>'ﲡ','ﲢ'=>'ﲢ','ﲣ'=>'ﲣ','ﲤ'=>'ﲤ','ﲥ'=>'ﲥ','ﲦ'=>'ﲦ','ﲧ'=>'ﲧ','ﲨ'=>'ﲨ','ﲩ'=>'ﲩ','ﲪ'=>'ﲪ','ﲫ'=>'ﲫ','ﲬ'=>'ﲬ','ﲭ'=>'ﲭ','ﲮ'=>'ﲮ','ﲯ'=>'ﲯ','ﲰ'=>'ﲰ','ﲱ'=>'ﲱ','ﲲ'=>'ﲲ','ﲳ'=>'ﲳ','ﲴ'=>'ﲴ','ﲵ'=>'ﲵ','ﲶ'=>'ﲶ','ﲷ'=>'ﲷ','ﲸ'=>'ﲸ','ﲹ'=>'ﲹ','ﲺ'=>'ﲺ','ﲻ'=>'ﲻ','ﲼ'=>'ﲼ','ﲽ'=>'ﲽ','ﲾ'=>'ﲾ','ﲿ'=>'ﲿ','ﳀ'=>'ﳀ','ﳁ'=>'ﳁ','ﳂ'=>'ﳂ','ﳃ'=>'ﳃ','ﳄ'=>'ﳄ','ﳅ'=>'ﳅ','ﳆ'=>'ﳆ','ﳇ'=>'ﳇ','ﳈ'=>'ﳈ','ﳉ'=>'ﳉ','ﳊ'=>'ﳊ','ﳋ'=>'ﳋ','ﳌ'=>'ﳌ','ﳍ'=>'ﳍ','ﳎ'=>'ﳎ','ﳏ'=>'ﳏ','ﳐ'=>'ﳐ','ﳑ'=>'ﳑ','ﳒ'=>'ﳒ','ﳓ'=>'ﳓ','ﳔ'=>'ﳔ','ﳕ'=>'ﳕ','ﳖ'=>'ﳖ','ﳗ'=>'ﳗ','ﳘ'=>'ﳘ','ﳙ'=>'ﳙ','ﳚ'=>'ﳚ','ﳛ'=>'ﳛ','ﳜ'=>'ﳜ','ﳝ'=>'ﳝ','ﳞ'=>'ﳞ','ﳟ'=>'ﳟ','ﳠ'=>'ﳠ','ﳡ'=>'ﳡ','ﳢ'=>'ﳢ','ﳣ'=>'ﳣ','ﳤ'=>'ﳤ','ﳥ'=>'ﳥ','ﳦ'=>'ﳦ','ﳧ'=>'ﳧ','ﳨ'=>'ﳨ','ﳩ'=>'ﳩ','ﳪ'=>'ﳪ','ﳫ'=>'ﳫ','ﳬ'=>'ﳬ','ﳭ'=>'ﳭ','ﳮ'=>'ﳮ','ﳯ'=>'ﳯ','ﳰ'=>'ﳰ','ﳱ'=>'ﳱ','ﳲ'=>'ﳲ','ﳳ'=>'ﳳ','ﳴ'=>'ﳴ','ﳵ'=>'ﳵ','ﳶ'=>'ﳶ','ﳷ'=>'ﳷ','ﳸ'=>'ﳸ','ﳹ'=>'ﳹ','ﳺ'=>'ﳺ','ﳻ'=>'ﳻ','ﳼ'=>'ﳼ','ﳽ'=>'ﳽ','ﳾ'=>'ﳾ','ﳿ'=>'ﳿ','ﴀ'=>'ﴀ','ﴁ'=>'ﴁ','ﴂ'=>'ﴂ','ﴃ'=>'ﴃ','ﴄ'=>'ﴄ','ﴅ'=>'ﴅ','ﴆ'=>'ﴆ','ﴇ'=>'ﴇ','ﴈ'=>'ﴈ','ﴉ'=>'ﴉ','ﴊ'=>'ﴊ','ﴋ'=>'ﴋ','ﴌ'=>'ﴌ','ﴍ'=>'ﴍ','ﴎ'=>'ﴎ','ﴏ'=>'ﴏ','ﴐ'=>'ﴐ','ﴑ'=>'ﴑ','ﴒ'=>'ﴒ','ﴓ'=>'ﴓ','ﴔ'=>'ﴔ','ﴕ'=>'ﴕ','ﴖ'=>'ﴖ','ﴗ'=>'ﴗ','ﴘ'=>'ﴘ','ﴙ'=>'ﴙ','ﴚ'=>'ﴚ','ﴛ'=>'ﴛ','ﴜ'=>'ﴜ','ﴝ'=>'ﴝ','ﴞ'=>'ﴞ','ﴟ'=>'ﴟ','ﴠ'=>'ﴠ','ﴡ'=>'ﴡ','ﴢ'=>'ﴢ','ﴣ'=>'ﴣ','ﴤ'=>'ﴤ','ﴥ'=>'ﴥ','ﴦ'=>'ﴦ','ﴧ'=>'ﴧ','ﴨ'=>'ﴨ','ﴩ'=>'ﴩ','ﴪ'=>'ﴪ','ﴫ'=>'ﴫ','ﴬ'=>'ﴬ','ﴭ'=>'ﴭ','ﴮ'=>'ﴮ','ﴯ'=>'ﴯ','ﴰ'=>'ﴰ','ﴱ'=>'ﴱ','ﴲ'=>'ﴲ','ﴳ'=>'ﴳ','ﴴ'=>'ﴴ','ﴵ'=>'ﴵ','ﴶ'=>'ﴶ','ﴷ'=>'ﴷ','ﴸ'=>'ﴸ','ﴹ'=>'ﴹ','ﴺ'=>'ﴺ','ﴻ'=>'ﴻ','ﴼ'=>'ﴼ','ﴽ'=>'ﴽ','ﵐ'=>'ﵐ','ﵑ'=>'ﵑ','ﵒ'=>'ﵒ','ﵓ'=>'ﵓ','ﵔ'=>'ﵔ','ﵕ'=>'ﵕ','ﵖ'=>'ﵖ','ﵗ'=>'ﵗ','ﵘ'=>'ﵘ','ﵙ'=>'ﵙ','ﵚ'=>'ﵚ','ﵛ'=>'ﵛ','ﵜ'=>'ﵜ','ﵝ'=>'ﵝ','ﵞ'=>'ﵞ','ﵟ'=>'ﵟ','ﵠ'=>'ﵠ','ﵡ'=>'ﵡ','ﵢ'=>'ﵢ','ﵣ'=>'ﵣ','ﵤ'=>'ﵤ','ﵥ'=>'ﵥ','ﵦ'=>'ﵦ','ﵧ'=>'ﵧ','ﵨ'=>'ﵨ','ﵩ'=>'ﵩ','ﵪ'=>'ﵪ','ﵫ'=>'ﵫ','ﵬ'=>'ﵬ','ﵭ'=>'ﵭ','ﵮ'=>'ﵮ','ﵯ'=>'ﵯ','ﵰ'=>'ﵰ','ﵱ'=>'ﵱ','ﵲ'=>'ﵲ','ﵳ'=>'ﵳ','ﵴ'=>'ﵴ','ﵵ'=>'ﵵ','ﵶ'=>'ﵶ','ﵷ'=>'ﵷ','ﵸ'=>'ﵸ','ﵹ'=>'ﵹ','ﵺ'=>'ﵺ','ﵻ'=>'ﵻ','ﵼ'=>'ﵼ','ﵽ'=>'ﵽ','ﵾ'=>'ﵾ','ﵿ'=>'ﵿ','ﶀ'=>'ﶀ','ﶁ'=>'ﶁ','ﶂ'=>'ﶂ','ﶃ'=>'ﶃ','ﶄ'=>'ﶄ','ﶅ'=>'ﶅ','ﶆ'=>'ﶆ','ﶇ'=>'ﶇ','ﶈ'=>'ﶈ','ﶉ'=>'ﶉ','ﶊ'=>'ﶊ','ﶋ'=>'ﶋ','ﶌ'=>'ﶌ','ﶍ'=>'ﶍ','ﶎ'=>'ﶎ','ﶏ'=>'ﶏ','ﶒ'=>'ﶒ','ﶓ'=>'ﶓ','ﶔ'=>'ﶔ','ﶕ'=>'ﶕ','ﶖ'=>'ﶖ','ﶗ'=>'ﶗ','ﶘ'=>'ﶘ','ﶙ'=>'ﶙ','ﶚ'=>'ﶚ','ﶛ'=>'ﶛ','ﶜ'=>'ﶜ','ﶝ'=>'ﶝ','ﶞ'=>'ﶞ','ﶟ'=>'ﶟ','ﶠ'=>'ﶠ','ﶡ'=>'ﶡ','ﶢ'=>'ﶢ','ﶣ'=>'ﶣ','ﶤ'=>'ﶤ','ﶥ'=>'ﶥ','ﶦ'=>'ﶦ','ﶧ'=>'ﶧ','ﶨ'=>'ﶨ','ﶩ'=>'ﶩ','ﶪ'=>'ﶪ','ﶫ'=>'ﶫ','ﶬ'=>'ﶬ','ﶭ'=>'ﶭ','ﶮ'=>'ﶮ','ﶯ'=>'ﶯ','ﶰ'=>'ﶰ','ﶱ'=>'ﶱ','ﶲ'=>'ﶲ','ﶳ'=>'ﶳ','ﶴ'=>'ﶴ','ﶵ'=>'ﶵ','ﶶ'=>'ﶶ','ﶷ'=>'ﶷ','ﶸ'=>'ﶸ','ﶹ'=>'ﶹ','ﶺ'=>'ﶺ','ﶻ'=>'ﶻ','ﶼ'=>'ﶼ','ﶽ'=>'ﶽ','ﶾ'=>'ﶾ','ﶿ'=>'ﶿ','ﷀ'=>'ﷀ','ﷁ'=>'ﷁ','ﷂ'=>'ﷂ','ﷃ'=>'ﷃ','ﷄ'=>'ﷄ','ﷅ'=>'ﷅ','ﷆ'=>'ﷆ','ﷇ'=>'ﷇ','ﷰ'=>'ﷰ','ﷱ'=>'ﷱ','ﷲ'=>'ﷲ','ﷳ'=>'ﷳ','ﷴ'=>'ﷴ','ﷵ'=>'ﷵ','ﷶ'=>'ﷶ','ﷷ'=>'ﷷ','ﷸ'=>'ﷸ','ﷹ'=>'ﷹ','ﷺ'=>'ﷺ','ﷻ'=>'ﷻ','︀'=>'︀','︁'=>'︁','︂'=>'︂','︃'=>'︃','︄'=>'︄','︅'=>'︅','︆'=>'︆','︇'=>'︇','︈'=>'︈','︉'=>'︉','︊'=>'︊','︋'=>'︋','︌'=>'︌','︍'=>'︍','︎'=>'︎','️'=>'️','︠'=>'︠','︡'=>'︡','︢'=>'︢','︣'=>'︣','ﹰ'=>'ﹰ','ﹱ'=>'ﹱ','ﹲ'=>'ﹲ','ﹳ'=>'ﹳ','ﹴ'=>'ﹴ','ﹶ'=>'ﹶ','ﹷ'=>'ﹷ','ﹸ'=>'ﹸ','ﹹ'=>'ﹹ','ﹺ'=>'ﹺ','ﹻ'=>'ﹻ','ﹼ'=>'ﹼ','ﹽ'=>'ﹽ','ﹾ'=>'ﹾ','ﹿ'=>'ﹿ','ﺀ'=>'ﺀ','ﺁ'=>'ﺁ','ﺂ'=>'ﺂ','ﺃ'=>'ﺃ','ﺄ'=>'ﺄ','ﺅ'=>'ﺅ','ﺆ'=>'ﺆ','ﺇ'=>'ﺇ','ﺈ'=>'ﺈ','ﺉ'=>'ﺉ','ﺊ'=>'ﺊ','ﺋ'=>'ﺋ','ﺌ'=>'ﺌ','ﺍ'=>'ﺍ','ﺎ'=>'ﺎ','ﺏ'=>'ﺏ','ﺐ'=>'ﺐ','ﺑ'=>'ﺑ','ﺒ'=>'ﺒ','ﺓ'=>'ﺓ','ﺔ'=>'ﺔ','ﺕ'=>'ﺕ','ﺖ'=>'ﺖ','ﺗ'=>'ﺗ','ﺘ'=>'ﺘ','ﺙ'=>'ﺙ','ﺚ'=>'ﺚ','ﺛ'=>'ﺛ','ﺜ'=>'ﺜ','ﺝ'=>'ﺝ','ﺞ'=>'ﺞ','ﺟ'=>'ﺟ','ﺠ'=>'ﺠ','ﺡ'=>'ﺡ','ﺢ'=>'ﺢ','ﺣ'=>'ﺣ','ﺤ'=>'ﺤ','ﺥ'=>'ﺥ','ﺦ'=>'ﺦ','ﺧ'=>'ﺧ','ﺨ'=>'ﺨ','ﺩ'=>'ﺩ','ﺪ'=>'ﺪ','ﺫ'=>'ﺫ','ﺬ'=>'ﺬ','ﺭ'=>'ﺭ','ﺮ'=>'ﺮ','ﺯ'=>'ﺯ','ﺰ'=>'ﺰ','ﺱ'=>'ﺱ','ﺲ'=>'ﺲ','ﺳ'=>'ﺳ','ﺴ'=>'ﺴ','ﺵ'=>'ﺵ','ﺶ'=>'ﺶ','ﺷ'=>'ﺷ','ﺸ'=>'ﺸ','ﺹ'=>'ﺹ','ﺺ'=>'ﺺ','ﺻ'=>'ﺻ','ﺼ'=>'ﺼ','ﺽ'=>'ﺽ','ﺾ'=>'ﺾ','ﺿ'=>'ﺿ','ﻀ'=>'ﻀ','ﻁ'=>'ﻁ','ﻂ'=>'ﻂ','ﻃ'=>'ﻃ','ﻄ'=>'ﻄ','ﻅ'=>'ﻅ','ﻆ'=>'ﻆ','ﻇ'=>'ﻇ','ﻈ'=>'ﻈ','ﻉ'=>'ﻉ','ﻊ'=>'ﻊ','ﻋ'=>'ﻋ','ﻌ'=>'ﻌ','ﻍ'=>'ﻍ','ﻎ'=>'ﻎ','ﻏ'=>'ﻏ','ﻐ'=>'ﻐ','ﻑ'=>'ﻑ','ﻒ'=>'ﻒ','ﻓ'=>'ﻓ','ﻔ'=>'ﻔ','ﻕ'=>'ﻕ','ﻖ'=>'ﻖ','ﻗ'=>'ﻗ','ﻘ'=>'ﻘ','ﻙ'=>'ﻙ','ﻚ'=>'ﻚ','ﻛ'=>'ﻛ','ﻜ'=>'ﻜ','ﻝ'=>'ﻝ','ﻞ'=>'ﻞ','ﻟ'=>'ﻟ','ﻠ'=>'ﻠ','ﻡ'=>'ﻡ','ﻢ'=>'ﻢ','ﻣ'=>'ﻣ','ﻤ'=>'ﻤ','ﻥ'=>'ﻥ','ﻦ'=>'ﻦ','ﻧ'=>'ﻧ','ﻨ'=>'ﻨ','ﻩ'=>'ﻩ','ﻪ'=>'ﻪ','ﻫ'=>'ﻫ','ﻬ'=>'ﻬ','ﻭ'=>'ﻭ','ﻮ'=>'ﻮ','ﻯ'=>'ﻯ','ﻰ'=>'ﻰ','ﻱ'=>'ﻱ','ﻲ'=>'ﻲ','ﻳ'=>'ﻳ','ﻴ'=>'ﻴ','ﻵ'=>'ﻵ','ﻶ'=>'ﻶ','ﻷ'=>'ﻷ','ﻸ'=>'ﻸ','ﻹ'=>'ﻹ','ﻺ'=>'ﻺ','ﻻ'=>'ﻻ','ﻼ'=>'ﻼ','0'=>'0','1'=>'1','2'=>'2','3'=>'3','4'=>'4','5'=>'5','6'=>'6','7'=>'7','8'=>'8','9'=>'9','A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','a'=>'a','b'=>'b','c'=>'c','d'=>'d','e'=>'e','f'=>'f','g'=>'g','h'=>'h','i'=>'i','j'=>'j','k'=>'k','l'=>'l','m'=>'m','n'=>'n','o'=>'o','p'=>'p','q'=>'q','r'=>'r','s'=>'s','t'=>'t','u'=>'u','v'=>'v','w'=>'w','x'=>'x','y'=>'y','z'=>'z','ヲ'=>'ヲ','ァ'=>'ァ','ィ'=>'ィ','ゥ'=>'ゥ','ェ'=>'ェ','ォ'=>'ォ','ャ'=>'ャ','ュ'=>'ュ','ョ'=>'ョ','ッ'=>'ッ','ー'=>'ー','ア'=>'ア','イ'=>'イ','ウ'=>'ウ','エ'=>'エ','オ'=>'オ','カ'=>'カ','キ'=>'キ','ク'=>'ク','ケ'=>'ケ','コ'=>'コ','サ'=>'サ','シ'=>'シ','ス'=>'ス','セ'=>'セ','ソ'=>'ソ','タ'=>'タ','チ'=>'チ','ツ'=>'ツ','テ'=>'テ','ト'=>'ト','ナ'=>'ナ','ニ'=>'ニ','ヌ'=>'ヌ','ネ'=>'ネ','ノ'=>'ノ','ハ'=>'ハ','ヒ'=>'ヒ','フ'=>'フ','ヘ'=>'ヘ','ホ'=>'ホ','マ'=>'マ','ミ'=>'ミ','ム'=>'ム','メ'=>'メ','モ'=>'モ','ヤ'=>'ヤ','ユ'=>'ユ','ヨ'=>'ヨ','ラ'=>'ラ','リ'=>'リ','ル'=>'ル','レ'=>'レ','ロ'=>'ロ','ワ'=>'ワ','ン'=>'ン','゙'=>'゙','゚'=>'゚','ᅠ'=>'ᅠ','ᄀ'=>'ᄀ','ᄁ'=>'ᄁ','ᆪ'=>'ᆪ','ᄂ'=>'ᄂ','ᆬ'=>'ᆬ','ᆭ'=>'ᆭ','ᄃ'=>'ᄃ','ᄄ'=>'ᄄ','ᄅ'=>'ᄅ','ᆰ'=>'ᆰ','ᆱ'=>'ᆱ','ᆲ'=>'ᆲ','ᆳ'=>'ᆳ','ᆴ'=>'ᆴ','ᆵ'=>'ᆵ','ᄚ'=>'ᄚ','ᄆ'=>'ᄆ','ᄇ'=>'ᄇ','ᄈ'=>'ᄈ','ᄡ'=>'ᄡ','ᄉ'=>'ᄉ','ᄊ'=>'ᄊ','ᄋ'=>'ᄋ','ᄌ'=>'ᄌ','ᄍ'=>'ᄍ','ᄎ'=>'ᄎ','ᄏ'=>'ᄏ','ᄐ'=>'ᄐ','ᄑ'=>'ᄑ','ᄒ'=>'ᄒ','ᅡ'=>'ᅡ','ᅢ'=>'ᅢ','ᅣ'=>'ᅣ','ᅤ'=>'ᅤ','ᅥ'=>'ᅥ','ᅦ'=>'ᅦ','ᅧ'=>'ᅧ','ᅨ'=>'ᅨ','ᅩ'=>'ᅩ','ᅪ'=>'ᅪ','ᅫ'=>'ᅫ','ᅬ'=>'ᅬ','ᅭ'=>'ᅭ','ᅮ'=>'ᅮ','ᅯ'=>'ᅯ','ᅰ'=>'ᅰ','ᅱ'=>'ᅱ','ᅲ'=>'ᅲ','ᅳ'=>'ᅳ','ᅴ'=>'ᅴ','ᅵ'=>'ᅵ');
\ No newline at end of file +<?php return array('豈'=>'豈','更'=>'更','車'=>'車','賈'=>'賈','滑'=>'滑','串'=>'串','句'=>'句','龜'=>'龜','龜'=>'龜','契'=>'契','金'=>'金','喇'=>'喇','奈'=>'奈','懶'=>'懶','癩'=>'癩','羅'=>'羅','蘿'=>'蘿','螺'=>'螺','裸'=>'裸','邏'=>'邏','樂'=>'樂','洛'=>'洛','烙'=>'烙','珞'=>'珞','落'=>'落','酪'=>'酪','駱'=>'駱','亂'=>'亂','卵'=>'卵','欄'=>'欄','爛'=>'爛','蘭'=>'蘭','鸞'=>'鸞','嵐'=>'嵐','濫'=>'濫','藍'=>'藍','襤'=>'襤','拉'=>'拉','臘'=>'臘','蠟'=>'蠟','廊'=>'廊','朗'=>'朗','浪'=>'浪','狼'=>'狼','郎'=>'郎','來'=>'來','冷'=>'冷','勞'=>'勞','擄'=>'擄','櫓'=>'櫓','爐'=>'爐','盧'=>'盧','老'=>'老','蘆'=>'蘆','虜'=>'虜','路'=>'路','露'=>'露','魯'=>'魯','鷺'=>'鷺','碌'=>'碌','祿'=>'祿','綠'=>'綠','菉'=>'菉','錄'=>'錄','鹿'=>'鹿','論'=>'論','壟'=>'壟','弄'=>'弄','籠'=>'籠','聾'=>'聾','牢'=>'牢','磊'=>'磊','賂'=>'賂','雷'=>'雷','壘'=>'壘','屢'=>'屢','樓'=>'樓','淚'=>'淚','漏'=>'漏','累'=>'累','縷'=>'縷','陋'=>'陋','勒'=>'勒','肋'=>'肋','凜'=>'凜','凌'=>'凌','稜'=>'稜','綾'=>'綾','菱'=>'菱','陵'=>'陵','讀'=>'讀','拏'=>'拏','樂'=>'樂','諾'=>'諾','丹'=>'丹','寧'=>'寧','怒'=>'怒','率'=>'率','異'=>'異','北'=>'北','磻'=>'磻','便'=>'便','復'=>'復','不'=>'不','泌'=>'泌','數'=>'數','索'=>'索','參'=>'參','塞'=>'塞','省'=>'省','葉'=>'葉','說'=>'說','殺'=>'殺','辰'=>'辰','沈'=>'沈','拾'=>'拾','若'=>'若','掠'=>'掠','略'=>'略','亮'=>'亮','兩'=>'兩','凉'=>'凉','梁'=>'梁','糧'=>'糧','良'=>'良','諒'=>'諒','量'=>'量','勵'=>'勵','呂'=>'呂','女'=>'女','廬'=>'廬','旅'=>'旅','濾'=>'濾','礪'=>'礪','閭'=>'閭','驪'=>'驪','麗'=>'麗','黎'=>'黎','力'=>'力','曆'=>'曆','歷'=>'歷','轢'=>'轢','年'=>'年','憐'=>'憐','戀'=>'戀','撚'=>'撚','漣'=>'漣','煉'=>'煉','璉'=>'璉','秊'=>'秊','練'=>'練','聯'=>'聯','輦'=>'輦','蓮'=>'蓮','連'=>'連','鍊'=>'鍊','列'=>'列','劣'=>'劣','咽'=>'咽','烈'=>'烈','裂'=>'裂','說'=>'說','廉'=>'廉','念'=>'念','捻'=>'捻','殮'=>'殮','簾'=>'簾','獵'=>'獵','令'=>'令','囹'=>'囹','寧'=>'寧','嶺'=>'嶺','怜'=>'怜','玲'=>'玲','瑩'=>'瑩','羚'=>'羚','聆'=>'聆','鈴'=>'鈴','零'=>'零','靈'=>'靈','領'=>'領','例'=>'例','禮'=>'禮','醴'=>'醴','隸'=>'隸','惡'=>'惡','了'=>'了','僚'=>'僚','寮'=>'寮','尿'=>'尿','料'=>'料','樂'=>'樂','燎'=>'燎','療'=>'療','蓼'=>'蓼','遼'=>'遼','龍'=>'龍','暈'=>'暈','阮'=>'阮','劉'=>'劉','杻'=>'杻','柳'=>'柳','流'=>'流','溜'=>'溜','琉'=>'琉','留'=>'留','硫'=>'硫','紐'=>'紐','類'=>'類','六'=>'六','戮'=>'戮','陸'=>'陸','倫'=>'倫','崙'=>'崙','淪'=>'淪','輪'=>'輪','律'=>'律','慄'=>'慄','栗'=>'栗','率'=>'率','隆'=>'隆','利'=>'利','吏'=>'吏','履'=>'履','易'=>'易','李'=>'李','梨'=>'梨','泥'=>'泥','理'=>'理','痢'=>'痢','罹'=>'罹','裏'=>'裏','裡'=>'裡','里'=>'里','離'=>'離','匿'=>'匿','溺'=>'溺','吝'=>'吝','燐'=>'燐','璘'=>'璘','藺'=>'藺','隣'=>'隣','鱗'=>'鱗','麟'=>'麟','林'=>'林','淋'=>'淋','臨'=>'臨','立'=>'立','笠'=>'笠','粒'=>'粒','狀'=>'狀','炙'=>'炙','識'=>'識','什'=>'什','茶'=>'茶','刺'=>'刺','切'=>'切','度'=>'度','拓'=>'拓','糖'=>'糖','宅'=>'宅','洞'=>'洞','暴'=>'暴','輻'=>'輻','行'=>'行','降'=>'降','見'=>'見','廓'=>'廓','兀'=>'兀','嗀'=>'嗀','﨎'=>'﨎','﨏'=>'﨏','塚'=>'塚','﨑'=>'﨑','晴'=>'晴','﨓'=>'﨓','﨔'=>'﨔','凞'=>'凞','猪'=>'猪','益'=>'益','礼'=>'礼','神'=>'神','祥'=>'祥','福'=>'福','靖'=>'靖','精'=>'精','羽'=>'羽','﨟'=>'﨟','蘒'=>'蘒','﨡'=>'﨡','諸'=>'諸','﨣'=>'﨣','﨤'=>'﨤','逸'=>'逸','都'=>'都','﨧'=>'﨧','﨨'=>'﨨','﨩'=>'﨩','飯'=>'飯','飼'=>'飼','館'=>'館','鶴'=>'鶴','侮'=>'侮','僧'=>'僧','免'=>'免','勉'=>'勉','勤'=>'勤','卑'=>'卑','喝'=>'喝','嘆'=>'嘆','器'=>'器','塀'=>'塀','墨'=>'墨','層'=>'層','屮'=>'屮','悔'=>'悔','慨'=>'慨','憎'=>'憎','懲'=>'懲','敏'=>'敏','既'=>'既','暑'=>'暑','梅'=>'梅','海'=>'海','渚'=>'渚','漢'=>'漢','煮'=>'煮','爫'=>'爫','琢'=>'琢','碑'=>'碑','社'=>'社','祉'=>'祉','祈'=>'祈','祐'=>'祐','祖'=>'祖','祝'=>'祝','禍'=>'禍','禎'=>'禎','穀'=>'穀','突'=>'突','節'=>'節','練'=>'練','縉'=>'縉','繁'=>'繁','署'=>'署','者'=>'者','臭'=>'臭','艹'=>'艹','艹'=>'艹','著'=>'著','褐'=>'褐','視'=>'視','謁'=>'謁','謹'=>'謹','賓'=>'賓','贈'=>'贈','辶'=>'辶','逸'=>'逸','難'=>'難','響'=>'響','頻'=>'頻','並'=>'並','况'=>'况','全'=>'全','侀'=>'侀','充'=>'充','冀'=>'冀','勇'=>'勇','勺'=>'勺','喝'=>'喝','啕'=>'啕','喙'=>'喙','嗢'=>'嗢','塚'=>'塚','墳'=>'墳','奄'=>'奄','奔'=>'奔','婢'=>'婢','嬨'=>'嬨','廒'=>'廒','廙'=>'廙','彩'=>'彩','徭'=>'徭','惘'=>'惘','慎'=>'慎','愈'=>'愈','憎'=>'憎','慠'=>'慠','懲'=>'懲','戴'=>'戴','揄'=>'揄','搜'=>'搜','摒'=>'摒','敖'=>'敖','晴'=>'晴','朗'=>'朗','望'=>'望','杖'=>'杖','歹'=>'歹','殺'=>'殺','流'=>'流','滛'=>'滛','滋'=>'滋','漢'=>'漢','瀞'=>'瀞','煮'=>'煮','瞧'=>'瞧','爵'=>'爵','犯'=>'犯','猪'=>'猪','瑱'=>'瑱','甆'=>'甆','画'=>'画','瘝'=>'瘝','瘟'=>'瘟','益'=>'益','盛'=>'盛','直'=>'直','睊'=>'睊','着'=>'着','磌'=>'磌','窱'=>'窱','節'=>'節','类'=>'类','絛'=>'絛','練'=>'練','缾'=>'缾','者'=>'者','荒'=>'荒','華'=>'華','蝹'=>'蝹','襁'=>'襁','覆'=>'覆','視'=>'視','調'=>'調','諸'=>'諸','請'=>'請','謁'=>'謁','諾'=>'諾','諭'=>'諭','謹'=>'謹','變'=>'變','贈'=>'贈','輸'=>'輸','遲'=>'遲','醙'=>'醙','鉶'=>'鉶','陼'=>'陼','難'=>'難','靖'=>'靖','韛'=>'韛','響'=>'響','頋'=>'頋','頻'=>'頻','鬒'=>'鬒','龜'=>'龜','𢡊'=>'𢡊','𢡄'=>'𢡄','𣏕'=>'𣏕','㮝'=>'㮝','䀘'=>'䀘','䀹'=>'䀹','𥉉'=>'𥉉','𥳐'=>'𥳐','𧻓'=>'𧻓','齃'=>'齃','龎'=>'龎','ff'=>'ff','fi'=>'fi','fl'=>'fl','ffi'=>'ffi','ffl'=>'ffl','ſt'=>'ſt','st'=>'st','ﬓ'=>'ﬓ','ﬔ'=>'ﬔ','ﬕ'=>'ﬕ','ﬖ'=>'ﬖ','ﬗ'=>'ﬗ','יִ'=>'יִ','ﬞ'=>'ﬞ','ײַ'=>'ײַ','ﬠ'=>'ﬠ','ﬡ'=>'ﬡ','ﬢ'=>'ﬢ','ﬣ'=>'ﬣ','ﬤ'=>'ﬤ','ﬥ'=>'ﬥ','ﬦ'=>'ﬦ','ﬧ'=>'ﬧ','ﬨ'=>'ﬨ','שׁ'=>'שׁ','שׂ'=>'שׂ','שּׁ'=>'שּׁ','שּׂ'=>'שּׂ','אַ'=>'אַ','אָ'=>'אָ','אּ'=>'אּ','בּ'=>'בּ','גּ'=>'גּ','דּ'=>'דּ','הּ'=>'הּ','וּ'=>'וּ','זּ'=>'זּ','טּ'=>'טּ','יּ'=>'יּ','ךּ'=>'ךּ','כּ'=>'כּ','לּ'=>'לּ','מּ'=>'מּ','נּ'=>'נּ','סּ'=>'סּ','ףּ'=>'ףּ','פּ'=>'פּ','צּ'=>'צּ','קּ'=>'קּ','רּ'=>'רּ','שּ'=>'שּ','תּ'=>'תּ','וֹ'=>'וֹ','בֿ'=>'בֿ','כֿ'=>'כֿ','פֿ'=>'פֿ','ﭏ'=>'ﭏ','ﭐ'=>'ﭐ','ﭑ'=>'ﭑ','ﭒ'=>'ﭒ','ﭓ'=>'ﭓ','ﭔ'=>'ﭔ','ﭕ'=>'ﭕ','ﭖ'=>'ﭖ','ﭗ'=>'ﭗ','ﭘ'=>'ﭘ','ﭙ'=>'ﭙ','ﭚ'=>'ﭚ','ﭛ'=>'ﭛ','ﭜ'=>'ﭜ','ﭝ'=>'ﭝ','ﭞ'=>'ﭞ','ﭟ'=>'ﭟ','ﭠ'=>'ﭠ','ﭡ'=>'ﭡ','ﭢ'=>'ﭢ','ﭣ'=>'ﭣ','ﭤ'=>'ﭤ','ﭥ'=>'ﭥ','ﭦ'=>'ﭦ','ﭧ'=>'ﭧ','ﭨ'=>'ﭨ','ﭩ'=>'ﭩ','ﭪ'=>'ﭪ','ﭫ'=>'ﭫ','ﭬ'=>'ﭬ','ﭭ'=>'ﭭ','ﭮ'=>'ﭮ','ﭯ'=>'ﭯ','ﭰ'=>'ﭰ','ﭱ'=>'ﭱ','ﭲ'=>'ﭲ','ﭳ'=>'ﭳ','ﭴ'=>'ﭴ','ﭵ'=>'ﭵ','ﭶ'=>'ﭶ','ﭷ'=>'ﭷ','ﭸ'=>'ﭸ','ﭹ'=>'ﭹ','ﭺ'=>'ﭺ','ﭻ'=>'ﭻ','ﭼ'=>'ﭼ','ﭽ'=>'ﭽ','ﭾ'=>'ﭾ','ﭿ'=>'ﭿ','ﮀ'=>'ﮀ','ﮁ'=>'ﮁ','ﮂ'=>'ﮂ','ﮃ'=>'ﮃ','ﮄ'=>'ﮄ','ﮅ'=>'ﮅ','ﮆ'=>'ﮆ','ﮇ'=>'ﮇ','ﮈ'=>'ﮈ','ﮉ'=>'ﮉ','ﮊ'=>'ﮊ','ﮋ'=>'ﮋ','ﮌ'=>'ﮌ','ﮍ'=>'ﮍ','ﮎ'=>'ﮎ','ﮏ'=>'ﮏ','ﮐ'=>'ﮐ','ﮑ'=>'ﮑ','ﮒ'=>'ﮒ','ﮓ'=>'ﮓ','ﮔ'=>'ﮔ','ﮕ'=>'ﮕ','ﮖ'=>'ﮖ','ﮗ'=>'ﮗ','ﮘ'=>'ﮘ','ﮙ'=>'ﮙ','ﮚ'=>'ﮚ','ﮛ'=>'ﮛ','ﮜ'=>'ﮜ','ﮝ'=>'ﮝ','ﮞ'=>'ﮞ','ﮟ'=>'ﮟ','ﮠ'=>'ﮠ','ﮡ'=>'ﮡ','ﮢ'=>'ﮢ','ﮣ'=>'ﮣ','ﮤ'=>'ﮤ','ﮥ'=>'ﮥ','ﮦ'=>'ﮦ','ﮧ'=>'ﮧ','ﮨ'=>'ﮨ','ﮩ'=>'ﮩ','ﮪ'=>'ﮪ','ﮫ'=>'ﮫ','ﮬ'=>'ﮬ','ﮭ'=>'ﮭ','ﮮ'=>'ﮮ','ﮯ'=>'ﮯ','ﮰ'=>'ﮰ','ﮱ'=>'ﮱ','ﯓ'=>'ﯓ','ﯔ'=>'ﯔ','ﯕ'=>'ﯕ','ﯖ'=>'ﯖ','ﯗ'=>'ﯗ','ﯘ'=>'ﯘ','ﯙ'=>'ﯙ','ﯚ'=>'ﯚ','ﯛ'=>'ﯛ','ﯜ'=>'ﯜ','ﯝ'=>'ﯝ','ﯞ'=>'ﯞ','ﯟ'=>'ﯟ','ﯠ'=>'ﯠ','ﯡ'=>'ﯡ','ﯢ'=>'ﯢ','ﯣ'=>'ﯣ','ﯤ'=>'ﯤ','ﯥ'=>'ﯥ','ﯦ'=>'ﯦ','ﯧ'=>'ﯧ','ﯨ'=>'ﯨ','ﯩ'=>'ﯩ','ﯪ'=>'ﯪ','ﯫ'=>'ﯫ','ﯬ'=>'ﯬ','ﯭ'=>'ﯭ','ﯮ'=>'ﯮ','ﯯ'=>'ﯯ','ﯰ'=>'ﯰ','ﯱ'=>'ﯱ','ﯲ'=>'ﯲ','ﯳ'=>'ﯳ','ﯴ'=>'ﯴ','ﯵ'=>'ﯵ','ﯶ'=>'ﯶ','ﯷ'=>'ﯷ','ﯸ'=>'ﯸ','ﯹ'=>'ﯹ','ﯺ'=>'ﯺ','ﯻ'=>'ﯻ','ﯼ'=>'ﯼ','ﯽ'=>'ﯽ','ﯾ'=>'ﯾ','ﯿ'=>'ﯿ','ﰀ'=>'ﰀ','ﰁ'=>'ﰁ','ﰂ'=>'ﰂ','ﰃ'=>'ﰃ','ﰄ'=>'ﰄ','ﰅ'=>'ﰅ','ﰆ'=>'ﰆ','ﰇ'=>'ﰇ','ﰈ'=>'ﰈ','ﰉ'=>'ﰉ','ﰊ'=>'ﰊ','ﰋ'=>'ﰋ','ﰌ'=>'ﰌ','ﰍ'=>'ﰍ','ﰎ'=>'ﰎ','ﰏ'=>'ﰏ','ﰐ'=>'ﰐ','ﰑ'=>'ﰑ','ﰒ'=>'ﰒ','ﰓ'=>'ﰓ','ﰔ'=>'ﰔ','ﰕ'=>'ﰕ','ﰖ'=>'ﰖ','ﰗ'=>'ﰗ','ﰘ'=>'ﰘ','ﰙ'=>'ﰙ','ﰚ'=>'ﰚ','ﰛ'=>'ﰛ','ﰜ'=>'ﰜ','ﰝ'=>'ﰝ','ﰞ'=>'ﰞ','ﰟ'=>'ﰟ','ﰠ'=>'ﰠ','ﰡ'=>'ﰡ','ﰢ'=>'ﰢ','ﰣ'=>'ﰣ','ﰤ'=>'ﰤ','ﰥ'=>'ﰥ','ﰦ'=>'ﰦ','ﰧ'=>'ﰧ','ﰨ'=>'ﰨ','ﰩ'=>'ﰩ','ﰪ'=>'ﰪ','ﰫ'=>'ﰫ','ﰬ'=>'ﰬ','ﰭ'=>'ﰭ','ﰮ'=>'ﰮ','ﰯ'=>'ﰯ','ﰰ'=>'ﰰ','ﰱ'=>'ﰱ','ﰲ'=>'ﰲ','ﰳ'=>'ﰳ','ﰴ'=>'ﰴ','ﰵ'=>'ﰵ','ﰶ'=>'ﰶ','ﰷ'=>'ﰷ','ﰸ'=>'ﰸ','ﰹ'=>'ﰹ','ﰺ'=>'ﰺ','ﰻ'=>'ﰻ','ﰼ'=>'ﰼ','ﰽ'=>'ﰽ','ﰾ'=>'ﰾ','ﰿ'=>'ﰿ','ﱀ'=>'ﱀ','ﱁ'=>'ﱁ','ﱂ'=>'ﱂ','ﱃ'=>'ﱃ','ﱄ'=>'ﱄ','ﱅ'=>'ﱅ','ﱆ'=>'ﱆ','ﱇ'=>'ﱇ','ﱈ'=>'ﱈ','ﱉ'=>'ﱉ','ﱊ'=>'ﱊ','ﱋ'=>'ﱋ','ﱌ'=>'ﱌ','ﱍ'=>'ﱍ','ﱎ'=>'ﱎ','ﱏ'=>'ﱏ','ﱐ'=>'ﱐ','ﱑ'=>'ﱑ','ﱒ'=>'ﱒ','ﱓ'=>'ﱓ','ﱔ'=>'ﱔ','ﱕ'=>'ﱕ','ﱖ'=>'ﱖ','ﱗ'=>'ﱗ','ﱘ'=>'ﱘ','ﱙ'=>'ﱙ','ﱚ'=>'ﱚ','ﱛ'=>'ﱛ','ﱜ'=>'ﱜ','ﱝ'=>'ﱝ','ﱞ'=>'ﱞ','ﱟ'=>'ﱟ','ﱠ'=>'ﱠ','ﱡ'=>'ﱡ','ﱢ'=>'ﱢ','ﱣ'=>'ﱣ','ﱤ'=>'ﱤ','ﱥ'=>'ﱥ','ﱦ'=>'ﱦ','ﱧ'=>'ﱧ','ﱨ'=>'ﱨ','ﱩ'=>'ﱩ','ﱪ'=>'ﱪ','ﱫ'=>'ﱫ','ﱬ'=>'ﱬ','ﱭ'=>'ﱭ','ﱮ'=>'ﱮ','ﱯ'=>'ﱯ','ﱰ'=>'ﱰ','ﱱ'=>'ﱱ','ﱲ'=>'ﱲ','ﱳ'=>'ﱳ','ﱴ'=>'ﱴ','ﱵ'=>'ﱵ','ﱶ'=>'ﱶ','ﱷ'=>'ﱷ','ﱸ'=>'ﱸ','ﱹ'=>'ﱹ','ﱺ'=>'ﱺ','ﱻ'=>'ﱻ','ﱼ'=>'ﱼ','ﱽ'=>'ﱽ','ﱾ'=>'ﱾ','ﱿ'=>'ﱿ','ﲀ'=>'ﲀ','ﲁ'=>'ﲁ','ﲂ'=>'ﲂ','ﲃ'=>'ﲃ','ﲄ'=>'ﲄ','ﲅ'=>'ﲅ','ﲆ'=>'ﲆ','ﲇ'=>'ﲇ','ﲈ'=>'ﲈ','ﲉ'=>'ﲉ','ﲊ'=>'ﲊ','ﲋ'=>'ﲋ','ﲌ'=>'ﲌ','ﲍ'=>'ﲍ','ﲎ'=>'ﲎ','ﲏ'=>'ﲏ','ﲐ'=>'ﲐ','ﲑ'=>'ﲑ','ﲒ'=>'ﲒ','ﲓ'=>'ﲓ','ﲔ'=>'ﲔ','ﲕ'=>'ﲕ','ﲖ'=>'ﲖ','ﲗ'=>'ﲗ','ﲘ'=>'ﲘ','ﲙ'=>'ﲙ','ﲚ'=>'ﲚ','ﲛ'=>'ﲛ','ﲜ'=>'ﲜ','ﲝ'=>'ﲝ','ﲞ'=>'ﲞ','ﲟ'=>'ﲟ','ﲠ'=>'ﲠ','ﲡ'=>'ﲡ','ﲢ'=>'ﲢ','ﲣ'=>'ﲣ','ﲤ'=>'ﲤ','ﲥ'=>'ﲥ','ﲦ'=>'ﲦ','ﲧ'=>'ﲧ','ﲨ'=>'ﲨ','ﲩ'=>'ﲩ','ﲪ'=>'ﲪ','ﲫ'=>'ﲫ','ﲬ'=>'ﲬ','ﲭ'=>'ﲭ','ﲮ'=>'ﲮ','ﲯ'=>'ﲯ','ﲰ'=>'ﲰ','ﲱ'=>'ﲱ','ﲲ'=>'ﲲ','ﲳ'=>'ﲳ','ﲴ'=>'ﲴ','ﲵ'=>'ﲵ','ﲶ'=>'ﲶ','ﲷ'=>'ﲷ','ﲸ'=>'ﲸ','ﲹ'=>'ﲹ','ﲺ'=>'ﲺ','ﲻ'=>'ﲻ','ﲼ'=>'ﲼ','ﲽ'=>'ﲽ','ﲾ'=>'ﲾ','ﲿ'=>'ﲿ','ﳀ'=>'ﳀ','ﳁ'=>'ﳁ','ﳂ'=>'ﳂ','ﳃ'=>'ﳃ','ﳄ'=>'ﳄ','ﳅ'=>'ﳅ','ﳆ'=>'ﳆ','ﳇ'=>'ﳇ','ﳈ'=>'ﳈ','ﳉ'=>'ﳉ','ﳊ'=>'ﳊ','ﳋ'=>'ﳋ','ﳌ'=>'ﳌ','ﳍ'=>'ﳍ','ﳎ'=>'ﳎ','ﳏ'=>'ﳏ','ﳐ'=>'ﳐ','ﳑ'=>'ﳑ','ﳒ'=>'ﳒ','ﳓ'=>'ﳓ','ﳔ'=>'ﳔ','ﳕ'=>'ﳕ','ﳖ'=>'ﳖ','ﳗ'=>'ﳗ','ﳘ'=>'ﳘ','ﳙ'=>'ﳙ','ﳚ'=>'ﳚ','ﳛ'=>'ﳛ','ﳜ'=>'ﳜ','ﳝ'=>'ﳝ','ﳞ'=>'ﳞ','ﳟ'=>'ﳟ','ﳠ'=>'ﳠ','ﳡ'=>'ﳡ','ﳢ'=>'ﳢ','ﳣ'=>'ﳣ','ﳤ'=>'ﳤ','ﳥ'=>'ﳥ','ﳦ'=>'ﳦ','ﳧ'=>'ﳧ','ﳨ'=>'ﳨ','ﳩ'=>'ﳩ','ﳪ'=>'ﳪ','ﳫ'=>'ﳫ','ﳬ'=>'ﳬ','ﳭ'=>'ﳭ','ﳮ'=>'ﳮ','ﳯ'=>'ﳯ','ﳰ'=>'ﳰ','ﳱ'=>'ﳱ','ﳲ'=>'ﳲ','ﳳ'=>'ﳳ','ﳴ'=>'ﳴ','ﳵ'=>'ﳵ','ﳶ'=>'ﳶ','ﳷ'=>'ﳷ','ﳸ'=>'ﳸ','ﳹ'=>'ﳹ','ﳺ'=>'ﳺ','ﳻ'=>'ﳻ','ﳼ'=>'ﳼ','ﳽ'=>'ﳽ','ﳾ'=>'ﳾ','ﳿ'=>'ﳿ','ﴀ'=>'ﴀ','ﴁ'=>'ﴁ','ﴂ'=>'ﴂ','ﴃ'=>'ﴃ','ﴄ'=>'ﴄ','ﴅ'=>'ﴅ','ﴆ'=>'ﴆ','ﴇ'=>'ﴇ','ﴈ'=>'ﴈ','ﴉ'=>'ﴉ','ﴊ'=>'ﴊ','ﴋ'=>'ﴋ','ﴌ'=>'ﴌ','ﴍ'=>'ﴍ','ﴎ'=>'ﴎ','ﴏ'=>'ﴏ','ﴐ'=>'ﴐ','ﴑ'=>'ﴑ','ﴒ'=>'ﴒ','ﴓ'=>'ﴓ','ﴔ'=>'ﴔ','ﴕ'=>'ﴕ','ﴖ'=>'ﴖ','ﴗ'=>'ﴗ','ﴘ'=>'ﴘ','ﴙ'=>'ﴙ','ﴚ'=>'ﴚ','ﴛ'=>'ﴛ','ﴜ'=>'ﴜ','ﴝ'=>'ﴝ','ﴞ'=>'ﴞ','ﴟ'=>'ﴟ','ﴠ'=>'ﴠ','ﴡ'=>'ﴡ','ﴢ'=>'ﴢ','ﴣ'=>'ﴣ','ﴤ'=>'ﴤ','ﴥ'=>'ﴥ','ﴦ'=>'ﴦ','ﴧ'=>'ﴧ','ﴨ'=>'ﴨ','ﴩ'=>'ﴩ','ﴪ'=>'ﴪ','ﴫ'=>'ﴫ','ﴬ'=>'ﴬ','ﴭ'=>'ﴭ','ﴮ'=>'ﴮ','ﴯ'=>'ﴯ','ﴰ'=>'ﴰ','ﴱ'=>'ﴱ','ﴲ'=>'ﴲ','ﴳ'=>'ﴳ','ﴴ'=>'ﴴ','ﴵ'=>'ﴵ','ﴶ'=>'ﴶ','ﴷ'=>'ﴷ','ﴸ'=>'ﴸ','ﴹ'=>'ﴹ','ﴺ'=>'ﴺ','ﴻ'=>'ﴻ','ﴼ'=>'ﴼ','ﴽ'=>'ﴽ','ﵐ'=>'ﵐ','ﵑ'=>'ﵑ','ﵒ'=>'ﵒ','ﵓ'=>'ﵓ','ﵔ'=>'ﵔ','ﵕ'=>'ﵕ','ﵖ'=>'ﵖ','ﵗ'=>'ﵗ','ﵘ'=>'ﵘ','ﵙ'=>'ﵙ','ﵚ'=>'ﵚ','ﵛ'=>'ﵛ','ﵜ'=>'ﵜ','ﵝ'=>'ﵝ','ﵞ'=>'ﵞ','ﵟ'=>'ﵟ','ﵠ'=>'ﵠ','ﵡ'=>'ﵡ','ﵢ'=>'ﵢ','ﵣ'=>'ﵣ','ﵤ'=>'ﵤ','ﵥ'=>'ﵥ','ﵦ'=>'ﵦ','ﵧ'=>'ﵧ','ﵨ'=>'ﵨ','ﵩ'=>'ﵩ','ﵪ'=>'ﵪ','ﵫ'=>'ﵫ','ﵬ'=>'ﵬ','ﵭ'=>'ﵭ','ﵮ'=>'ﵮ','ﵯ'=>'ﵯ','ﵰ'=>'ﵰ','ﵱ'=>'ﵱ','ﵲ'=>'ﵲ','ﵳ'=>'ﵳ','ﵴ'=>'ﵴ','ﵵ'=>'ﵵ','ﵶ'=>'ﵶ','ﵷ'=>'ﵷ','ﵸ'=>'ﵸ','ﵹ'=>'ﵹ','ﵺ'=>'ﵺ','ﵻ'=>'ﵻ','ﵼ'=>'ﵼ','ﵽ'=>'ﵽ','ﵾ'=>'ﵾ','ﵿ'=>'ﵿ','ﶀ'=>'ﶀ','ﶁ'=>'ﶁ','ﶂ'=>'ﶂ','ﶃ'=>'ﶃ','ﶄ'=>'ﶄ','ﶅ'=>'ﶅ','ﶆ'=>'ﶆ','ﶇ'=>'ﶇ','ﶈ'=>'ﶈ','ﶉ'=>'ﶉ','ﶊ'=>'ﶊ','ﶋ'=>'ﶋ','ﶌ'=>'ﶌ','ﶍ'=>'ﶍ','ﶎ'=>'ﶎ','ﶏ'=>'ﶏ','ﶒ'=>'ﶒ','ﶓ'=>'ﶓ','ﶔ'=>'ﶔ','ﶕ'=>'ﶕ','ﶖ'=>'ﶖ','ﶗ'=>'ﶗ','ﶘ'=>'ﶘ','ﶙ'=>'ﶙ','ﶚ'=>'ﶚ','ﶛ'=>'ﶛ','ﶜ'=>'ﶜ','ﶝ'=>'ﶝ','ﶞ'=>'ﶞ','ﶟ'=>'ﶟ','ﶠ'=>'ﶠ','ﶡ'=>'ﶡ','ﶢ'=>'ﶢ','ﶣ'=>'ﶣ','ﶤ'=>'ﶤ','ﶥ'=>'ﶥ','ﶦ'=>'ﶦ','ﶧ'=>'ﶧ','ﶨ'=>'ﶨ','ﶩ'=>'ﶩ','ﶪ'=>'ﶪ','ﶫ'=>'ﶫ','ﶬ'=>'ﶬ','ﶭ'=>'ﶭ','ﶮ'=>'ﶮ','ﶯ'=>'ﶯ','ﶰ'=>'ﶰ','ﶱ'=>'ﶱ','ﶲ'=>'ﶲ','ﶳ'=>'ﶳ','ﶴ'=>'ﶴ','ﶵ'=>'ﶵ','ﶶ'=>'ﶶ','ﶷ'=>'ﶷ','ﶸ'=>'ﶸ','ﶹ'=>'ﶹ','ﶺ'=>'ﶺ','ﶻ'=>'ﶻ','ﶼ'=>'ﶼ','ﶽ'=>'ﶽ','ﶾ'=>'ﶾ','ﶿ'=>'ﶿ','ﷀ'=>'ﷀ','ﷁ'=>'ﷁ','ﷂ'=>'ﷂ','ﷃ'=>'ﷃ','ﷄ'=>'ﷄ','ﷅ'=>'ﷅ','ﷆ'=>'ﷆ','ﷇ'=>'ﷇ','ﷰ'=>'ﷰ','ﷱ'=>'ﷱ','ﷲ'=>'ﷲ','ﷳ'=>'ﷳ','ﷴ'=>'ﷴ','ﷵ'=>'ﷵ','ﷶ'=>'ﷶ','ﷷ'=>'ﷷ','ﷸ'=>'ﷸ','ﷹ'=>'ﷹ','ﷺ'=>'ﷺ','ﷻ'=>'ﷻ','︀'=>'︀','︁'=>'︁','︂'=>'︂','︃'=>'︃','︄'=>'︄','︅'=>'︅','︆'=>'︆','︇'=>'︇','︈'=>'︈','︉'=>'︉','︊'=>'︊','︋'=>'︋','︌'=>'︌','︍'=>'︍','︎'=>'︎','️'=>'️','︠'=>'︠','︡'=>'︡','︢'=>'︢','︣'=>'︣','ﹰ'=>'ﹰ','ﹱ'=>'ﹱ','ﹲ'=>'ﹲ','ﹳ'=>'ﹳ','ﹴ'=>'ﹴ','ﹶ'=>'ﹶ','ﹷ'=>'ﹷ','ﹸ'=>'ﹸ','ﹹ'=>'ﹹ','ﹺ'=>'ﹺ','ﹻ'=>'ﹻ','ﹼ'=>'ﹼ','ﹽ'=>'ﹽ','ﹾ'=>'ﹾ','ﹿ'=>'ﹿ','ﺀ'=>'ﺀ','ﺁ'=>'ﺁ','ﺂ'=>'ﺂ','ﺃ'=>'ﺃ','ﺄ'=>'ﺄ','ﺅ'=>'ﺅ','ﺆ'=>'ﺆ','ﺇ'=>'ﺇ','ﺈ'=>'ﺈ','ﺉ'=>'ﺉ','ﺊ'=>'ﺊ','ﺋ'=>'ﺋ','ﺌ'=>'ﺌ','ﺍ'=>'ﺍ','ﺎ'=>'ﺎ','ﺏ'=>'ﺏ','ﺐ'=>'ﺐ','ﺑ'=>'ﺑ','ﺒ'=>'ﺒ','ﺓ'=>'ﺓ','ﺔ'=>'ﺔ','ﺕ'=>'ﺕ','ﺖ'=>'ﺖ','ﺗ'=>'ﺗ','ﺘ'=>'ﺘ','ﺙ'=>'ﺙ','ﺚ'=>'ﺚ','ﺛ'=>'ﺛ','ﺜ'=>'ﺜ','ﺝ'=>'ﺝ','ﺞ'=>'ﺞ','ﺟ'=>'ﺟ','ﺠ'=>'ﺠ','ﺡ'=>'ﺡ','ﺢ'=>'ﺢ','ﺣ'=>'ﺣ','ﺤ'=>'ﺤ','ﺥ'=>'ﺥ','ﺦ'=>'ﺦ','ﺧ'=>'ﺧ','ﺨ'=>'ﺨ','ﺩ'=>'ﺩ','ﺪ'=>'ﺪ','ﺫ'=>'ﺫ','ﺬ'=>'ﺬ','ﺭ'=>'ﺭ','ﺮ'=>'ﺮ','ﺯ'=>'ﺯ','ﺰ'=>'ﺰ','ﺱ'=>'ﺱ','ﺲ'=>'ﺲ','ﺳ'=>'ﺳ','ﺴ'=>'ﺴ','ﺵ'=>'ﺵ','ﺶ'=>'ﺶ','ﺷ'=>'ﺷ','ﺸ'=>'ﺸ','ﺹ'=>'ﺹ','ﺺ'=>'ﺺ','ﺻ'=>'ﺻ','ﺼ'=>'ﺼ','ﺽ'=>'ﺽ','ﺾ'=>'ﺾ','ﺿ'=>'ﺿ','ﻀ'=>'ﻀ','ﻁ'=>'ﻁ','ﻂ'=>'ﻂ','ﻃ'=>'ﻃ','ﻄ'=>'ﻄ','ﻅ'=>'ﻅ','ﻆ'=>'ﻆ','ﻇ'=>'ﻇ','ﻈ'=>'ﻈ','ﻉ'=>'ﻉ','ﻊ'=>'ﻊ','ﻋ'=>'ﻋ','ﻌ'=>'ﻌ','ﻍ'=>'ﻍ','ﻎ'=>'ﻎ','ﻏ'=>'ﻏ','ﻐ'=>'ﻐ','ﻑ'=>'ﻑ','ﻒ'=>'ﻒ','ﻓ'=>'ﻓ','ﻔ'=>'ﻔ','ﻕ'=>'ﻕ','ﻖ'=>'ﻖ','ﻗ'=>'ﻗ','ﻘ'=>'ﻘ','ﻙ'=>'ﻙ','ﻚ'=>'ﻚ','ﻛ'=>'ﻛ','ﻜ'=>'ﻜ','ﻝ'=>'ﻝ','ﻞ'=>'ﻞ','ﻟ'=>'ﻟ','ﻠ'=>'ﻠ','ﻡ'=>'ﻡ','ﻢ'=>'ﻢ','ﻣ'=>'ﻣ','ﻤ'=>'ﻤ','ﻥ'=>'ﻥ','ﻦ'=>'ﻦ','ﻧ'=>'ﻧ','ﻨ'=>'ﻨ','ﻩ'=>'ﻩ','ﻪ'=>'ﻪ','ﻫ'=>'ﻫ','ﻬ'=>'ﻬ','ﻭ'=>'ﻭ','ﻮ'=>'ﻮ','ﻯ'=>'ﻯ','ﻰ'=>'ﻰ','ﻱ'=>'ﻱ','ﻲ'=>'ﻲ','ﻳ'=>'ﻳ','ﻴ'=>'ﻴ','ﻵ'=>'ﻵ','ﻶ'=>'ﻶ','ﻷ'=>'ﻷ','ﻸ'=>'ﻸ','ﻹ'=>'ﻹ','ﻺ'=>'ﻺ','ﻻ'=>'ﻻ','ﻼ'=>'ﻼ','0'=>'0','1'=>'1','2'=>'2','3'=>'3','4'=>'4','5'=>'5','6'=>'6','7'=>'7','8'=>'8','9'=>'9','A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','a'=>'a','b'=>'b','c'=>'c','d'=>'d','e'=>'e','f'=>'f','g'=>'g','h'=>'h','i'=>'i','j'=>'j','k'=>'k','l'=>'l','m'=>'m','n'=>'n','o'=>'o','p'=>'p','q'=>'q','r'=>'r','s'=>'s','t'=>'t','u'=>'u','v'=>'v','w'=>'w','x'=>'x','y'=>'y','z'=>'z','ヲ'=>'ヲ','ァ'=>'ァ','ィ'=>'ィ','ゥ'=>'ゥ','ェ'=>'ェ','ォ'=>'ォ','ャ'=>'ャ','ュ'=>'ュ','ョ'=>'ョ','ッ'=>'ッ','ー'=>'ー','ア'=>'ア','イ'=>'イ','ウ'=>'ウ','エ'=>'エ','オ'=>'オ','カ'=>'カ','キ'=>'キ','ク'=>'ク','ケ'=>'ケ','コ'=>'コ','サ'=>'サ','シ'=>'シ','ス'=>'ス','セ'=>'セ','ソ'=>'ソ','タ'=>'タ','チ'=>'チ','ツ'=>'ツ','テ'=>'テ','ト'=>'ト','ナ'=>'ナ','ニ'=>'ニ','ヌ'=>'ヌ','ネ'=>'ネ','ノ'=>'ノ','ハ'=>'ハ','ヒ'=>'ヒ','フ'=>'フ','ヘ'=>'ヘ','ホ'=>'ホ','マ'=>'マ','ミ'=>'ミ','ム'=>'ム','メ'=>'メ','モ'=>'モ','ヤ'=>'ヤ','ユ'=>'ユ','ヨ'=>'ヨ','ラ'=>'ラ','リ'=>'リ','ル'=>'ル','レ'=>'レ','ロ'=>'ロ','ワ'=>'ワ','ン'=>'ン','゙'=>'゙','゚'=>'゚','ᅠ'=>'ᅠ','ᄀ'=>'ᄀ','ᄁ'=>'ᄁ','ᆪ'=>'ᆪ','ᄂ'=>'ᄂ','ᆬ'=>'ᆬ','ᆭ'=>'ᆭ','ᄃ'=>'ᄃ','ᄄ'=>'ᄄ','ᄅ'=>'ᄅ','ᆰ'=>'ᆰ','ᆱ'=>'ᆱ','ᆲ'=>'ᆲ','ᆳ'=>'ᆳ','ᆴ'=>'ᆴ','ᆵ'=>'ᆵ','ᄚ'=>'ᄚ','ᄆ'=>'ᄆ','ᄇ'=>'ᄇ','ᄈ'=>'ᄈ','ᄡ'=>'ᄡ','ᄉ'=>'ᄉ','ᄊ'=>'ᄊ','ᄋ'=>'ᄋ','ᄌ'=>'ᄌ','ᄍ'=>'ᄍ','ᄎ'=>'ᄎ','ᄏ'=>'ᄏ','ᄐ'=>'ᄐ','ᄑ'=>'ᄑ','ᄒ'=>'ᄒ','ᅡ'=>'ᅡ','ᅢ'=>'ᅢ','ᅣ'=>'ᅣ','ᅤ'=>'ᅤ','ᅥ'=>'ᅥ','ᅦ'=>'ᅦ','ᅧ'=>'ᅧ','ᅨ'=>'ᅨ','ᅩ'=>'ᅩ','ᅪ'=>'ᅪ','ᅫ'=>'ᅫ','ᅬ'=>'ᅬ','ᅭ'=>'ᅭ','ᅮ'=>'ᅮ','ᅯ'=>'ᅯ','ᅰ'=>'ᅰ','ᅱ'=>'ᅱ','ᅲ'=>'ᅲ','ᅳ'=>'ᅳ','ᅴ'=>'ᅴ','ᅵ'=>'ᅵ'); diff --git a/phpBB/includes/utf/data/search_indexer_32.php b/phpBB/includes/utf/data/search_indexer_32.php index 73ed2924ab..cea5ebad6a 100644 --- a/phpBB/includes/utf/data/search_indexer_32.php +++ b/phpBB/includes/utf/data/search_indexer_32.php @@ -1 +1 @@ -<?php return array('𐀀'=>'𐀀','𐀁'=>'𐀁','𐀂'=>'𐀂','𐀃'=>'𐀃','𐀄'=>'𐀄','𐀅'=>'𐀅','𐀆'=>'𐀆','𐀇'=>'𐀇','𐀈'=>'𐀈','𐀉'=>'𐀉','𐀊'=>'𐀊','𐀋'=>'𐀋','𐀍'=>'𐀍','𐀎'=>'𐀎','𐀏'=>'𐀏','𐀐'=>'𐀐','𐀑'=>'𐀑','𐀒'=>'𐀒','𐀓'=>'𐀓','𐀔'=>'𐀔','𐀕'=>'𐀕','𐀖'=>'𐀖','𐀗'=>'𐀗','𐀘'=>'𐀘','𐀙'=>'𐀙','𐀚'=>'𐀚','𐀛'=>'𐀛','𐀜'=>'𐀜','𐀝'=>'𐀝','𐀞'=>'𐀞','𐀟'=>'𐀟','𐀠'=>'𐀠','𐀡'=>'𐀡','𐀢'=>'𐀢','𐀣'=>'𐀣','𐀤'=>'𐀤','𐀥'=>'𐀥','𐀦'=>'𐀦','𐀨'=>'𐀨','𐀩'=>'𐀩','𐀪'=>'𐀪','𐀫'=>'𐀫','𐀬'=>'𐀬','𐀭'=>'𐀭','𐀮'=>'𐀮','𐀯'=>'𐀯','𐀰'=>'𐀰','𐀱'=>'𐀱','𐀲'=>'𐀲','𐀳'=>'𐀳','𐀴'=>'𐀴','𐀵'=>'𐀵','𐀶'=>'𐀶','𐀷'=>'𐀷','𐀸'=>'𐀸','𐀹'=>'𐀹','𐀺'=>'𐀺','𐀼'=>'𐀼','𐀽'=>'𐀽','𐀿'=>'𐀿','𐁀'=>'𐁀','𐁁'=>'𐁁','𐁂'=>'𐁂','𐁃'=>'𐁃','𐁄'=>'𐁄','𐁅'=>'𐁅','𐁆'=>'𐁆','𐁇'=>'𐁇','𐁈'=>'𐁈','𐁉'=>'𐁉','𐁊'=>'𐁊','𐁋'=>'𐁋','𐁌'=>'𐁌','𐁍'=>'𐁍','𐁐'=>'𐁐','𐁑'=>'𐁑','𐁒'=>'𐁒','𐁓'=>'𐁓','𐁔'=>'𐁔','𐁕'=>'𐁕','𐁖'=>'𐁖','𐁗'=>'𐁗','𐁘'=>'𐁘','𐁙'=>'𐁙','𐁚'=>'𐁚','𐁛'=>'𐁛','𐁜'=>'𐁜','𐁝'=>'𐁝','𐂀'=>'𐂀','𐂁'=>'𐂁','𐂂'=>'𐂂','𐂃'=>'𐂃','𐂄'=>'𐂄','𐂅'=>'𐂅','𐂆'=>'𐂆','𐂇'=>'𐂇','𐂈'=>'𐂈','𐂉'=>'𐂉','𐂊'=>'𐂊','𐂋'=>'𐂋','𐂌'=>'𐂌','𐂍'=>'𐂍','𐂎'=>'𐂎','𐂏'=>'𐂏','𐂐'=>'𐂐','𐂑'=>'𐂑','𐂒'=>'𐂒','𐂓'=>'𐂓','𐂔'=>'𐂔','𐂕'=>'𐂕','𐂖'=>'𐂖','𐂗'=>'𐂗','𐂘'=>'𐂘','𐂙'=>'𐂙','𐂚'=>'𐂚','𐂛'=>'𐂛','𐂜'=>'𐂜','𐂝'=>'𐂝','𐂞'=>'𐂞','𐂟'=>'𐂟','𐂠'=>'𐂠','𐂡'=>'𐂡','𐂢'=>'𐂢','𐂣'=>'𐂣','𐂤'=>'𐂤','𐂥'=>'𐂥','𐂦'=>'𐂦','𐂧'=>'𐂧','𐂨'=>'𐂨','𐂩'=>'𐂩','𐂪'=>'𐂪','𐂫'=>'𐂫','𐂬'=>'𐂬','𐂭'=>'𐂭','𐂮'=>'𐂮','𐂯'=>'𐂯','𐂰'=>'𐂰','𐂱'=>'𐂱','𐂲'=>'𐂲','𐂳'=>'𐂳','𐂴'=>'𐂴','𐂵'=>'𐂵','𐂶'=>'𐂶','𐂷'=>'𐂷','𐂸'=>'𐂸','𐂹'=>'𐂹','𐂺'=>'𐂺','𐂻'=>'𐂻','𐂼'=>'𐂼','𐂽'=>'𐂽','𐂾'=>'𐂾','𐂿'=>'𐂿','𐃀'=>'𐃀','𐃁'=>'𐃁','𐃂'=>'𐃂','𐃃'=>'𐃃','𐃄'=>'𐃄','𐃅'=>'𐃅','𐃆'=>'𐃆','𐃇'=>'𐃇','𐃈'=>'𐃈','𐃉'=>'𐃉','𐃊'=>'𐃊','𐃋'=>'𐃋','𐃌'=>'𐃌','𐃍'=>'𐃍','𐃎'=>'𐃎','𐃏'=>'𐃏','𐃐'=>'𐃐','𐃑'=>'𐃑','𐃒'=>'𐃒','𐃓'=>'𐃓','𐃔'=>'𐃔','𐃕'=>'𐃕','𐃖'=>'𐃖','𐃗'=>'𐃗','𐃘'=>'𐃘','𐃙'=>'𐃙','𐃚'=>'𐃚','𐃛'=>'𐃛','𐃜'=>'𐃜','𐃝'=>'𐃝','𐃞'=>'𐃞','𐃟'=>'𐃟','𐃠'=>'𐃠','𐃡'=>'𐃡','𐃢'=>'𐃢','𐃣'=>'𐃣','𐃤'=>'𐃤','𐃥'=>'𐃥','𐃦'=>'𐃦','𐃧'=>'𐃧','𐃨'=>'𐃨','𐃩'=>'𐃩','𐃪'=>'𐃪','𐃫'=>'𐃫','𐃬'=>'𐃬','𐃭'=>'𐃭','𐃮'=>'𐃮','𐃯'=>'𐃯','𐃰'=>'𐃰','𐃱'=>'𐃱','𐃲'=>'𐃲','𐃳'=>'𐃳','𐃴'=>'𐃴','𐃵'=>'𐃵','𐃶'=>'𐃶','𐃷'=>'𐃷','𐃸'=>'𐃸','𐃹'=>'𐃹','𐃺'=>'𐃺','𐄇'=>'1','𐄈'=>'2','𐄉'=>'3','𐄊'=>'4','𐄋'=>'5','𐄌'=>'6','𐄍'=>'7','𐄎'=>'8','𐄏'=>'9','𐄐'=>'10','𐄑'=>'20','𐄒'=>'30','𐄓'=>'40','𐄔'=>'50','𐄕'=>'60','𐄖'=>'70','𐄗'=>'80','𐄘'=>'90','𐄙'=>'100','𐄚'=>'200','𐄛'=>'300','𐄜'=>'400','𐄝'=>'500','𐄞'=>'600','𐄟'=>'700','𐄠'=>'800','𐄡'=>'900','𐄢'=>'1000','𐄣'=>'2000','𐄤'=>'3000','𐄥'=>'4000','𐄦'=>'5000','𐄧'=>'6000','𐄨'=>'7000','𐄩'=>'8000','𐄪'=>'9000','𐄫'=>'10000','𐄬'=>'20000','𐄭'=>'30000','𐄮'=>'40000','𐄯'=>'50000','𐄰'=>'60000','𐄱'=>'70000','𐄲'=>'80000','𐄳'=>'90000','𐅀'=>'1/4','𐅁'=>'1/2','𐅂'=>'1','𐅃'=>'5','𐅄'=>'50','𐅅'=>'500','𐅆'=>'5000','𐅇'=>'50000','𐅈'=>'5','𐅉'=>'10','𐅊'=>'50','𐅋'=>'100','𐅌'=>'500','𐅍'=>'1000','𐅎'=>'5000','𐅏'=>'5','𐅐'=>'10','𐅑'=>'50','𐅒'=>'100','𐅓'=>'500','𐅔'=>'1000','𐅕'=>'10000','𐅖'=>'50000','𐅗'=>'10','𐅘'=>'1','𐅙'=>'1','𐅚'=>'1','𐅛'=>'2','𐅜'=>'2','𐅝'=>'2','𐅞'=>'2','𐅟'=>'5','𐅠'=>'10','𐅡'=>'10','𐅢'=>'10','𐅣'=>'10','𐅤'=>'10','𐅥'=>'30','𐅦'=>'50','𐅧'=>'50','𐅨'=>'50','𐅩'=>'50','𐅪'=>'100','𐅫'=>'300','𐅬'=>'500','𐅭'=>'500','𐅮'=>'500','𐅯'=>'500','𐅰'=>'500','𐅱'=>'1000','𐅲'=>'5000','𐅳'=>'5','𐅴'=>'50','𐅵'=>'1/2','𐅶'=>'1/2','𐅷'=>'2/3','𐅸'=>'3/4','𐆊'=>'0','𐌀'=>'𐌀','𐌁'=>'𐌁','𐌂'=>'𐌂','𐌃'=>'𐌃','𐌄'=>'𐌄','𐌅'=>'𐌅','𐌆'=>'𐌆','𐌇'=>'𐌇','𐌈'=>'𐌈','𐌉'=>'𐌉','𐌊'=>'𐌊','𐌋'=>'𐌋','𐌌'=>'𐌌','𐌍'=>'𐌍','𐌎'=>'𐌎','𐌏'=>'𐌏','𐌐'=>'𐌐','𐌑'=>'𐌑','𐌒'=>'𐌒','𐌓'=>'𐌓','𐌔'=>'𐌔','𐌕'=>'𐌕','𐌖'=>'𐌖','𐌗'=>'𐌗','𐌘'=>'𐌘','𐌙'=>'𐌙','𐌚'=>'𐌚','𐌛'=>'𐌛','𐌜'=>'𐌜','𐌝'=>'𐌝','𐌞'=>'𐌞','𐌠'=>'1','𐌡'=>'5','𐌢'=>'10','𐌣'=>'50','𐌰'=>'𐌰','𐌱'=>'𐌱','𐌲'=>'𐌲','𐌳'=>'𐌳','𐌴'=>'𐌴','𐌵'=>'𐌵','𐌶'=>'𐌶','𐌷'=>'𐌷','𐌸'=>'𐌸','𐌹'=>'𐌹','𐌺'=>'𐌺','𐌻'=>'𐌻','𐌼'=>'𐌼','𐌽'=>'𐌽','𐌾'=>'𐌾','𐌿'=>'𐌿','𐍀'=>'𐍀','𐍁'=>'90','𐍂'=>'𐍂','𐍃'=>'𐍃','𐍄'=>'𐍄','𐍅'=>'𐍅','𐍆'=>'𐍆','𐍇'=>'𐍇','𐍈'=>'𐍈','𐍉'=>'𐍉','𐍊'=>'900','𐎀'=>'𐎀','𐎁'=>'𐎁','𐎂'=>'𐎂','𐎃'=>'𐎃','𐎄'=>'𐎄','𐎅'=>'𐎅','𐎆'=>'𐎆','𐎇'=>'𐎇','𐎈'=>'𐎈','𐎉'=>'𐎉','𐎊'=>'𐎊','𐎋'=>'𐎋','𐎌'=>'𐎌','𐎍'=>'𐎍','𐎎'=>'𐎎','𐎏'=>'𐎏','𐎐'=>'𐎐','𐎑'=>'𐎑','𐎒'=>'𐎒','𐎓'=>'𐎓','𐎔'=>'𐎔','𐎕'=>'𐎕','𐎖'=>'𐎖','𐎗'=>'𐎗','𐎘'=>'𐎘','𐎙'=>'𐎙','𐎚'=>'𐎚','𐎛'=>'𐎛','𐎜'=>'𐎜','𐎝'=>'𐎝','𐎠'=>'𐎠','𐎡'=>'𐎡','𐎢'=>'𐎢','𐎣'=>'𐎣','𐎤'=>'𐎤','𐎥'=>'𐎥','𐎦'=>'𐎦','𐎧'=>'𐎧','𐎨'=>'𐎨','𐎩'=>'𐎩','𐎪'=>'𐎪','𐎫'=>'𐎫','𐎬'=>'𐎬','𐎭'=>'𐎭','𐎮'=>'𐎮','𐎯'=>'𐎯','𐎰'=>'𐎰','𐎱'=>'𐎱','𐎲'=>'𐎲','𐎳'=>'𐎳','𐎴'=>'𐎴','𐎵'=>'𐎵','𐎶'=>'𐎶','𐎷'=>'𐎷','𐎸'=>'𐎸','𐎹'=>'𐎹','𐎺'=>'𐎺','𐎻'=>'𐎻','𐎼'=>'𐎼','𐎽'=>'𐎽','𐎾'=>'𐎾','𐎿'=>'𐎿','𐏀'=>'𐏀','𐏁'=>'𐏁','𐏂'=>'𐏂','𐏃'=>'𐏃','𐏈'=>'𐏈','𐏉'=>'𐏉','𐏊'=>'𐏊','𐏋'=>'𐏋','𐏌'=>'𐏌','𐏍'=>'𐏍','𐏎'=>'𐏎','𐏏'=>'𐏏','𐏑'=>'1','𐏒'=>'2','𐏓'=>'10','𐏔'=>'20','𐏕'=>'100','𐐀'=>'𐐨','𐐁'=>'𐐩','𐐂'=>'𐐪','𐐃'=>'𐐫','𐐄'=>'𐐬','𐐅'=>'𐐭','𐐆'=>'𐐮','𐐇'=>'𐐯','𐐈'=>'𐐰','𐐉'=>'𐐱','𐐊'=>'𐐲','𐐋'=>'𐐳','𐐌'=>'𐐴','𐐍'=>'𐐵','𐐎'=>'𐐶','𐐏'=>'𐐷','𐐐'=>'𐐸','𐐑'=>'𐐹','𐐒'=>'𐐺','𐐓'=>'𐐻','𐐔'=>'𐐼','𐐕'=>'𐐽','𐐖'=>'𐐾','𐐗'=>'𐐿','𐐘'=>'𐑀','𐐙'=>'𐑁','𐐚'=>'𐑂','𐐛'=>'𐑃','𐐜'=>'𐑄','𐐝'=>'𐑅','𐐞'=>'𐑆','𐐟'=>'𐑇','𐐠'=>'𐑈','𐐡'=>'𐑉','𐐢'=>'𐑊','𐐣'=>'𐑋','𐐤'=>'𐑌','𐐥'=>'𐑍','𐐦'=>'𐑎','𐐧'=>'𐑏','𐐨'=>'𐐨','𐐩'=>'𐐩','𐐪'=>'𐐪','𐐫'=>'𐐫','𐐬'=>'𐐬','𐐭'=>'𐐭','𐐮'=>'𐐮','𐐯'=>'𐐯','𐐰'=>'𐐰','𐐱'=>'𐐱','𐐲'=>'𐐲','𐐳'=>'𐐳','𐐴'=>'𐐴','𐐵'=>'𐐵','𐐶'=>'𐐶','𐐷'=>'𐐷','𐐸'=>'𐐸','𐐹'=>'𐐹','𐐺'=>'𐐺','𐐻'=>'𐐻','𐐼'=>'𐐼','𐐽'=>'𐐽','𐐾'=>'𐐾','𐐿'=>'𐐿','𐑀'=>'𐑀','𐑁'=>'𐑁','𐑂'=>'𐑂','𐑃'=>'𐑃','𐑄'=>'𐑄','𐑅'=>'𐑅','𐑆'=>'𐑆','𐑇'=>'𐑇','𐑈'=>'𐑈','𐑉'=>'𐑉','𐑊'=>'𐑊','𐑋'=>'𐑋','𐑌'=>'𐑌','𐑍'=>'𐑍','𐑎'=>'𐑎','𐑏'=>'𐑏','𐑐'=>'𐑐','𐑑'=>'𐑑','𐑒'=>'𐑒','𐑓'=>'𐑓','𐑔'=>'𐑔','𐑕'=>'𐑕','𐑖'=>'𐑖','𐑗'=>'𐑗','𐑘'=>'𐑘','𐑙'=>'𐑙','𐑚'=>'𐑚','𐑛'=>'𐑛','𐑜'=>'𐑜','𐑝'=>'𐑝','𐑞'=>'𐑞','𐑟'=>'𐑟','𐑠'=>'𐑠','𐑡'=>'𐑡','𐑢'=>'𐑢','𐑣'=>'𐑣','𐑤'=>'𐑤','𐑥'=>'𐑥','𐑦'=>'𐑦','𐑧'=>'𐑧','𐑨'=>'𐑨','𐑩'=>'𐑩','𐑪'=>'𐑪','𐑫'=>'𐑫','𐑬'=>'𐑬','𐑭'=>'𐑭','𐑮'=>'𐑮','𐑯'=>'𐑯','𐑰'=>'𐑰','𐑱'=>'𐑱','𐑲'=>'𐑲','𐑳'=>'𐑳','𐑴'=>'𐑴','𐑵'=>'𐑵','𐑶'=>'𐑶','𐑷'=>'𐑷','𐑸'=>'𐑸','𐑹'=>'𐑹','𐑺'=>'𐑺','𐑻'=>'𐑻','𐑼'=>'𐑼','𐑽'=>'𐑽','𐑾'=>'𐑾','𐑿'=>'𐑿','𐒀'=>'𐒀','𐒁'=>'𐒁','𐒂'=>'𐒂','𐒃'=>'𐒃','𐒄'=>'𐒄','𐒅'=>'𐒅','𐒆'=>'𐒆','𐒇'=>'𐒇','𐒈'=>'𐒈','𐒉'=>'𐒉','𐒊'=>'𐒊','𐒋'=>'𐒋','𐒌'=>'𐒌','𐒍'=>'𐒍','𐒎'=>'𐒎','𐒏'=>'𐒏','𐒐'=>'𐒐','𐒑'=>'𐒑','𐒒'=>'𐒒','𐒓'=>'𐒓','𐒔'=>'𐒔','𐒕'=>'𐒕','𐒖'=>'𐒖','𐒗'=>'𐒗','𐒘'=>'𐒘','𐒙'=>'𐒙','𐒚'=>'𐒚','𐒛'=>'𐒛','𐒜'=>'𐒜','𐒝'=>'𐒝','𐒠'=>'0','𐒡'=>'1','𐒢'=>'2','𐒣'=>'3','𐒤'=>'4','𐒥'=>'5','𐒦'=>'6','𐒧'=>'7','𐒨'=>'8','𐒩'=>'9');
\ No newline at end of file +<?php return array('𐀀'=>'𐀀','𐀁'=>'𐀁','𐀂'=>'𐀂','𐀃'=>'𐀃','𐀄'=>'𐀄','𐀅'=>'𐀅','𐀆'=>'𐀆','𐀇'=>'𐀇','𐀈'=>'𐀈','𐀉'=>'𐀉','𐀊'=>'𐀊','𐀋'=>'𐀋','𐀍'=>'𐀍','𐀎'=>'𐀎','𐀏'=>'𐀏','𐀐'=>'𐀐','𐀑'=>'𐀑','𐀒'=>'𐀒','𐀓'=>'𐀓','𐀔'=>'𐀔','𐀕'=>'𐀕','𐀖'=>'𐀖','𐀗'=>'𐀗','𐀘'=>'𐀘','𐀙'=>'𐀙','𐀚'=>'𐀚','𐀛'=>'𐀛','𐀜'=>'𐀜','𐀝'=>'𐀝','𐀞'=>'𐀞','𐀟'=>'𐀟','𐀠'=>'𐀠','𐀡'=>'𐀡','𐀢'=>'𐀢','𐀣'=>'𐀣','𐀤'=>'𐀤','𐀥'=>'𐀥','𐀦'=>'𐀦','𐀨'=>'𐀨','𐀩'=>'𐀩','𐀪'=>'𐀪','𐀫'=>'𐀫','𐀬'=>'𐀬','𐀭'=>'𐀭','𐀮'=>'𐀮','𐀯'=>'𐀯','𐀰'=>'𐀰','𐀱'=>'𐀱','𐀲'=>'𐀲','𐀳'=>'𐀳','𐀴'=>'𐀴','𐀵'=>'𐀵','𐀶'=>'𐀶','𐀷'=>'𐀷','𐀸'=>'𐀸','𐀹'=>'𐀹','𐀺'=>'𐀺','𐀼'=>'𐀼','𐀽'=>'𐀽','𐀿'=>'𐀿','𐁀'=>'𐁀','𐁁'=>'𐁁','𐁂'=>'𐁂','𐁃'=>'𐁃','𐁄'=>'𐁄','𐁅'=>'𐁅','𐁆'=>'𐁆','𐁇'=>'𐁇','𐁈'=>'𐁈','𐁉'=>'𐁉','𐁊'=>'𐁊','𐁋'=>'𐁋','𐁌'=>'𐁌','𐁍'=>'𐁍','𐁐'=>'𐁐','𐁑'=>'𐁑','𐁒'=>'𐁒','𐁓'=>'𐁓','𐁔'=>'𐁔','𐁕'=>'𐁕','𐁖'=>'𐁖','𐁗'=>'𐁗','𐁘'=>'𐁘','𐁙'=>'𐁙','𐁚'=>'𐁚','𐁛'=>'𐁛','𐁜'=>'𐁜','𐁝'=>'𐁝','𐂀'=>'𐂀','𐂁'=>'𐂁','𐂂'=>'𐂂','𐂃'=>'𐂃','𐂄'=>'𐂄','𐂅'=>'𐂅','𐂆'=>'𐂆','𐂇'=>'𐂇','𐂈'=>'𐂈','𐂉'=>'𐂉','𐂊'=>'𐂊','𐂋'=>'𐂋','𐂌'=>'𐂌','𐂍'=>'𐂍','𐂎'=>'𐂎','𐂏'=>'𐂏','𐂐'=>'𐂐','𐂑'=>'𐂑','𐂒'=>'𐂒','𐂓'=>'𐂓','𐂔'=>'𐂔','𐂕'=>'𐂕','𐂖'=>'𐂖','𐂗'=>'𐂗','𐂘'=>'𐂘','𐂙'=>'𐂙','𐂚'=>'𐂚','𐂛'=>'𐂛','𐂜'=>'𐂜','𐂝'=>'𐂝','𐂞'=>'𐂞','𐂟'=>'𐂟','𐂠'=>'𐂠','𐂡'=>'𐂡','𐂢'=>'𐂢','𐂣'=>'𐂣','𐂤'=>'𐂤','𐂥'=>'𐂥','𐂦'=>'𐂦','𐂧'=>'𐂧','𐂨'=>'𐂨','𐂩'=>'𐂩','𐂪'=>'𐂪','𐂫'=>'𐂫','𐂬'=>'𐂬','𐂭'=>'𐂭','𐂮'=>'𐂮','𐂯'=>'𐂯','𐂰'=>'𐂰','𐂱'=>'𐂱','𐂲'=>'𐂲','𐂳'=>'𐂳','𐂴'=>'𐂴','𐂵'=>'𐂵','𐂶'=>'𐂶','𐂷'=>'𐂷','𐂸'=>'𐂸','𐂹'=>'𐂹','𐂺'=>'𐂺','𐂻'=>'𐂻','𐂼'=>'𐂼','𐂽'=>'𐂽','𐂾'=>'𐂾','𐂿'=>'𐂿','𐃀'=>'𐃀','𐃁'=>'𐃁','𐃂'=>'𐃂','𐃃'=>'𐃃','𐃄'=>'𐃄','𐃅'=>'𐃅','𐃆'=>'𐃆','𐃇'=>'𐃇','𐃈'=>'𐃈','𐃉'=>'𐃉','𐃊'=>'𐃊','𐃋'=>'𐃋','𐃌'=>'𐃌','𐃍'=>'𐃍','𐃎'=>'𐃎','𐃏'=>'𐃏','𐃐'=>'𐃐','𐃑'=>'𐃑','𐃒'=>'𐃒','𐃓'=>'𐃓','𐃔'=>'𐃔','𐃕'=>'𐃕','𐃖'=>'𐃖','𐃗'=>'𐃗','𐃘'=>'𐃘','𐃙'=>'𐃙','𐃚'=>'𐃚','𐃛'=>'𐃛','𐃜'=>'𐃜','𐃝'=>'𐃝','𐃞'=>'𐃞','𐃟'=>'𐃟','𐃠'=>'𐃠','𐃡'=>'𐃡','𐃢'=>'𐃢','𐃣'=>'𐃣','𐃤'=>'𐃤','𐃥'=>'𐃥','𐃦'=>'𐃦','𐃧'=>'𐃧','𐃨'=>'𐃨','𐃩'=>'𐃩','𐃪'=>'𐃪','𐃫'=>'𐃫','𐃬'=>'𐃬','𐃭'=>'𐃭','𐃮'=>'𐃮','𐃯'=>'𐃯','𐃰'=>'𐃰','𐃱'=>'𐃱','𐃲'=>'𐃲','𐃳'=>'𐃳','𐃴'=>'𐃴','𐃵'=>'𐃵','𐃶'=>'𐃶','𐃷'=>'𐃷','𐃸'=>'𐃸','𐃹'=>'𐃹','𐃺'=>'𐃺','𐄇'=>'1','𐄈'=>'2','𐄉'=>'3','𐄊'=>'4','𐄋'=>'5','𐄌'=>'6','𐄍'=>'7','𐄎'=>'8','𐄏'=>'9','𐄐'=>'10','𐄑'=>'20','𐄒'=>'30','𐄓'=>'40','𐄔'=>'50','𐄕'=>'60','𐄖'=>'70','𐄗'=>'80','𐄘'=>'90','𐄙'=>'100','𐄚'=>'200','𐄛'=>'300','𐄜'=>'400','𐄝'=>'500','𐄞'=>'600','𐄟'=>'700','𐄠'=>'800','𐄡'=>'900','𐄢'=>'1000','𐄣'=>'2000','𐄤'=>'3000','𐄥'=>'4000','𐄦'=>'5000','𐄧'=>'6000','𐄨'=>'7000','𐄩'=>'8000','𐄪'=>'9000','𐄫'=>'10000','𐄬'=>'20000','𐄭'=>'30000','𐄮'=>'40000','𐄯'=>'50000','𐄰'=>'60000','𐄱'=>'70000','𐄲'=>'80000','𐄳'=>'90000','𐅀'=>'1/4','𐅁'=>'1/2','𐅂'=>'1','𐅃'=>'5','𐅄'=>'50','𐅅'=>'500','𐅆'=>'5000','𐅇'=>'50000','𐅈'=>'5','𐅉'=>'10','𐅊'=>'50','𐅋'=>'100','𐅌'=>'500','𐅍'=>'1000','𐅎'=>'5000','𐅏'=>'5','𐅐'=>'10','𐅑'=>'50','𐅒'=>'100','𐅓'=>'500','𐅔'=>'1000','𐅕'=>'10000','𐅖'=>'50000','𐅗'=>'10','𐅘'=>'1','𐅙'=>'1','𐅚'=>'1','𐅛'=>'2','𐅜'=>'2','𐅝'=>'2','𐅞'=>'2','𐅟'=>'5','𐅠'=>'10','𐅡'=>'10','𐅢'=>'10','𐅣'=>'10','𐅤'=>'10','𐅥'=>'30','𐅦'=>'50','𐅧'=>'50','𐅨'=>'50','𐅩'=>'50','𐅪'=>'100','𐅫'=>'300','𐅬'=>'500','𐅭'=>'500','𐅮'=>'500','𐅯'=>'500','𐅰'=>'500','𐅱'=>'1000','𐅲'=>'5000','𐅳'=>'5','𐅴'=>'50','𐅵'=>'1/2','𐅶'=>'1/2','𐅷'=>'2/3','𐅸'=>'3/4','𐆊'=>'0','𐌀'=>'𐌀','𐌁'=>'𐌁','𐌂'=>'𐌂','𐌃'=>'𐌃','𐌄'=>'𐌄','𐌅'=>'𐌅','𐌆'=>'𐌆','𐌇'=>'𐌇','𐌈'=>'𐌈','𐌉'=>'𐌉','𐌊'=>'𐌊','𐌋'=>'𐌋','𐌌'=>'𐌌','𐌍'=>'𐌍','𐌎'=>'𐌎','𐌏'=>'𐌏','𐌐'=>'𐌐','𐌑'=>'𐌑','𐌒'=>'𐌒','𐌓'=>'𐌓','𐌔'=>'𐌔','𐌕'=>'𐌕','𐌖'=>'𐌖','𐌗'=>'𐌗','𐌘'=>'𐌘','𐌙'=>'𐌙','𐌚'=>'𐌚','𐌛'=>'𐌛','𐌜'=>'𐌜','𐌝'=>'𐌝','𐌞'=>'𐌞','𐌠'=>'1','𐌡'=>'5','𐌢'=>'10','𐌣'=>'50','𐌰'=>'𐌰','𐌱'=>'𐌱','𐌲'=>'𐌲','𐌳'=>'𐌳','𐌴'=>'𐌴','𐌵'=>'𐌵','𐌶'=>'𐌶','𐌷'=>'𐌷','𐌸'=>'𐌸','𐌹'=>'𐌹','𐌺'=>'𐌺','𐌻'=>'𐌻','𐌼'=>'𐌼','𐌽'=>'𐌽','𐌾'=>'𐌾','𐌿'=>'𐌿','𐍀'=>'𐍀','𐍁'=>'90','𐍂'=>'𐍂','𐍃'=>'𐍃','𐍄'=>'𐍄','𐍅'=>'𐍅','𐍆'=>'𐍆','𐍇'=>'𐍇','𐍈'=>'𐍈','𐍉'=>'𐍉','𐍊'=>'900','𐎀'=>'𐎀','𐎁'=>'𐎁','𐎂'=>'𐎂','𐎃'=>'𐎃','𐎄'=>'𐎄','𐎅'=>'𐎅','𐎆'=>'𐎆','𐎇'=>'𐎇','𐎈'=>'𐎈','𐎉'=>'𐎉','𐎊'=>'𐎊','𐎋'=>'𐎋','𐎌'=>'𐎌','𐎍'=>'𐎍','𐎎'=>'𐎎','𐎏'=>'𐎏','𐎐'=>'𐎐','𐎑'=>'𐎑','𐎒'=>'𐎒','𐎓'=>'𐎓','𐎔'=>'𐎔','𐎕'=>'𐎕','𐎖'=>'𐎖','𐎗'=>'𐎗','𐎘'=>'𐎘','𐎙'=>'𐎙','𐎚'=>'𐎚','𐎛'=>'𐎛','𐎜'=>'𐎜','𐎝'=>'𐎝','𐎠'=>'𐎠','𐎡'=>'𐎡','𐎢'=>'𐎢','𐎣'=>'𐎣','𐎤'=>'𐎤','𐎥'=>'𐎥','𐎦'=>'𐎦','𐎧'=>'𐎧','𐎨'=>'𐎨','𐎩'=>'𐎩','𐎪'=>'𐎪','𐎫'=>'𐎫','𐎬'=>'𐎬','𐎭'=>'𐎭','𐎮'=>'𐎮','𐎯'=>'𐎯','𐎰'=>'𐎰','𐎱'=>'𐎱','𐎲'=>'𐎲','𐎳'=>'𐎳','𐎴'=>'𐎴','𐎵'=>'𐎵','𐎶'=>'𐎶','𐎷'=>'𐎷','𐎸'=>'𐎸','𐎹'=>'𐎹','𐎺'=>'𐎺','𐎻'=>'𐎻','𐎼'=>'𐎼','𐎽'=>'𐎽','𐎾'=>'𐎾','𐎿'=>'𐎿','𐏀'=>'𐏀','𐏁'=>'𐏁','𐏂'=>'𐏂','𐏃'=>'𐏃','𐏈'=>'𐏈','𐏉'=>'𐏉','𐏊'=>'𐏊','𐏋'=>'𐏋','𐏌'=>'𐏌','𐏍'=>'𐏍','𐏎'=>'𐏎','𐏏'=>'𐏏','𐏑'=>'1','𐏒'=>'2','𐏓'=>'10','𐏔'=>'20','𐏕'=>'100','𐐀'=>'𐐨','𐐁'=>'𐐩','𐐂'=>'𐐪','𐐃'=>'𐐫','𐐄'=>'𐐬','𐐅'=>'𐐭','𐐆'=>'𐐮','𐐇'=>'𐐯','𐐈'=>'𐐰','𐐉'=>'𐐱','𐐊'=>'𐐲','𐐋'=>'𐐳','𐐌'=>'𐐴','𐐍'=>'𐐵','𐐎'=>'𐐶','𐐏'=>'𐐷','𐐐'=>'𐐸','𐐑'=>'𐐹','𐐒'=>'𐐺','𐐓'=>'𐐻','𐐔'=>'𐐼','𐐕'=>'𐐽','𐐖'=>'𐐾','𐐗'=>'𐐿','𐐘'=>'𐑀','𐐙'=>'𐑁','𐐚'=>'𐑂','𐐛'=>'𐑃','𐐜'=>'𐑄','𐐝'=>'𐑅','𐐞'=>'𐑆','𐐟'=>'𐑇','𐐠'=>'𐑈','𐐡'=>'𐑉','𐐢'=>'𐑊','𐐣'=>'𐑋','𐐤'=>'𐑌','𐐥'=>'𐑍','𐐦'=>'𐑎','𐐧'=>'𐑏','𐐨'=>'𐐨','𐐩'=>'𐐩','𐐪'=>'𐐪','𐐫'=>'𐐫','𐐬'=>'𐐬','𐐭'=>'𐐭','𐐮'=>'𐐮','𐐯'=>'𐐯','𐐰'=>'𐐰','𐐱'=>'𐐱','𐐲'=>'𐐲','𐐳'=>'𐐳','𐐴'=>'𐐴','𐐵'=>'𐐵','𐐶'=>'𐐶','𐐷'=>'𐐷','𐐸'=>'𐐸','𐐹'=>'𐐹','𐐺'=>'𐐺','𐐻'=>'𐐻','𐐼'=>'𐐼','𐐽'=>'𐐽','𐐾'=>'𐐾','𐐿'=>'𐐿','𐑀'=>'𐑀','𐑁'=>'𐑁','𐑂'=>'𐑂','𐑃'=>'𐑃','𐑄'=>'𐑄','𐑅'=>'𐑅','𐑆'=>'𐑆','𐑇'=>'𐑇','𐑈'=>'𐑈','𐑉'=>'𐑉','𐑊'=>'𐑊','𐑋'=>'𐑋','𐑌'=>'𐑌','𐑍'=>'𐑍','𐑎'=>'𐑎','𐑏'=>'𐑏','𐑐'=>'𐑐','𐑑'=>'𐑑','𐑒'=>'𐑒','𐑓'=>'𐑓','𐑔'=>'𐑔','𐑕'=>'𐑕','𐑖'=>'𐑖','𐑗'=>'𐑗','𐑘'=>'𐑘','𐑙'=>'𐑙','𐑚'=>'𐑚','𐑛'=>'𐑛','𐑜'=>'𐑜','𐑝'=>'𐑝','𐑞'=>'𐑞','𐑟'=>'𐑟','𐑠'=>'𐑠','𐑡'=>'𐑡','𐑢'=>'𐑢','𐑣'=>'𐑣','𐑤'=>'𐑤','𐑥'=>'𐑥','𐑦'=>'𐑦','𐑧'=>'𐑧','𐑨'=>'𐑨','𐑩'=>'𐑩','𐑪'=>'𐑪','𐑫'=>'𐑫','𐑬'=>'𐑬','𐑭'=>'𐑭','𐑮'=>'𐑮','𐑯'=>'𐑯','𐑰'=>'𐑰','𐑱'=>'𐑱','𐑲'=>'𐑲','𐑳'=>'𐑳','𐑴'=>'𐑴','𐑵'=>'𐑵','𐑶'=>'𐑶','𐑷'=>'𐑷','𐑸'=>'𐑸','𐑹'=>'𐑹','𐑺'=>'𐑺','𐑻'=>'𐑻','𐑼'=>'𐑼','𐑽'=>'𐑽','𐑾'=>'𐑾','𐑿'=>'𐑿','𐒀'=>'𐒀','𐒁'=>'𐒁','𐒂'=>'𐒂','𐒃'=>'𐒃','𐒄'=>'𐒄','𐒅'=>'𐒅','𐒆'=>'𐒆','𐒇'=>'𐒇','𐒈'=>'𐒈','𐒉'=>'𐒉','𐒊'=>'𐒊','𐒋'=>'𐒋','𐒌'=>'𐒌','𐒍'=>'𐒍','𐒎'=>'𐒎','𐒏'=>'𐒏','𐒐'=>'𐒐','𐒑'=>'𐒑','𐒒'=>'𐒒','𐒓'=>'𐒓','𐒔'=>'𐒔','𐒕'=>'𐒕','𐒖'=>'𐒖','𐒗'=>'𐒗','𐒘'=>'𐒘','𐒙'=>'𐒙','𐒚'=>'𐒚','𐒛'=>'𐒛','𐒜'=>'𐒜','𐒝'=>'𐒝','𐒠'=>'0','𐒡'=>'1','𐒢'=>'2','𐒣'=>'3','𐒤'=>'4','𐒥'=>'5','𐒦'=>'6','𐒧'=>'7','𐒨'=>'8','𐒩'=>'9'); diff --git a/phpBB/includes/utf/data/search_indexer_33.php b/phpBB/includes/utf/data/search_indexer_33.php index 4e8762a646..3b77ca26f7 100644 --- a/phpBB/includes/utf/data/search_indexer_33.php +++ b/phpBB/includes/utf/data/search_indexer_33.php @@ -1 +1 @@ -<?php return array('𐠀'=>'𐠀','𐠁'=>'𐠁','𐠂'=>'𐠂','𐠃'=>'𐠃','𐠄'=>'𐠄','𐠅'=>'𐠅','𐠈'=>'𐠈','𐠊'=>'𐠊','𐠋'=>'𐠋','𐠌'=>'𐠌','𐠍'=>'𐠍','𐠎'=>'𐠎','𐠏'=>'𐠏','𐠐'=>'𐠐','𐠑'=>'𐠑','𐠒'=>'𐠒','𐠓'=>'𐠓','𐠔'=>'𐠔','𐠕'=>'𐠕','𐠖'=>'𐠖','𐠗'=>'𐠗','𐠘'=>'𐠘','𐠙'=>'𐠙','𐠚'=>'𐠚','𐠛'=>'𐠛','𐠜'=>'𐠜','𐠝'=>'𐠝','𐠞'=>'𐠞','𐠟'=>'𐠟','𐠠'=>'𐠠','𐠡'=>'𐠡','𐠢'=>'𐠢','𐠣'=>'𐠣','𐠤'=>'𐠤','𐠥'=>'𐠥','𐠦'=>'𐠦','𐠧'=>'𐠧','𐠨'=>'𐠨','𐠩'=>'𐠩','𐠪'=>'𐠪','𐠫'=>'𐠫','𐠬'=>'𐠬','𐠭'=>'𐠭','𐠮'=>'𐠮','𐠯'=>'𐠯','𐠰'=>'𐠰','𐠱'=>'𐠱','𐠲'=>'𐠲','𐠳'=>'𐠳','𐠴'=>'𐠴','𐠵'=>'𐠵','𐠷'=>'𐠷','𐠸'=>'𐠸','𐠼'=>'𐠼','𐠿'=>'𐠿','𐤀'=>'𐤀','𐤁'=>'𐤁','𐤂'=>'𐤂','𐤃'=>'𐤃','𐤄'=>'𐤄','𐤅'=>'𐤅','𐤆'=>'𐤆','𐤇'=>'𐤇','𐤈'=>'𐤈','𐤉'=>'𐤉','𐤊'=>'𐤊','𐤋'=>'𐤋','𐤌'=>'𐤌','𐤍'=>'𐤍','𐤎'=>'𐤎','𐤏'=>'𐤏','𐤐'=>'𐤐','𐤑'=>'𐤑','𐤒'=>'𐤒','𐤓'=>'𐤓','𐤔'=>'𐤔','𐤕'=>'𐤕','𐤖'=>'1','𐤗'=>'10','𐤘'=>'20','𐤙'=>'100','𐨀'=>'𐨀','𐨁'=>'𐨁','𐨂'=>'𐨂','𐨃'=>'𐨃','𐨅'=>'𐨅','𐨆'=>'𐨆','𐨌'=>'𐨌','𐨍'=>'𐨍','𐨎'=>'𐨎','𐨏'=>'𐨏','𐨐'=>'𐨐','𐨑'=>'𐨑','𐨒'=>'𐨒','𐨓'=>'𐨓','𐨕'=>'𐨕','𐨖'=>'𐨖','𐨗'=>'𐨗','𐨙'=>'𐨙','𐨚'=>'𐨚','𐨛'=>'𐨛','𐨜'=>'𐨜','𐨝'=>'𐨝','𐨞'=>'𐨞','𐨟'=>'𐨟','𐨠'=>'𐨠','𐨡'=>'𐨡','𐨢'=>'𐨢','𐨣'=>'𐨣','𐨤'=>'𐨤','𐨥'=>'𐨥','𐨦'=>'𐨦','𐨧'=>'𐨧','𐨨'=>'𐨨','𐨩'=>'𐨩','𐨪'=>'𐨪','𐨫'=>'𐨫','𐨬'=>'𐨬','𐨭'=>'𐨭','𐨮'=>'𐨮','𐨯'=>'𐨯','𐨰'=>'𐨰','𐨱'=>'𐨱','𐨲'=>'𐨲','𐨳'=>'𐨳','𐨸'=>'𐨸','𐨹'=>'𐨹','𐨺'=>'𐨺','𐨿'=>'𐨿','𐩀'=>'1','𐩁'=>'2','𐩂'=>'3','𐩃'=>'4','𐩄'=>'10','𐩅'=>'20','𐩆'=>'100','𐩇'=>'1000');
\ No newline at end of file +<?php return array('𐠀'=>'𐠀','𐠁'=>'𐠁','𐠂'=>'𐠂','𐠃'=>'𐠃','𐠄'=>'𐠄','𐠅'=>'𐠅','𐠈'=>'𐠈','𐠊'=>'𐠊','𐠋'=>'𐠋','𐠌'=>'𐠌','𐠍'=>'𐠍','𐠎'=>'𐠎','𐠏'=>'𐠏','𐠐'=>'𐠐','𐠑'=>'𐠑','𐠒'=>'𐠒','𐠓'=>'𐠓','𐠔'=>'𐠔','𐠕'=>'𐠕','𐠖'=>'𐠖','𐠗'=>'𐠗','𐠘'=>'𐠘','𐠙'=>'𐠙','𐠚'=>'𐠚','𐠛'=>'𐠛','𐠜'=>'𐠜','𐠝'=>'𐠝','𐠞'=>'𐠞','𐠟'=>'𐠟','𐠠'=>'𐠠','𐠡'=>'𐠡','𐠢'=>'𐠢','𐠣'=>'𐠣','𐠤'=>'𐠤','𐠥'=>'𐠥','𐠦'=>'𐠦','𐠧'=>'𐠧','𐠨'=>'𐠨','𐠩'=>'𐠩','𐠪'=>'𐠪','𐠫'=>'𐠫','𐠬'=>'𐠬','𐠭'=>'𐠭','𐠮'=>'𐠮','𐠯'=>'𐠯','𐠰'=>'𐠰','𐠱'=>'𐠱','𐠲'=>'𐠲','𐠳'=>'𐠳','𐠴'=>'𐠴','𐠵'=>'𐠵','𐠷'=>'𐠷','𐠸'=>'𐠸','𐠼'=>'𐠼','𐠿'=>'𐠿','𐤀'=>'𐤀','𐤁'=>'𐤁','𐤂'=>'𐤂','𐤃'=>'𐤃','𐤄'=>'𐤄','𐤅'=>'𐤅','𐤆'=>'𐤆','𐤇'=>'𐤇','𐤈'=>'𐤈','𐤉'=>'𐤉','𐤊'=>'𐤊','𐤋'=>'𐤋','𐤌'=>'𐤌','𐤍'=>'𐤍','𐤎'=>'𐤎','𐤏'=>'𐤏','𐤐'=>'𐤐','𐤑'=>'𐤑','𐤒'=>'𐤒','𐤓'=>'𐤓','𐤔'=>'𐤔','𐤕'=>'𐤕','𐤖'=>'1','𐤗'=>'10','𐤘'=>'20','𐤙'=>'100','𐨀'=>'𐨀','𐨁'=>'𐨁','𐨂'=>'𐨂','𐨃'=>'𐨃','𐨅'=>'𐨅','𐨆'=>'𐨆','𐨌'=>'𐨌','𐨍'=>'𐨍','𐨎'=>'𐨎','𐨏'=>'𐨏','𐨐'=>'𐨐','𐨑'=>'𐨑','𐨒'=>'𐨒','𐨓'=>'𐨓','𐨕'=>'𐨕','𐨖'=>'𐨖','𐨗'=>'𐨗','𐨙'=>'𐨙','𐨚'=>'𐨚','𐨛'=>'𐨛','𐨜'=>'𐨜','𐨝'=>'𐨝','𐨞'=>'𐨞','𐨟'=>'𐨟','𐨠'=>'𐨠','𐨡'=>'𐨡','𐨢'=>'𐨢','𐨣'=>'𐨣','𐨤'=>'𐨤','𐨥'=>'𐨥','𐨦'=>'𐨦','𐨧'=>'𐨧','𐨨'=>'𐨨','𐨩'=>'𐨩','𐨪'=>'𐨪','𐨫'=>'𐨫','𐨬'=>'𐨬','𐨭'=>'𐨭','𐨮'=>'𐨮','𐨯'=>'𐨯','𐨰'=>'𐨰','𐨱'=>'𐨱','𐨲'=>'𐨲','𐨳'=>'𐨳','𐨸'=>'𐨸','𐨹'=>'𐨹','𐨺'=>'𐨺','𐨿'=>'𐨿','𐩀'=>'1','𐩁'=>'2','𐩂'=>'3','𐩃'=>'4','𐩄'=>'10','𐩅'=>'20','𐩆'=>'100','𐩇'=>'1000'); diff --git a/phpBB/includes/utf/data/search_indexer_36.php b/phpBB/includes/utf/data/search_indexer_36.php index 8bf908e514..a970fa295b 100644 --- a/phpBB/includes/utf/data/search_indexer_36.php +++ b/phpBB/includes/utf/data/search_indexer_36.php @@ -1 +1 @@ -<?php return array('𒀀'=>'𒀀','𒀁'=>'𒀁','𒀂'=>'𒀂','𒀃'=>'𒀃','𒀄'=>'𒀄','𒀅'=>'𒀅','𒀆'=>'𒀆','𒀇'=>'𒀇','𒀈'=>'𒀈','𒀉'=>'𒀉','𒀊'=>'𒀊','𒀋'=>'𒀋','𒀌'=>'𒀌','𒀍'=>'𒀍','𒀎'=>'𒀎','𒀏'=>'𒀏','𒀐'=>'𒀐','𒀑'=>'𒀑','𒀒'=>'𒀒','𒀓'=>'𒀓','𒀔'=>'𒀔','𒀕'=>'𒀕','𒀖'=>'𒀖','𒀗'=>'𒀗','𒀘'=>'𒀘','𒀙'=>'𒀙','𒀚'=>'𒀚','𒀛'=>'𒀛','𒀜'=>'𒀜','𒀝'=>'𒀝','𒀞'=>'𒀞','𒀟'=>'𒀟','𒀠'=>'𒀠','𒀡'=>'𒀡','𒀢'=>'𒀢','𒀣'=>'𒀣','𒀤'=>'𒀤','𒀥'=>'𒀥','𒀦'=>'𒀦','𒀧'=>'𒀧','𒀨'=>'𒀨','𒀩'=>'𒀩','𒀪'=>'𒀪','𒀫'=>'𒀫','𒀬'=>'𒀬','𒀭'=>'𒀭','𒀮'=>'𒀮','𒀯'=>'𒀯','𒀰'=>'𒀰','𒀱'=>'𒀱','𒀲'=>'𒀲','𒀳'=>'𒀳','𒀴'=>'𒀴','𒀵'=>'𒀵','𒀶'=>'𒀶','𒀷'=>'𒀷','𒀸'=>'𒀸','𒀹'=>'𒀹','𒀺'=>'𒀺','𒀻'=>'𒀻','𒀼'=>'𒀼','𒀽'=>'𒀽','𒀾'=>'𒀾','𒀿'=>'𒀿','𒁀'=>'𒁀','𒁁'=>'𒁁','𒁂'=>'𒁂','𒁃'=>'𒁃','𒁄'=>'𒁄','𒁅'=>'𒁅','𒁆'=>'𒁆','𒁇'=>'𒁇','𒁈'=>'𒁈','𒁉'=>'𒁉','𒁊'=>'𒁊','𒁋'=>'𒁋','𒁌'=>'𒁌','𒁍'=>'𒁍','𒁎'=>'𒁎','𒁏'=>'𒁏','𒁐'=>'𒁐','𒁑'=>'𒁑','𒁒'=>'𒁒','𒁓'=>'𒁓','𒁔'=>'𒁔','𒁕'=>'𒁕','𒁖'=>'𒁖','𒁗'=>'𒁗','𒁘'=>'𒁘','𒁙'=>'𒁙','𒁚'=>'𒁚','𒁛'=>'𒁛','𒁜'=>'𒁜','𒁝'=>'𒁝','𒁞'=>'𒁞','𒁟'=>'𒁟','𒁠'=>'𒁠','𒁡'=>'𒁡','𒁢'=>'𒁢','𒁣'=>'𒁣','𒁤'=>'𒁤','𒁥'=>'𒁥','𒁦'=>'𒁦','𒁧'=>'𒁧','𒁨'=>'𒁨','𒁩'=>'𒁩','𒁪'=>'𒁪','𒁫'=>'𒁫','𒁬'=>'𒁬','𒁭'=>'𒁭','𒁮'=>'𒁮','𒁯'=>'𒁯','𒁰'=>'𒁰','𒁱'=>'𒁱','𒁲'=>'𒁲','𒁳'=>'𒁳','𒁴'=>'𒁴','𒁵'=>'𒁵','𒁶'=>'𒁶','𒁷'=>'𒁷','𒁸'=>'𒁸','𒁹'=>'𒁹','𒁺'=>'𒁺','𒁻'=>'𒁻','𒁼'=>'𒁼','𒁽'=>'𒁽','𒁾'=>'𒁾','𒁿'=>'𒁿','𒂀'=>'𒂀','𒂁'=>'𒂁','𒂂'=>'𒂂','𒂃'=>'𒂃','𒂄'=>'𒂄','𒂅'=>'𒂅','𒂆'=>'𒂆','𒂇'=>'𒂇','𒂈'=>'𒂈','𒂉'=>'𒂉','𒂊'=>'𒂊','𒂋'=>'𒂋','𒂌'=>'𒂌','𒂍'=>'𒂍','𒂎'=>'𒂎','𒂏'=>'𒂏','𒂐'=>'𒂐','𒂑'=>'𒂑','𒂒'=>'𒂒','𒂓'=>'𒂓','𒂔'=>'𒂔','𒂕'=>'𒂕','𒂖'=>'𒂖','𒂗'=>'𒂗','𒂘'=>'𒂘','𒂙'=>'𒂙','𒂚'=>'𒂚','𒂛'=>'𒂛','𒂜'=>'𒂜','𒂝'=>'𒂝','𒂞'=>'𒂞','𒂟'=>'𒂟','𒂠'=>'𒂠','𒂡'=>'𒂡','𒂢'=>'𒂢','𒂣'=>'𒂣','𒂤'=>'𒂤','𒂥'=>'𒂥','𒂦'=>'𒂦','𒂧'=>'𒂧','𒂨'=>'𒂨','𒂩'=>'𒂩','𒂪'=>'𒂪','𒂫'=>'𒂫','𒂬'=>'𒂬','𒂭'=>'𒂭','𒂮'=>'𒂮','𒂯'=>'𒂯','𒂰'=>'𒂰','𒂱'=>'𒂱','𒂲'=>'𒂲','𒂳'=>'𒂳','𒂴'=>'𒂴','𒂵'=>'𒂵','𒂶'=>'𒂶','𒂷'=>'𒂷','𒂸'=>'𒂸','𒂹'=>'𒂹','𒂺'=>'𒂺','𒂻'=>'𒂻','𒂼'=>'𒂼','𒂽'=>'𒂽','𒂾'=>'𒂾','𒂿'=>'𒂿','𒃀'=>'𒃀','𒃁'=>'𒃁','𒃂'=>'𒃂','𒃃'=>'𒃃','𒃄'=>'𒃄','𒃅'=>'𒃅','𒃆'=>'𒃆','𒃇'=>'𒃇','𒃈'=>'𒃈','𒃉'=>'𒃉','𒃊'=>'𒃊','𒃋'=>'𒃋','𒃌'=>'𒃌','𒃍'=>'𒃍','𒃎'=>'𒃎','𒃏'=>'𒃏','𒃐'=>'𒃐','𒃑'=>'𒃑','𒃒'=>'𒃒','𒃓'=>'𒃓','𒃔'=>'𒃔','𒃕'=>'𒃕','𒃖'=>'𒃖','𒃗'=>'𒃗','𒃘'=>'𒃘','𒃙'=>'𒃙','𒃚'=>'𒃚','𒃛'=>'𒃛','𒃜'=>'𒃜','𒃝'=>'𒃝','𒃞'=>'𒃞','𒃟'=>'𒃟','𒃠'=>'𒃠','𒃡'=>'𒃡','𒃢'=>'𒃢','𒃣'=>'𒃣','𒃤'=>'𒃤','𒃥'=>'𒃥','𒃦'=>'𒃦','𒃧'=>'𒃧','𒃨'=>'𒃨','𒃩'=>'𒃩','𒃪'=>'𒃪','𒃫'=>'𒃫','𒃬'=>'𒃬','𒃭'=>'𒃭','𒃮'=>'𒃮','𒃯'=>'𒃯','𒃰'=>'𒃰','𒃱'=>'𒃱','𒃲'=>'𒃲','𒃳'=>'𒃳','𒃴'=>'𒃴','𒃵'=>'𒃵','𒃶'=>'𒃶','𒃷'=>'𒃷','𒃸'=>'𒃸','𒃹'=>'𒃹','𒃺'=>'𒃺','𒃻'=>'𒃻','𒃼'=>'𒃼','𒃽'=>'𒃽','𒃾'=>'𒃾','𒃿'=>'𒃿','𒄀'=>'𒄀','𒄁'=>'𒄁','𒄂'=>'𒄂','𒄃'=>'𒄃','𒄄'=>'𒄄','𒄅'=>'𒄅','𒄆'=>'𒄆','𒄇'=>'𒄇','𒄈'=>'𒄈','𒄉'=>'𒄉','𒄊'=>'𒄊','𒄋'=>'𒄋','𒄌'=>'𒄌','𒄍'=>'𒄍','𒄎'=>'𒄎','𒄏'=>'𒄏','𒄐'=>'𒄐','𒄑'=>'𒄑','𒄒'=>'𒄒','𒄓'=>'𒄓','𒄔'=>'𒄔','𒄕'=>'𒄕','𒄖'=>'𒄖','𒄗'=>'𒄗','𒄘'=>'𒄘','𒄙'=>'𒄙','𒄚'=>'𒄚','𒄛'=>'𒄛','𒄜'=>'𒄜','𒄝'=>'𒄝','𒄞'=>'𒄞','𒄟'=>'𒄟','𒄠'=>'𒄠','𒄡'=>'𒄡','𒄢'=>'𒄢','𒄣'=>'𒄣','𒄤'=>'𒄤','𒄥'=>'𒄥','𒄦'=>'𒄦','𒄧'=>'𒄧','𒄨'=>'𒄨','𒄩'=>'𒄩','𒄪'=>'𒄪','𒄫'=>'𒄫','𒄬'=>'𒄬','𒄭'=>'𒄭','𒄮'=>'𒄮','𒄯'=>'𒄯','𒄰'=>'𒄰','𒄱'=>'𒄱','𒄲'=>'𒄲','𒄳'=>'𒄳','𒄴'=>'𒄴','𒄵'=>'𒄵','𒄶'=>'𒄶','𒄷'=>'𒄷','𒄸'=>'𒄸','𒄹'=>'𒄹','𒄺'=>'𒄺','𒄻'=>'𒄻','𒄼'=>'𒄼','𒄽'=>'𒄽','𒄾'=>'𒄾','𒄿'=>'𒄿','𒅀'=>'𒅀','𒅁'=>'𒅁','𒅂'=>'𒅂','𒅃'=>'𒅃','𒅄'=>'𒅄','𒅅'=>'𒅅','𒅆'=>'𒅆','𒅇'=>'𒅇','𒅈'=>'𒅈','𒅉'=>'𒅉','𒅊'=>'𒅊','𒅋'=>'𒅋','𒅌'=>'𒅌','𒅍'=>'𒅍','𒅎'=>'𒅎','𒅏'=>'𒅏','𒅐'=>'𒅐','𒅑'=>'𒅑','𒅒'=>'𒅒','𒅓'=>'𒅓','𒅔'=>'𒅔','𒅕'=>'𒅕','𒅖'=>'𒅖','𒅗'=>'𒅗','𒅘'=>'𒅘','𒅙'=>'𒅙','𒅚'=>'𒅚','𒅛'=>'𒅛','𒅜'=>'𒅜','𒅝'=>'𒅝','𒅞'=>'𒅞','𒅟'=>'𒅟','𒅠'=>'𒅠','𒅡'=>'𒅡','𒅢'=>'𒅢','𒅣'=>'𒅣','𒅤'=>'𒅤','𒅥'=>'𒅥','𒅦'=>'𒅦','𒅧'=>'𒅧','𒅨'=>'𒅨','𒅩'=>'𒅩','𒅪'=>'𒅪','𒅫'=>'𒅫','𒅬'=>'𒅬','𒅭'=>'𒅭','𒅮'=>'𒅮','𒅯'=>'𒅯','𒅰'=>'𒅰','𒅱'=>'𒅱','𒅲'=>'𒅲','𒅳'=>'𒅳','𒅴'=>'𒅴','𒅵'=>'𒅵','𒅶'=>'𒅶','𒅷'=>'𒅷','𒅸'=>'𒅸','𒅹'=>'𒅹','𒅺'=>'𒅺','𒅻'=>'𒅻','𒅼'=>'𒅼','𒅽'=>'𒅽','𒅾'=>'𒅾','𒅿'=>'𒅿','𒆀'=>'𒆀','𒆁'=>'𒆁','𒆂'=>'𒆂','𒆃'=>'𒆃','𒆄'=>'𒆄','𒆅'=>'𒆅','𒆆'=>'𒆆','𒆇'=>'𒆇','𒆈'=>'𒆈','𒆉'=>'𒆉','𒆊'=>'𒆊','𒆋'=>'𒆋','𒆌'=>'𒆌','𒆍'=>'𒆍','𒆎'=>'𒆎','𒆏'=>'𒆏','𒆐'=>'𒆐','𒆑'=>'𒆑','𒆒'=>'𒆒','𒆓'=>'𒆓','𒆔'=>'𒆔','𒆕'=>'𒆕','𒆖'=>'𒆖','𒆗'=>'𒆗','𒆘'=>'𒆘','𒆙'=>'𒆙','𒆚'=>'𒆚','𒆛'=>'𒆛','𒆜'=>'𒆜','𒆝'=>'𒆝','𒆞'=>'𒆞','𒆟'=>'𒆟','𒆠'=>'𒆠','𒆡'=>'𒆡','𒆢'=>'𒆢','𒆣'=>'𒆣','𒆤'=>'𒆤','𒆥'=>'𒆥','𒆦'=>'𒆦','𒆧'=>'𒆧','𒆨'=>'𒆨','𒆩'=>'𒆩','𒆪'=>'𒆪','𒆫'=>'𒆫','𒆬'=>'𒆬','𒆭'=>'𒆭','𒆮'=>'𒆮','𒆯'=>'𒆯','𒆰'=>'𒆰','𒆱'=>'𒆱','𒆲'=>'𒆲','𒆳'=>'𒆳','𒆴'=>'𒆴','𒆵'=>'𒆵','𒆶'=>'𒆶','𒆷'=>'𒆷','𒆸'=>'𒆸','𒆹'=>'𒆹','𒆺'=>'𒆺','𒆻'=>'𒆻','𒆼'=>'𒆼','𒆽'=>'𒆽','𒆾'=>'𒆾','𒆿'=>'𒆿','𒇀'=>'𒇀','𒇁'=>'𒇁','𒇂'=>'𒇂','𒇃'=>'𒇃','𒇄'=>'𒇄','𒇅'=>'𒇅','𒇆'=>'𒇆','𒇇'=>'𒇇','𒇈'=>'𒇈','𒇉'=>'𒇉','𒇊'=>'𒇊','𒇋'=>'𒇋','𒇌'=>'𒇌','𒇍'=>'𒇍','𒇎'=>'𒇎','𒇏'=>'𒇏','𒇐'=>'𒇐','𒇑'=>'𒇑','𒇒'=>'𒇒','𒇓'=>'𒇓','𒇔'=>'𒇔','𒇕'=>'𒇕','𒇖'=>'𒇖','𒇗'=>'𒇗','𒇘'=>'𒇘','𒇙'=>'𒇙','𒇚'=>'𒇚','𒇛'=>'𒇛','𒇜'=>'𒇜','𒇝'=>'𒇝','𒇞'=>'𒇞','𒇟'=>'𒇟','𒇠'=>'𒇠','𒇡'=>'𒇡','𒇢'=>'𒇢','𒇣'=>'𒇣','𒇤'=>'𒇤','𒇥'=>'𒇥','𒇦'=>'𒇦','𒇧'=>'𒇧','𒇨'=>'𒇨','𒇩'=>'𒇩','𒇪'=>'𒇪','𒇫'=>'𒇫','𒇬'=>'𒇬','𒇭'=>'𒇭','𒇮'=>'𒇮','𒇯'=>'𒇯','𒇰'=>'𒇰','𒇱'=>'𒇱','𒇲'=>'𒇲','𒇳'=>'𒇳','𒇴'=>'𒇴','𒇵'=>'𒇵','𒇶'=>'𒇶','𒇷'=>'𒇷','𒇸'=>'𒇸','𒇹'=>'𒇹','𒇺'=>'𒇺','𒇻'=>'𒇻','𒇼'=>'𒇼','𒇽'=>'𒇽','𒇾'=>'𒇾','𒇿'=>'𒇿','𒈀'=>'𒈀','𒈁'=>'𒈁','𒈂'=>'𒈂','𒈃'=>'𒈃','𒈄'=>'𒈄','𒈅'=>'𒈅','𒈆'=>'𒈆','𒈇'=>'𒈇','𒈈'=>'𒈈','𒈉'=>'𒈉','𒈊'=>'𒈊','𒈋'=>'𒈋','𒈌'=>'𒈌','𒈍'=>'𒈍','𒈎'=>'𒈎','𒈏'=>'𒈏','𒈐'=>'𒈐','𒈑'=>'𒈑','𒈒'=>'𒈒','𒈓'=>'𒈓','𒈔'=>'𒈔','𒈕'=>'𒈕','𒈖'=>'𒈖','𒈗'=>'𒈗','𒈘'=>'𒈘','𒈙'=>'𒈙','𒈚'=>'𒈚','𒈛'=>'𒈛','𒈜'=>'𒈜','𒈝'=>'𒈝','𒈞'=>'𒈞','𒈟'=>'𒈟','𒈠'=>'𒈠','𒈡'=>'𒈡','𒈢'=>'𒈢','𒈣'=>'𒈣','𒈤'=>'𒈤','𒈥'=>'𒈥','𒈦'=>'𒈦','𒈧'=>'𒈧','𒈨'=>'𒈨','𒈩'=>'𒈩','𒈪'=>'𒈪','𒈫'=>'𒈫','𒈬'=>'𒈬','𒈭'=>'𒈭','𒈮'=>'𒈮','𒈯'=>'𒈯','𒈰'=>'𒈰','𒈱'=>'𒈱','𒈲'=>'𒈲','𒈳'=>'𒈳','𒈴'=>'𒈴','𒈵'=>'𒈵','𒈶'=>'𒈶','𒈷'=>'𒈷','𒈸'=>'𒈸','𒈹'=>'𒈹','𒈺'=>'𒈺','𒈻'=>'𒈻','𒈼'=>'𒈼','𒈽'=>'𒈽','𒈾'=>'𒈾','𒈿'=>'𒈿','𒉀'=>'𒉀','𒉁'=>'𒉁','𒉂'=>'𒉂','𒉃'=>'𒉃','𒉄'=>'𒉄','𒉅'=>'𒉅','𒉆'=>'𒉆','𒉇'=>'𒉇','𒉈'=>'𒉈','𒉉'=>'𒉉','𒉊'=>'𒉊','𒉋'=>'𒉋','𒉌'=>'𒉌','𒉍'=>'𒉍','𒉎'=>'𒉎','𒉏'=>'𒉏','𒉐'=>'𒉐','𒉑'=>'𒉑','𒉒'=>'𒉒','𒉓'=>'𒉓','𒉔'=>'𒉔','𒉕'=>'𒉕','𒉖'=>'𒉖','𒉗'=>'𒉗','𒉘'=>'𒉘','𒉙'=>'𒉙','𒉚'=>'𒉚','𒉛'=>'𒉛','𒉜'=>'𒉜','𒉝'=>'𒉝','𒉞'=>'𒉞','𒉟'=>'𒉟','𒉠'=>'𒉠','𒉡'=>'𒉡','𒉢'=>'𒉢','𒉣'=>'𒉣','𒉤'=>'𒉤','𒉥'=>'𒉥','𒉦'=>'𒉦','𒉧'=>'𒉧','𒉨'=>'𒉨','𒉩'=>'𒉩','𒉪'=>'𒉪','𒉫'=>'𒉫','𒉬'=>'𒉬','𒉭'=>'𒉭','𒉮'=>'𒉮','𒉯'=>'𒉯','𒉰'=>'𒉰','𒉱'=>'𒉱','𒉲'=>'𒉲','𒉳'=>'𒉳','𒉴'=>'𒉴','𒉵'=>'𒉵','𒉶'=>'𒉶','𒉷'=>'𒉷','𒉸'=>'𒉸','𒉹'=>'𒉹','𒉺'=>'𒉺','𒉻'=>'𒉻','𒉼'=>'𒉼','𒉽'=>'𒉽','𒉾'=>'𒉾','𒉿'=>'𒉿','𒊀'=>'𒊀','𒊁'=>'𒊁','𒊂'=>'𒊂','𒊃'=>'𒊃','𒊄'=>'𒊄','𒊅'=>'𒊅','𒊆'=>'𒊆','𒊇'=>'𒊇','𒊈'=>'𒊈','𒊉'=>'𒊉','𒊊'=>'𒊊','𒊋'=>'𒊋','𒊌'=>'𒊌','𒊍'=>'𒊍','𒊎'=>'𒊎','𒊏'=>'𒊏','𒊐'=>'𒊐','𒊑'=>'𒊑','𒊒'=>'𒊒','𒊓'=>'𒊓','𒊔'=>'𒊔','𒊕'=>'𒊕','𒊖'=>'𒊖','𒊗'=>'𒊗','𒊘'=>'𒊘','𒊙'=>'𒊙','𒊚'=>'𒊚','𒊛'=>'𒊛','𒊜'=>'𒊜','𒊝'=>'𒊝','𒊞'=>'𒊞','𒊟'=>'𒊟','𒊠'=>'𒊠','𒊡'=>'𒊡','𒊢'=>'𒊢','𒊣'=>'𒊣','𒊤'=>'𒊤','𒊥'=>'𒊥','𒊦'=>'𒊦','𒊧'=>'𒊧','𒊨'=>'𒊨','𒊩'=>'𒊩','𒊪'=>'𒊪','𒊫'=>'𒊫','𒊬'=>'𒊬','𒊭'=>'𒊭','𒊮'=>'𒊮','𒊯'=>'𒊯','𒊰'=>'𒊰','𒊱'=>'𒊱','𒊲'=>'𒊲','𒊳'=>'𒊳','𒊴'=>'𒊴','𒊵'=>'𒊵','𒊶'=>'𒊶','𒊷'=>'𒊷','𒊸'=>'𒊸','𒊹'=>'𒊹','𒊺'=>'𒊺','𒊻'=>'𒊻','𒊼'=>'𒊼','𒊽'=>'𒊽','𒊾'=>'𒊾','𒊿'=>'𒊿','𒋀'=>'𒋀','𒋁'=>'𒋁','𒋂'=>'𒋂','𒋃'=>'𒋃','𒋄'=>'𒋄','𒋅'=>'𒋅','𒋆'=>'𒋆','𒋇'=>'𒋇','𒋈'=>'𒋈','𒋉'=>'𒋉','𒋊'=>'𒋊','𒋋'=>'𒋋','𒋌'=>'𒋌','𒋍'=>'𒋍','𒋎'=>'𒋎','𒋏'=>'𒋏','𒋐'=>'𒋐','𒋑'=>'𒋑','𒋒'=>'𒋒','𒋓'=>'𒋓','𒋔'=>'𒋔','𒋕'=>'𒋕','𒋖'=>'𒋖','𒋗'=>'𒋗','𒋘'=>'𒋘','𒋙'=>'𒋙','𒋚'=>'𒋚','𒋛'=>'𒋛','𒋜'=>'𒋜','𒋝'=>'𒋝','𒋞'=>'𒋞','𒋟'=>'𒋟','𒋠'=>'𒋠','𒋡'=>'𒋡','𒋢'=>'𒋢','𒋣'=>'𒋣','𒋤'=>'𒋤','𒋥'=>'𒋥','𒋦'=>'𒋦','𒋧'=>'𒋧','𒋨'=>'𒋨','𒋩'=>'𒋩','𒋪'=>'𒋪','𒋫'=>'𒋫','𒋬'=>'𒋬','𒋭'=>'𒋭','𒋮'=>'𒋮','𒋯'=>'𒋯','𒋰'=>'𒋰','𒋱'=>'𒋱','𒋲'=>'𒋲','𒋳'=>'𒋳','𒋴'=>'𒋴','𒋵'=>'𒋵','𒋶'=>'𒋶','𒋷'=>'𒋷','𒋸'=>'𒋸','𒋹'=>'𒋹','𒋺'=>'𒋺','𒋻'=>'𒋻','𒋼'=>'𒋼','𒋽'=>'𒋽','𒋾'=>'𒋾','𒋿'=>'𒋿','𒌀'=>'𒌀','𒌁'=>'𒌁','𒌂'=>'𒌂','𒌃'=>'𒌃','𒌄'=>'𒌄','𒌅'=>'𒌅','𒌆'=>'𒌆','𒌇'=>'𒌇','𒌈'=>'𒌈','𒌉'=>'𒌉','𒌊'=>'𒌊','𒌋'=>'𒌋','𒌌'=>'𒌌','𒌍'=>'𒌍','𒌎'=>'𒌎','𒌏'=>'𒌏','𒌐'=>'𒌐','𒌑'=>'𒌑','𒌒'=>'𒌒','𒌓'=>'𒌓','𒌔'=>'𒌔','𒌕'=>'𒌕','𒌖'=>'𒌖','𒌗'=>'𒌗','𒌘'=>'𒌘','𒌙'=>'𒌙','𒌚'=>'𒌚','𒌛'=>'𒌛','𒌜'=>'𒌜','𒌝'=>'𒌝','𒌞'=>'𒌞','𒌟'=>'𒌟','𒌠'=>'𒌠','𒌡'=>'𒌡','𒌢'=>'𒌢','𒌣'=>'𒌣','𒌤'=>'𒌤','𒌥'=>'𒌥','𒌦'=>'𒌦','𒌧'=>'𒌧','𒌨'=>'𒌨','𒌩'=>'𒌩','𒌪'=>'𒌪','𒌫'=>'𒌫','𒌬'=>'𒌬','𒌭'=>'𒌭','𒌮'=>'𒌮','𒌯'=>'𒌯','𒌰'=>'𒌰','𒌱'=>'𒌱','𒌲'=>'𒌲','𒌳'=>'𒌳','𒌴'=>'𒌴','𒌵'=>'𒌵','𒌶'=>'𒌶','𒌷'=>'𒌷','𒌸'=>'𒌸','𒌹'=>'𒌹','𒌺'=>'𒌺','𒌻'=>'𒌻','𒌼'=>'𒌼','𒌽'=>'𒌽','𒌾'=>'𒌾','𒌿'=>'𒌿','𒍀'=>'𒍀','𒍁'=>'𒍁','𒍂'=>'𒍂','𒍃'=>'𒍃','𒍄'=>'𒍄','𒍅'=>'𒍅','𒍆'=>'𒍆','𒍇'=>'𒍇','𒍈'=>'𒍈','𒍉'=>'𒍉','𒍊'=>'𒍊','𒍋'=>'𒍋','𒍌'=>'𒍌','𒍍'=>'𒍍','𒍎'=>'𒍎','𒍏'=>'𒍏','𒍐'=>'𒍐','𒍑'=>'𒍑','𒍒'=>'𒍒','𒍓'=>'𒍓','𒍔'=>'𒍔','𒍕'=>'𒍕','𒍖'=>'𒍖','𒍗'=>'𒍗','𒍘'=>'𒍘','𒍙'=>'𒍙','𒍚'=>'𒍚','𒍛'=>'𒍛','𒍜'=>'𒍜','𒍝'=>'𒍝','𒍞'=>'𒍞','𒍟'=>'𒍟','𒍠'=>'𒍠','𒍡'=>'𒍡','𒍢'=>'𒍢','𒍣'=>'𒍣','𒍤'=>'𒍤','𒍥'=>'𒍥','𒍦'=>'𒍦','𒍧'=>'𒍧','𒍨'=>'𒍨','𒍩'=>'𒍩','𒍪'=>'𒍪','𒍫'=>'𒍫','𒍬'=>'𒍬','𒍭'=>'𒍭','𒍮'=>'𒍮','𒐀'=>'2','𒐁'=>'3','𒐂'=>'4','𒐃'=>'5','𒐄'=>'6','𒐅'=>'7','𒐆'=>'8','𒐇'=>'9','𒐈'=>'3','𒐉'=>'4','𒐊'=>'5','𒐋'=>'6','𒐌'=>'7','𒐍'=>'8','𒐎'=>'9','𒐏'=>'4','𒐐'=>'5','𒐑'=>'6','𒐒'=>'7','𒐓'=>'8','𒐔'=>'9','𒐕'=>'1','𒐖'=>'2','𒐗'=>'3','𒐘'=>'4','𒐙'=>'5','𒐚'=>'6','𒐛'=>'7','𒐜'=>'8','𒐝'=>'9','𒐞'=>'1','𒐟'=>'2','𒐠'=>'3','𒐡'=>'4','𒐢'=>'5','𒐣'=>'2','𒐤'=>'3','𒐥'=>'3','𒐦'=>'4','𒐧'=>'5','𒐨'=>'6','𒐩'=>'7','𒐪'=>'8','𒐫'=>'9','𒐬'=>'1','𒐭'=>'2','𒐮'=>'3','𒐯'=>'3','𒐰'=>'4','𒐱'=>'5','𒐲'=>'𒐲','𒐳'=>'𒐳','𒐴'=>'1','𒐵'=>'2','𒐶'=>'3','𒐷'=>'3','𒐸'=>'4','𒐹'=>'5','𒐺'=>'3','𒐻'=>'3','𒐼'=>'4','𒐽'=>'4','𒐾'=>'4','𒐿'=>'4','𒑀'=>'6','𒑁'=>'7','𒑂'=>'7','𒑃'=>'7','𒑄'=>'8','𒑅'=>'8','𒑆'=>'9','𒑇'=>'9','𒑈'=>'9','𒑉'=>'9','𒑊'=>'2','𒑋'=>'3','𒑌'=>'4','𒑍'=>'5','𒑎'=>'6','𒑏'=>'1','𒑐'=>'2','𒑑'=>'3','𒑒'=>'4','𒑓'=>'4','𒑔'=>'5','𒑕'=>'5','𒑖'=>'𒑖','𒑗'=>'𒑗','𒑘'=>'1','𒑙'=>'2','𒑚'=>'1/3','𒑛'=>'2/3','𒑜'=>'5/6','𒑝'=>'1/3','𒑞'=>'2/3','𒑟'=>'1/8','𒑠'=>'1/4','𒑡'=>'1/6','𒑢'=>'1/4');
\ No newline at end of file +<?php return array('𒀀'=>'𒀀','𒀁'=>'𒀁','𒀂'=>'𒀂','𒀃'=>'𒀃','𒀄'=>'𒀄','𒀅'=>'𒀅','𒀆'=>'𒀆','𒀇'=>'𒀇','𒀈'=>'𒀈','𒀉'=>'𒀉','𒀊'=>'𒀊','𒀋'=>'𒀋','𒀌'=>'𒀌','𒀍'=>'𒀍','𒀎'=>'𒀎','𒀏'=>'𒀏','𒀐'=>'𒀐','𒀑'=>'𒀑','𒀒'=>'𒀒','𒀓'=>'𒀓','𒀔'=>'𒀔','𒀕'=>'𒀕','𒀖'=>'𒀖','𒀗'=>'𒀗','𒀘'=>'𒀘','𒀙'=>'𒀙','𒀚'=>'𒀚','𒀛'=>'𒀛','𒀜'=>'𒀜','𒀝'=>'𒀝','𒀞'=>'𒀞','𒀟'=>'𒀟','𒀠'=>'𒀠','𒀡'=>'𒀡','𒀢'=>'𒀢','𒀣'=>'𒀣','𒀤'=>'𒀤','𒀥'=>'𒀥','𒀦'=>'𒀦','𒀧'=>'𒀧','𒀨'=>'𒀨','𒀩'=>'𒀩','𒀪'=>'𒀪','𒀫'=>'𒀫','𒀬'=>'𒀬','𒀭'=>'𒀭','𒀮'=>'𒀮','𒀯'=>'𒀯','𒀰'=>'𒀰','𒀱'=>'𒀱','𒀲'=>'𒀲','𒀳'=>'𒀳','𒀴'=>'𒀴','𒀵'=>'𒀵','𒀶'=>'𒀶','𒀷'=>'𒀷','𒀸'=>'𒀸','𒀹'=>'𒀹','𒀺'=>'𒀺','𒀻'=>'𒀻','𒀼'=>'𒀼','𒀽'=>'𒀽','𒀾'=>'𒀾','𒀿'=>'𒀿','𒁀'=>'𒁀','𒁁'=>'𒁁','𒁂'=>'𒁂','𒁃'=>'𒁃','𒁄'=>'𒁄','𒁅'=>'𒁅','𒁆'=>'𒁆','𒁇'=>'𒁇','𒁈'=>'𒁈','𒁉'=>'𒁉','𒁊'=>'𒁊','𒁋'=>'𒁋','𒁌'=>'𒁌','𒁍'=>'𒁍','𒁎'=>'𒁎','𒁏'=>'𒁏','𒁐'=>'𒁐','𒁑'=>'𒁑','𒁒'=>'𒁒','𒁓'=>'𒁓','𒁔'=>'𒁔','𒁕'=>'𒁕','𒁖'=>'𒁖','𒁗'=>'𒁗','𒁘'=>'𒁘','𒁙'=>'𒁙','𒁚'=>'𒁚','𒁛'=>'𒁛','𒁜'=>'𒁜','𒁝'=>'𒁝','𒁞'=>'𒁞','𒁟'=>'𒁟','𒁠'=>'𒁠','𒁡'=>'𒁡','𒁢'=>'𒁢','𒁣'=>'𒁣','𒁤'=>'𒁤','𒁥'=>'𒁥','𒁦'=>'𒁦','𒁧'=>'𒁧','𒁨'=>'𒁨','𒁩'=>'𒁩','𒁪'=>'𒁪','𒁫'=>'𒁫','𒁬'=>'𒁬','𒁭'=>'𒁭','𒁮'=>'𒁮','𒁯'=>'𒁯','𒁰'=>'𒁰','𒁱'=>'𒁱','𒁲'=>'𒁲','𒁳'=>'𒁳','𒁴'=>'𒁴','𒁵'=>'𒁵','𒁶'=>'𒁶','𒁷'=>'𒁷','𒁸'=>'𒁸','𒁹'=>'𒁹','𒁺'=>'𒁺','𒁻'=>'𒁻','𒁼'=>'𒁼','𒁽'=>'𒁽','𒁾'=>'𒁾','𒁿'=>'𒁿','𒂀'=>'𒂀','𒂁'=>'𒂁','𒂂'=>'𒂂','𒂃'=>'𒂃','𒂄'=>'𒂄','𒂅'=>'𒂅','𒂆'=>'𒂆','𒂇'=>'𒂇','𒂈'=>'𒂈','𒂉'=>'𒂉','𒂊'=>'𒂊','𒂋'=>'𒂋','𒂌'=>'𒂌','𒂍'=>'𒂍','𒂎'=>'𒂎','𒂏'=>'𒂏','𒂐'=>'𒂐','𒂑'=>'𒂑','𒂒'=>'𒂒','𒂓'=>'𒂓','𒂔'=>'𒂔','𒂕'=>'𒂕','𒂖'=>'𒂖','𒂗'=>'𒂗','𒂘'=>'𒂘','𒂙'=>'𒂙','𒂚'=>'𒂚','𒂛'=>'𒂛','𒂜'=>'𒂜','𒂝'=>'𒂝','𒂞'=>'𒂞','𒂟'=>'𒂟','𒂠'=>'𒂠','𒂡'=>'𒂡','𒂢'=>'𒂢','𒂣'=>'𒂣','𒂤'=>'𒂤','𒂥'=>'𒂥','𒂦'=>'𒂦','𒂧'=>'𒂧','𒂨'=>'𒂨','𒂩'=>'𒂩','𒂪'=>'𒂪','𒂫'=>'𒂫','𒂬'=>'𒂬','𒂭'=>'𒂭','𒂮'=>'𒂮','𒂯'=>'𒂯','𒂰'=>'𒂰','𒂱'=>'𒂱','𒂲'=>'𒂲','𒂳'=>'𒂳','𒂴'=>'𒂴','𒂵'=>'𒂵','𒂶'=>'𒂶','𒂷'=>'𒂷','𒂸'=>'𒂸','𒂹'=>'𒂹','𒂺'=>'𒂺','𒂻'=>'𒂻','𒂼'=>'𒂼','𒂽'=>'𒂽','𒂾'=>'𒂾','𒂿'=>'𒂿','𒃀'=>'𒃀','𒃁'=>'𒃁','𒃂'=>'𒃂','𒃃'=>'𒃃','𒃄'=>'𒃄','𒃅'=>'𒃅','𒃆'=>'𒃆','𒃇'=>'𒃇','𒃈'=>'𒃈','𒃉'=>'𒃉','𒃊'=>'𒃊','𒃋'=>'𒃋','𒃌'=>'𒃌','𒃍'=>'𒃍','𒃎'=>'𒃎','𒃏'=>'𒃏','𒃐'=>'𒃐','𒃑'=>'𒃑','𒃒'=>'𒃒','𒃓'=>'𒃓','𒃔'=>'𒃔','𒃕'=>'𒃕','𒃖'=>'𒃖','𒃗'=>'𒃗','𒃘'=>'𒃘','𒃙'=>'𒃙','𒃚'=>'𒃚','𒃛'=>'𒃛','𒃜'=>'𒃜','𒃝'=>'𒃝','𒃞'=>'𒃞','𒃟'=>'𒃟','𒃠'=>'𒃠','𒃡'=>'𒃡','𒃢'=>'𒃢','𒃣'=>'𒃣','𒃤'=>'𒃤','𒃥'=>'𒃥','𒃦'=>'𒃦','𒃧'=>'𒃧','𒃨'=>'𒃨','𒃩'=>'𒃩','𒃪'=>'𒃪','𒃫'=>'𒃫','𒃬'=>'𒃬','𒃭'=>'𒃭','𒃮'=>'𒃮','𒃯'=>'𒃯','𒃰'=>'𒃰','𒃱'=>'𒃱','𒃲'=>'𒃲','𒃳'=>'𒃳','𒃴'=>'𒃴','𒃵'=>'𒃵','𒃶'=>'𒃶','𒃷'=>'𒃷','𒃸'=>'𒃸','𒃹'=>'𒃹','𒃺'=>'𒃺','𒃻'=>'𒃻','𒃼'=>'𒃼','𒃽'=>'𒃽','𒃾'=>'𒃾','𒃿'=>'𒃿','𒄀'=>'𒄀','𒄁'=>'𒄁','𒄂'=>'𒄂','𒄃'=>'𒄃','𒄄'=>'𒄄','𒄅'=>'𒄅','𒄆'=>'𒄆','𒄇'=>'𒄇','𒄈'=>'𒄈','𒄉'=>'𒄉','𒄊'=>'𒄊','𒄋'=>'𒄋','𒄌'=>'𒄌','𒄍'=>'𒄍','𒄎'=>'𒄎','𒄏'=>'𒄏','𒄐'=>'𒄐','𒄑'=>'𒄑','𒄒'=>'𒄒','𒄓'=>'𒄓','𒄔'=>'𒄔','𒄕'=>'𒄕','𒄖'=>'𒄖','𒄗'=>'𒄗','𒄘'=>'𒄘','𒄙'=>'𒄙','𒄚'=>'𒄚','𒄛'=>'𒄛','𒄜'=>'𒄜','𒄝'=>'𒄝','𒄞'=>'𒄞','𒄟'=>'𒄟','𒄠'=>'𒄠','𒄡'=>'𒄡','𒄢'=>'𒄢','𒄣'=>'𒄣','𒄤'=>'𒄤','𒄥'=>'𒄥','𒄦'=>'𒄦','𒄧'=>'𒄧','𒄨'=>'𒄨','𒄩'=>'𒄩','𒄪'=>'𒄪','𒄫'=>'𒄫','𒄬'=>'𒄬','𒄭'=>'𒄭','𒄮'=>'𒄮','𒄯'=>'𒄯','𒄰'=>'𒄰','𒄱'=>'𒄱','𒄲'=>'𒄲','𒄳'=>'𒄳','𒄴'=>'𒄴','𒄵'=>'𒄵','𒄶'=>'𒄶','𒄷'=>'𒄷','𒄸'=>'𒄸','𒄹'=>'𒄹','𒄺'=>'𒄺','𒄻'=>'𒄻','𒄼'=>'𒄼','𒄽'=>'𒄽','𒄾'=>'𒄾','𒄿'=>'𒄿','𒅀'=>'𒅀','𒅁'=>'𒅁','𒅂'=>'𒅂','𒅃'=>'𒅃','𒅄'=>'𒅄','𒅅'=>'𒅅','𒅆'=>'𒅆','𒅇'=>'𒅇','𒅈'=>'𒅈','𒅉'=>'𒅉','𒅊'=>'𒅊','𒅋'=>'𒅋','𒅌'=>'𒅌','𒅍'=>'𒅍','𒅎'=>'𒅎','𒅏'=>'𒅏','𒅐'=>'𒅐','𒅑'=>'𒅑','𒅒'=>'𒅒','𒅓'=>'𒅓','𒅔'=>'𒅔','𒅕'=>'𒅕','𒅖'=>'𒅖','𒅗'=>'𒅗','𒅘'=>'𒅘','𒅙'=>'𒅙','𒅚'=>'𒅚','𒅛'=>'𒅛','𒅜'=>'𒅜','𒅝'=>'𒅝','𒅞'=>'𒅞','𒅟'=>'𒅟','𒅠'=>'𒅠','𒅡'=>'𒅡','𒅢'=>'𒅢','𒅣'=>'𒅣','𒅤'=>'𒅤','𒅥'=>'𒅥','𒅦'=>'𒅦','𒅧'=>'𒅧','𒅨'=>'𒅨','𒅩'=>'𒅩','𒅪'=>'𒅪','𒅫'=>'𒅫','𒅬'=>'𒅬','𒅭'=>'𒅭','𒅮'=>'𒅮','𒅯'=>'𒅯','𒅰'=>'𒅰','𒅱'=>'𒅱','𒅲'=>'𒅲','𒅳'=>'𒅳','𒅴'=>'𒅴','𒅵'=>'𒅵','𒅶'=>'𒅶','𒅷'=>'𒅷','𒅸'=>'𒅸','𒅹'=>'𒅹','𒅺'=>'𒅺','𒅻'=>'𒅻','𒅼'=>'𒅼','𒅽'=>'𒅽','𒅾'=>'𒅾','𒅿'=>'𒅿','𒆀'=>'𒆀','𒆁'=>'𒆁','𒆂'=>'𒆂','𒆃'=>'𒆃','𒆄'=>'𒆄','𒆅'=>'𒆅','𒆆'=>'𒆆','𒆇'=>'𒆇','𒆈'=>'𒆈','𒆉'=>'𒆉','𒆊'=>'𒆊','𒆋'=>'𒆋','𒆌'=>'𒆌','𒆍'=>'𒆍','𒆎'=>'𒆎','𒆏'=>'𒆏','𒆐'=>'𒆐','𒆑'=>'𒆑','𒆒'=>'𒆒','𒆓'=>'𒆓','𒆔'=>'𒆔','𒆕'=>'𒆕','𒆖'=>'𒆖','𒆗'=>'𒆗','𒆘'=>'𒆘','𒆙'=>'𒆙','𒆚'=>'𒆚','𒆛'=>'𒆛','𒆜'=>'𒆜','𒆝'=>'𒆝','𒆞'=>'𒆞','𒆟'=>'𒆟','𒆠'=>'𒆠','𒆡'=>'𒆡','𒆢'=>'𒆢','𒆣'=>'𒆣','𒆤'=>'𒆤','𒆥'=>'𒆥','𒆦'=>'𒆦','𒆧'=>'𒆧','𒆨'=>'𒆨','𒆩'=>'𒆩','𒆪'=>'𒆪','𒆫'=>'𒆫','𒆬'=>'𒆬','𒆭'=>'𒆭','𒆮'=>'𒆮','𒆯'=>'𒆯','𒆰'=>'𒆰','𒆱'=>'𒆱','𒆲'=>'𒆲','𒆳'=>'𒆳','𒆴'=>'𒆴','𒆵'=>'𒆵','𒆶'=>'𒆶','𒆷'=>'𒆷','𒆸'=>'𒆸','𒆹'=>'𒆹','𒆺'=>'𒆺','𒆻'=>'𒆻','𒆼'=>'𒆼','𒆽'=>'𒆽','𒆾'=>'𒆾','𒆿'=>'𒆿','𒇀'=>'𒇀','𒇁'=>'𒇁','𒇂'=>'𒇂','𒇃'=>'𒇃','𒇄'=>'𒇄','𒇅'=>'𒇅','𒇆'=>'𒇆','𒇇'=>'𒇇','𒇈'=>'𒇈','𒇉'=>'𒇉','𒇊'=>'𒇊','𒇋'=>'𒇋','𒇌'=>'𒇌','𒇍'=>'𒇍','𒇎'=>'𒇎','𒇏'=>'𒇏','𒇐'=>'𒇐','𒇑'=>'𒇑','𒇒'=>'𒇒','𒇓'=>'𒇓','𒇔'=>'𒇔','𒇕'=>'𒇕','𒇖'=>'𒇖','𒇗'=>'𒇗','𒇘'=>'𒇘','𒇙'=>'𒇙','𒇚'=>'𒇚','𒇛'=>'𒇛','𒇜'=>'𒇜','𒇝'=>'𒇝','𒇞'=>'𒇞','𒇟'=>'𒇟','𒇠'=>'𒇠','𒇡'=>'𒇡','𒇢'=>'𒇢','𒇣'=>'𒇣','𒇤'=>'𒇤','𒇥'=>'𒇥','𒇦'=>'𒇦','𒇧'=>'𒇧','𒇨'=>'𒇨','𒇩'=>'𒇩','𒇪'=>'𒇪','𒇫'=>'𒇫','𒇬'=>'𒇬','𒇭'=>'𒇭','𒇮'=>'𒇮','𒇯'=>'𒇯','𒇰'=>'𒇰','𒇱'=>'𒇱','𒇲'=>'𒇲','𒇳'=>'𒇳','𒇴'=>'𒇴','𒇵'=>'𒇵','𒇶'=>'𒇶','𒇷'=>'𒇷','𒇸'=>'𒇸','𒇹'=>'𒇹','𒇺'=>'𒇺','𒇻'=>'𒇻','𒇼'=>'𒇼','𒇽'=>'𒇽','𒇾'=>'𒇾','𒇿'=>'𒇿','𒈀'=>'𒈀','𒈁'=>'𒈁','𒈂'=>'𒈂','𒈃'=>'𒈃','𒈄'=>'𒈄','𒈅'=>'𒈅','𒈆'=>'𒈆','𒈇'=>'𒈇','𒈈'=>'𒈈','𒈉'=>'𒈉','𒈊'=>'𒈊','𒈋'=>'𒈋','𒈌'=>'𒈌','𒈍'=>'𒈍','𒈎'=>'𒈎','𒈏'=>'𒈏','𒈐'=>'𒈐','𒈑'=>'𒈑','𒈒'=>'𒈒','𒈓'=>'𒈓','𒈔'=>'𒈔','𒈕'=>'𒈕','𒈖'=>'𒈖','𒈗'=>'𒈗','𒈘'=>'𒈘','𒈙'=>'𒈙','𒈚'=>'𒈚','𒈛'=>'𒈛','𒈜'=>'𒈜','𒈝'=>'𒈝','𒈞'=>'𒈞','𒈟'=>'𒈟','𒈠'=>'𒈠','𒈡'=>'𒈡','𒈢'=>'𒈢','𒈣'=>'𒈣','𒈤'=>'𒈤','𒈥'=>'𒈥','𒈦'=>'𒈦','𒈧'=>'𒈧','𒈨'=>'𒈨','𒈩'=>'𒈩','𒈪'=>'𒈪','𒈫'=>'𒈫','𒈬'=>'𒈬','𒈭'=>'𒈭','𒈮'=>'𒈮','𒈯'=>'𒈯','𒈰'=>'𒈰','𒈱'=>'𒈱','𒈲'=>'𒈲','𒈳'=>'𒈳','𒈴'=>'𒈴','𒈵'=>'𒈵','𒈶'=>'𒈶','𒈷'=>'𒈷','𒈸'=>'𒈸','𒈹'=>'𒈹','𒈺'=>'𒈺','𒈻'=>'𒈻','𒈼'=>'𒈼','𒈽'=>'𒈽','𒈾'=>'𒈾','𒈿'=>'𒈿','𒉀'=>'𒉀','𒉁'=>'𒉁','𒉂'=>'𒉂','𒉃'=>'𒉃','𒉄'=>'𒉄','𒉅'=>'𒉅','𒉆'=>'𒉆','𒉇'=>'𒉇','𒉈'=>'𒉈','𒉉'=>'𒉉','𒉊'=>'𒉊','𒉋'=>'𒉋','𒉌'=>'𒉌','𒉍'=>'𒉍','𒉎'=>'𒉎','𒉏'=>'𒉏','𒉐'=>'𒉐','𒉑'=>'𒉑','𒉒'=>'𒉒','𒉓'=>'𒉓','𒉔'=>'𒉔','𒉕'=>'𒉕','𒉖'=>'𒉖','𒉗'=>'𒉗','𒉘'=>'𒉘','𒉙'=>'𒉙','𒉚'=>'𒉚','𒉛'=>'𒉛','𒉜'=>'𒉜','𒉝'=>'𒉝','𒉞'=>'𒉞','𒉟'=>'𒉟','𒉠'=>'𒉠','𒉡'=>'𒉡','𒉢'=>'𒉢','𒉣'=>'𒉣','𒉤'=>'𒉤','𒉥'=>'𒉥','𒉦'=>'𒉦','𒉧'=>'𒉧','𒉨'=>'𒉨','𒉩'=>'𒉩','𒉪'=>'𒉪','𒉫'=>'𒉫','𒉬'=>'𒉬','𒉭'=>'𒉭','𒉮'=>'𒉮','𒉯'=>'𒉯','𒉰'=>'𒉰','𒉱'=>'𒉱','𒉲'=>'𒉲','𒉳'=>'𒉳','𒉴'=>'𒉴','𒉵'=>'𒉵','𒉶'=>'𒉶','𒉷'=>'𒉷','𒉸'=>'𒉸','𒉹'=>'𒉹','𒉺'=>'𒉺','𒉻'=>'𒉻','𒉼'=>'𒉼','𒉽'=>'𒉽','𒉾'=>'𒉾','𒉿'=>'𒉿','𒊀'=>'𒊀','𒊁'=>'𒊁','𒊂'=>'𒊂','𒊃'=>'𒊃','𒊄'=>'𒊄','𒊅'=>'𒊅','𒊆'=>'𒊆','𒊇'=>'𒊇','𒊈'=>'𒊈','𒊉'=>'𒊉','𒊊'=>'𒊊','𒊋'=>'𒊋','𒊌'=>'𒊌','𒊍'=>'𒊍','𒊎'=>'𒊎','𒊏'=>'𒊏','𒊐'=>'𒊐','𒊑'=>'𒊑','𒊒'=>'𒊒','𒊓'=>'𒊓','𒊔'=>'𒊔','𒊕'=>'𒊕','𒊖'=>'𒊖','𒊗'=>'𒊗','𒊘'=>'𒊘','𒊙'=>'𒊙','𒊚'=>'𒊚','𒊛'=>'𒊛','𒊜'=>'𒊜','𒊝'=>'𒊝','𒊞'=>'𒊞','𒊟'=>'𒊟','𒊠'=>'𒊠','𒊡'=>'𒊡','𒊢'=>'𒊢','𒊣'=>'𒊣','𒊤'=>'𒊤','𒊥'=>'𒊥','𒊦'=>'𒊦','𒊧'=>'𒊧','𒊨'=>'𒊨','𒊩'=>'𒊩','𒊪'=>'𒊪','𒊫'=>'𒊫','𒊬'=>'𒊬','𒊭'=>'𒊭','𒊮'=>'𒊮','𒊯'=>'𒊯','𒊰'=>'𒊰','𒊱'=>'𒊱','𒊲'=>'𒊲','𒊳'=>'𒊳','𒊴'=>'𒊴','𒊵'=>'𒊵','𒊶'=>'𒊶','𒊷'=>'𒊷','𒊸'=>'𒊸','𒊹'=>'𒊹','𒊺'=>'𒊺','𒊻'=>'𒊻','𒊼'=>'𒊼','𒊽'=>'𒊽','𒊾'=>'𒊾','𒊿'=>'𒊿','𒋀'=>'𒋀','𒋁'=>'𒋁','𒋂'=>'𒋂','𒋃'=>'𒋃','𒋄'=>'𒋄','𒋅'=>'𒋅','𒋆'=>'𒋆','𒋇'=>'𒋇','𒋈'=>'𒋈','𒋉'=>'𒋉','𒋊'=>'𒋊','𒋋'=>'𒋋','𒋌'=>'𒋌','𒋍'=>'𒋍','𒋎'=>'𒋎','𒋏'=>'𒋏','𒋐'=>'𒋐','𒋑'=>'𒋑','𒋒'=>'𒋒','𒋓'=>'𒋓','𒋔'=>'𒋔','𒋕'=>'𒋕','𒋖'=>'𒋖','𒋗'=>'𒋗','𒋘'=>'𒋘','𒋙'=>'𒋙','𒋚'=>'𒋚','𒋛'=>'𒋛','𒋜'=>'𒋜','𒋝'=>'𒋝','𒋞'=>'𒋞','𒋟'=>'𒋟','𒋠'=>'𒋠','𒋡'=>'𒋡','𒋢'=>'𒋢','𒋣'=>'𒋣','𒋤'=>'𒋤','𒋥'=>'𒋥','𒋦'=>'𒋦','𒋧'=>'𒋧','𒋨'=>'𒋨','𒋩'=>'𒋩','𒋪'=>'𒋪','𒋫'=>'𒋫','𒋬'=>'𒋬','𒋭'=>'𒋭','𒋮'=>'𒋮','𒋯'=>'𒋯','𒋰'=>'𒋰','𒋱'=>'𒋱','𒋲'=>'𒋲','𒋳'=>'𒋳','𒋴'=>'𒋴','𒋵'=>'𒋵','𒋶'=>'𒋶','𒋷'=>'𒋷','𒋸'=>'𒋸','𒋹'=>'𒋹','𒋺'=>'𒋺','𒋻'=>'𒋻','𒋼'=>'𒋼','𒋽'=>'𒋽','𒋾'=>'𒋾','𒋿'=>'𒋿','𒌀'=>'𒌀','𒌁'=>'𒌁','𒌂'=>'𒌂','𒌃'=>'𒌃','𒌄'=>'𒌄','𒌅'=>'𒌅','𒌆'=>'𒌆','𒌇'=>'𒌇','𒌈'=>'𒌈','𒌉'=>'𒌉','𒌊'=>'𒌊','𒌋'=>'𒌋','𒌌'=>'𒌌','𒌍'=>'𒌍','𒌎'=>'𒌎','𒌏'=>'𒌏','𒌐'=>'𒌐','𒌑'=>'𒌑','𒌒'=>'𒌒','𒌓'=>'𒌓','𒌔'=>'𒌔','𒌕'=>'𒌕','𒌖'=>'𒌖','𒌗'=>'𒌗','𒌘'=>'𒌘','𒌙'=>'𒌙','𒌚'=>'𒌚','𒌛'=>'𒌛','𒌜'=>'𒌜','𒌝'=>'𒌝','𒌞'=>'𒌞','𒌟'=>'𒌟','𒌠'=>'𒌠','𒌡'=>'𒌡','𒌢'=>'𒌢','𒌣'=>'𒌣','𒌤'=>'𒌤','𒌥'=>'𒌥','𒌦'=>'𒌦','𒌧'=>'𒌧','𒌨'=>'𒌨','𒌩'=>'𒌩','𒌪'=>'𒌪','𒌫'=>'𒌫','𒌬'=>'𒌬','𒌭'=>'𒌭','𒌮'=>'𒌮','𒌯'=>'𒌯','𒌰'=>'𒌰','𒌱'=>'𒌱','𒌲'=>'𒌲','𒌳'=>'𒌳','𒌴'=>'𒌴','𒌵'=>'𒌵','𒌶'=>'𒌶','𒌷'=>'𒌷','𒌸'=>'𒌸','𒌹'=>'𒌹','𒌺'=>'𒌺','𒌻'=>'𒌻','𒌼'=>'𒌼','𒌽'=>'𒌽','𒌾'=>'𒌾','𒌿'=>'𒌿','𒍀'=>'𒍀','𒍁'=>'𒍁','𒍂'=>'𒍂','𒍃'=>'𒍃','𒍄'=>'𒍄','𒍅'=>'𒍅','𒍆'=>'𒍆','𒍇'=>'𒍇','𒍈'=>'𒍈','𒍉'=>'𒍉','𒍊'=>'𒍊','𒍋'=>'𒍋','𒍌'=>'𒍌','𒍍'=>'𒍍','𒍎'=>'𒍎','𒍏'=>'𒍏','𒍐'=>'𒍐','𒍑'=>'𒍑','𒍒'=>'𒍒','𒍓'=>'𒍓','𒍔'=>'𒍔','𒍕'=>'𒍕','𒍖'=>'𒍖','𒍗'=>'𒍗','𒍘'=>'𒍘','𒍙'=>'𒍙','𒍚'=>'𒍚','𒍛'=>'𒍛','𒍜'=>'𒍜','𒍝'=>'𒍝','𒍞'=>'𒍞','𒍟'=>'𒍟','𒍠'=>'𒍠','𒍡'=>'𒍡','𒍢'=>'𒍢','𒍣'=>'𒍣','𒍤'=>'𒍤','𒍥'=>'𒍥','𒍦'=>'𒍦','𒍧'=>'𒍧','𒍨'=>'𒍨','𒍩'=>'𒍩','𒍪'=>'𒍪','𒍫'=>'𒍫','𒍬'=>'𒍬','𒍭'=>'𒍭','𒍮'=>'𒍮','𒐀'=>'2','𒐁'=>'3','𒐂'=>'4','𒐃'=>'5','𒐄'=>'6','𒐅'=>'7','𒐆'=>'8','𒐇'=>'9','𒐈'=>'3','𒐉'=>'4','𒐊'=>'5','𒐋'=>'6','𒐌'=>'7','𒐍'=>'8','𒐎'=>'9','𒐏'=>'4','𒐐'=>'5','𒐑'=>'6','𒐒'=>'7','𒐓'=>'8','𒐔'=>'9','𒐕'=>'1','𒐖'=>'2','𒐗'=>'3','𒐘'=>'4','𒐙'=>'5','𒐚'=>'6','𒐛'=>'7','𒐜'=>'8','𒐝'=>'9','𒐞'=>'1','𒐟'=>'2','𒐠'=>'3','𒐡'=>'4','𒐢'=>'5','𒐣'=>'2','𒐤'=>'3','𒐥'=>'3','𒐦'=>'4','𒐧'=>'5','𒐨'=>'6','𒐩'=>'7','𒐪'=>'8','𒐫'=>'9','𒐬'=>'1','𒐭'=>'2','𒐮'=>'3','𒐯'=>'3','𒐰'=>'4','𒐱'=>'5','𒐲'=>'𒐲','𒐳'=>'𒐳','𒐴'=>'1','𒐵'=>'2','𒐶'=>'3','𒐷'=>'3','𒐸'=>'4','𒐹'=>'5','𒐺'=>'3','𒐻'=>'3','𒐼'=>'4','𒐽'=>'4','𒐾'=>'4','𒐿'=>'4','𒑀'=>'6','𒑁'=>'7','𒑂'=>'7','𒑃'=>'7','𒑄'=>'8','𒑅'=>'8','𒑆'=>'9','𒑇'=>'9','𒑈'=>'9','𒑉'=>'9','𒑊'=>'2','𒑋'=>'3','𒑌'=>'4','𒑍'=>'5','𒑎'=>'6','𒑏'=>'1','𒑐'=>'2','𒑑'=>'3','𒑒'=>'4','𒑓'=>'4','𒑔'=>'5','𒑕'=>'5','𒑖'=>'𒑖','𒑗'=>'𒑗','𒑘'=>'1','𒑙'=>'2','𒑚'=>'1/3','𒑛'=>'2/3','𒑜'=>'5/6','𒑝'=>'1/3','𒑞'=>'2/3','𒑟'=>'1/8','𒑠'=>'1/4','𒑡'=>'1/6','𒑢'=>'1/4'); diff --git a/phpBB/includes/utf/data/search_indexer_4.php b/phpBB/includes/utf/data/search_indexer_4.php index 51acbff1c2..6697501a89 100644 --- a/phpBB/includes/utf/data/search_indexer_4.php +++ b/phpBB/includes/utf/data/search_indexer_4.php @@ -1 +1 @@ -<?php return array('⁰'=>'0','ⁱ'=>'ⁱ','⁴'=>'4','⁵'=>'5','⁶'=>'6','⁷'=>'7','⁸'=>'8','⁹'=>'9','ⁿ'=>'ⁿ','₀'=>'0','₁'=>'1','₂'=>'2','₃'=>'3','₄'=>'4','₅'=>'5','₆'=>'6','₇'=>'7','₈'=>'8','₉'=>'9','ₐ'=>'ₐ','ₑ'=>'ₑ','ₒ'=>'ₒ','ₓ'=>'ₓ','ₔ'=>'ₔ','⃐'=>'⃐','⃑'=>'⃑','⃒'=>'⃒','⃓'=>'⃓','⃔'=>'⃔','⃕'=>'⃕','⃖'=>'⃖','⃗'=>'⃗','⃘'=>'⃘','⃙'=>'⃙','⃚'=>'⃚','⃛'=>'⃛','⃜'=>'⃜','⃝'=>'⃝','⃞'=>'⃞','⃟'=>'⃟','⃠'=>'⃠','⃡'=>'⃡','⃢'=>'⃢','⃣'=>'⃣','⃤'=>'⃤','⃥'=>'⃥','⃦'=>'⃦','⃧'=>'⃧','⃨'=>'⃨','⃩'=>'⃩','⃪'=>'⃪','⃫'=>'⃫','⃬'=>'⃬','⃭'=>'⃭','⃮'=>'⃮','⃯'=>'⃯','ℂ'=>'ℂ','ℇ'=>'ℇ','ℊ'=>'ℊ','ℋ'=>'ℋ','ℌ'=>'ℌ','ℍ'=>'ℍ','ℎ'=>'ℎ','ℏ'=>'ℏ','ℐ'=>'ℐ','ℑ'=>'ℑ','ℒ'=>'ℒ','ℓ'=>'ℓ','ℕ'=>'ℕ','ℙ'=>'ℙ','ℚ'=>'ℚ','ℛ'=>'ℛ','ℜ'=>'ℜ','ℝ'=>'ℝ','ℤ'=>'ℤ','Ω'=>'ω','ℨ'=>'ℨ','K'=>'k','Å'=>'å','ℬ'=>'ℬ','ℭ'=>'ℭ','ℯ'=>'ℯ','ℰ'=>'ℰ','ℱ'=>'ℱ','Ⅎ'=>'ⅎ','ℳ'=>'ℳ','ℴ'=>'ℴ','ℵ'=>'ℵ','ℶ'=>'ℶ','ℷ'=>'ℷ','ℸ'=>'ℸ','ℹ'=>'ℹ','ℼ'=>'ℼ','ℽ'=>'ℽ','ℾ'=>'ℾ','ℿ'=>'ℿ','ⅅ'=>'ⅅ','ⅆ'=>'ⅆ','ⅇ'=>'ⅇ','ⅈ'=>'ⅈ','ⅉ'=>'ⅉ','ⅎ'=>'ⅎ','⅓'=>'1/3','⅔'=>'2/3','⅕'=>'1/5','⅖'=>'2/5','⅗'=>'3/5','⅘'=>'4/5','⅙'=>'1/6','⅚'=>'5/6','⅛'=>'1/8','⅜'=>'3/8','⅝'=>'5/8','⅞'=>'7/8','⅟'=>'1','Ⅰ'=>'1','Ⅱ'=>'2','Ⅲ'=>'3','Ⅳ'=>'4','Ⅴ'=>'5','Ⅵ'=>'6','Ⅶ'=>'7','Ⅷ'=>'8','Ⅸ'=>'9','Ⅹ'=>'10','Ⅺ'=>'11','Ⅻ'=>'12','Ⅼ'=>'50','Ⅽ'=>'100','Ⅾ'=>'500','Ⅿ'=>'1000','ⅰ'=>'1','ⅱ'=>'2','ⅲ'=>'3','ⅳ'=>'4','ⅴ'=>'5','ⅵ'=>'6','ⅶ'=>'7','ⅷ'=>'8','ⅸ'=>'9','ⅹ'=>'10','ⅺ'=>'11','ⅻ'=>'12','ⅼ'=>'50','ⅽ'=>'100','ⅾ'=>'500','ⅿ'=>'1000','ↀ'=>'1000','ↁ'=>'5000','ↂ'=>'10000','Ↄ'=>'ↄ','ↄ'=>'ↄ','①'=>'1','②'=>'2','③'=>'3','④'=>'4','⑤'=>'5','⑥'=>'6','⑦'=>'7','⑧'=>'8','⑨'=>'9','⑩'=>'10','⑪'=>'11','⑫'=>'12','⑬'=>'13','⑭'=>'14','⑮'=>'15','⑯'=>'16','⑰'=>'17','⑱'=>'18','⑲'=>'19','⑳'=>'20','⑴'=>'1','⑵'=>'2','⑶'=>'3','⑷'=>'4','⑸'=>'5','⑹'=>'6','⑺'=>'7','⑻'=>'8','⑼'=>'9','⑽'=>'10','⑾'=>'11','⑿'=>'12','⒀'=>'13','⒁'=>'14','⒂'=>'15','⒃'=>'16','⒄'=>'17','⒅'=>'18','⒆'=>'19','⒇'=>'20','⒈'=>'1','⒉'=>'2','⒊'=>'3','⒋'=>'4','⒌'=>'5','⒍'=>'6','⒎'=>'7','⒏'=>'8','⒐'=>'9','⒑'=>'10','⒒'=>'11','⒓'=>'12','⒔'=>'13','⒕'=>'14','⒖'=>'15','⒗'=>'16','⒘'=>'17','⒙'=>'18','⒚'=>'19','⒛'=>'20','⓪'=>'0','⓫'=>'11','⓬'=>'12','⓭'=>'13','⓮'=>'14','⓯'=>'15','⓰'=>'16','⓱'=>'17','⓲'=>'18','⓳'=>'19','⓴'=>'20','⓵'=>'1','⓶'=>'2','⓷'=>'3','⓸'=>'4','⓹'=>'5','⓺'=>'6','⓻'=>'7','⓼'=>'8','⓽'=>'9','⓾'=>'10','⓿'=>'0','❶'=>'1','❷'=>'2','❸'=>'3','❹'=>'4','❺'=>'5','❻'=>'6','❼'=>'7','❽'=>'8','❾'=>'9','❿'=>'10','➀'=>'1','➁'=>'2','➂'=>'3','➃'=>'4','➄'=>'5','➅'=>'6','➆'=>'7','➇'=>'8','➈'=>'9','➉'=>'10','➊'=>'1','➋'=>'2','➌'=>'3','➍'=>'4','➎'=>'5','➏'=>'6','➐'=>'7','➑'=>'8','➒'=>'9','➓'=>'10');
\ No newline at end of file +<?php return array('⁰'=>'0','ⁱ'=>'ⁱ','⁴'=>'4','⁵'=>'5','⁶'=>'6','⁷'=>'7','⁸'=>'8','⁹'=>'9','ⁿ'=>'ⁿ','₀'=>'0','₁'=>'1','₂'=>'2','₃'=>'3','₄'=>'4','₅'=>'5','₆'=>'6','₇'=>'7','₈'=>'8','₉'=>'9','ₐ'=>'ₐ','ₑ'=>'ₑ','ₒ'=>'ₒ','ₓ'=>'ₓ','ₔ'=>'ₔ','⃐'=>'⃐','⃑'=>'⃑','⃒'=>'⃒','⃓'=>'⃓','⃔'=>'⃔','⃕'=>'⃕','⃖'=>'⃖','⃗'=>'⃗','⃘'=>'⃘','⃙'=>'⃙','⃚'=>'⃚','⃛'=>'⃛','⃜'=>'⃜','⃝'=>'⃝','⃞'=>'⃞','⃟'=>'⃟','⃠'=>'⃠','⃡'=>'⃡','⃢'=>'⃢','⃣'=>'⃣','⃤'=>'⃤','⃥'=>'⃥','⃦'=>'⃦','⃧'=>'⃧','⃨'=>'⃨','⃩'=>'⃩','⃪'=>'⃪','⃫'=>'⃫','⃬'=>'⃬','⃭'=>'⃭','⃮'=>'⃮','⃯'=>'⃯','ℂ'=>'ℂ','ℇ'=>'ℇ','ℊ'=>'ℊ','ℋ'=>'ℋ','ℌ'=>'ℌ','ℍ'=>'ℍ','ℎ'=>'ℎ','ℏ'=>'ℏ','ℐ'=>'ℐ','ℑ'=>'ℑ','ℒ'=>'ℒ','ℓ'=>'ℓ','ℕ'=>'ℕ','ℙ'=>'ℙ','ℚ'=>'ℚ','ℛ'=>'ℛ','ℜ'=>'ℜ','ℝ'=>'ℝ','ℤ'=>'ℤ','Ω'=>'ω','ℨ'=>'ℨ','K'=>'k','Å'=>'å','ℬ'=>'ℬ','ℭ'=>'ℭ','ℯ'=>'ℯ','ℰ'=>'ℰ','ℱ'=>'ℱ','Ⅎ'=>'ⅎ','ℳ'=>'ℳ','ℴ'=>'ℴ','ℵ'=>'ℵ','ℶ'=>'ℶ','ℷ'=>'ℷ','ℸ'=>'ℸ','ℹ'=>'ℹ','ℼ'=>'ℼ','ℽ'=>'ℽ','ℾ'=>'ℾ','ℿ'=>'ℿ','ⅅ'=>'ⅅ','ⅆ'=>'ⅆ','ⅇ'=>'ⅇ','ⅈ'=>'ⅈ','ⅉ'=>'ⅉ','ⅎ'=>'ⅎ','⅓'=>'1/3','⅔'=>'2/3','⅕'=>'1/5','⅖'=>'2/5','⅗'=>'3/5','⅘'=>'4/5','⅙'=>'1/6','⅚'=>'5/6','⅛'=>'1/8','⅜'=>'3/8','⅝'=>'5/8','⅞'=>'7/8','⅟'=>'1','Ⅰ'=>'1','Ⅱ'=>'2','Ⅲ'=>'3','Ⅳ'=>'4','Ⅴ'=>'5','Ⅵ'=>'6','Ⅶ'=>'7','Ⅷ'=>'8','Ⅸ'=>'9','Ⅹ'=>'10','Ⅺ'=>'11','Ⅻ'=>'12','Ⅼ'=>'50','Ⅽ'=>'100','Ⅾ'=>'500','Ⅿ'=>'1000','ⅰ'=>'1','ⅱ'=>'2','ⅲ'=>'3','ⅳ'=>'4','ⅴ'=>'5','ⅵ'=>'6','ⅶ'=>'7','ⅷ'=>'8','ⅸ'=>'9','ⅹ'=>'10','ⅺ'=>'11','ⅻ'=>'12','ⅼ'=>'50','ⅽ'=>'100','ⅾ'=>'500','ⅿ'=>'1000','ↀ'=>'1000','ↁ'=>'5000','ↂ'=>'10000','Ↄ'=>'ↄ','ↄ'=>'ↄ','①'=>'1','②'=>'2','③'=>'3','④'=>'4','⑤'=>'5','⑥'=>'6','⑦'=>'7','⑧'=>'8','⑨'=>'9','⑩'=>'10','⑪'=>'11','⑫'=>'12','⑬'=>'13','⑭'=>'14','⑮'=>'15','⑯'=>'16','⑰'=>'17','⑱'=>'18','⑲'=>'19','⑳'=>'20','⑴'=>'1','⑵'=>'2','⑶'=>'3','⑷'=>'4','⑸'=>'5','⑹'=>'6','⑺'=>'7','⑻'=>'8','⑼'=>'9','⑽'=>'10','⑾'=>'11','⑿'=>'12','⒀'=>'13','⒁'=>'14','⒂'=>'15','⒃'=>'16','⒄'=>'17','⒅'=>'18','⒆'=>'19','⒇'=>'20','⒈'=>'1','⒉'=>'2','⒊'=>'3','⒋'=>'4','⒌'=>'5','⒍'=>'6','⒎'=>'7','⒏'=>'8','⒐'=>'9','⒑'=>'10','⒒'=>'11','⒓'=>'12','⒔'=>'13','⒕'=>'14','⒖'=>'15','⒗'=>'16','⒘'=>'17','⒙'=>'18','⒚'=>'19','⒛'=>'20','⓪'=>'0','⓫'=>'11','⓬'=>'12','⓭'=>'13','⓮'=>'14','⓯'=>'15','⓰'=>'16','⓱'=>'17','⓲'=>'18','⓳'=>'19','⓴'=>'20','⓵'=>'1','⓶'=>'2','⓷'=>'3','⓸'=>'4','⓹'=>'5','⓺'=>'6','⓻'=>'7','⓼'=>'8','⓽'=>'9','⓾'=>'10','⓿'=>'0','❶'=>'1','❷'=>'2','❸'=>'3','❹'=>'4','❺'=>'5','❻'=>'6','❼'=>'7','❽'=>'8','❾'=>'9','❿'=>'10','➀'=>'1','➁'=>'2','➂'=>'3','➃'=>'4','➄'=>'5','➅'=>'6','➆'=>'7','➇'=>'8','➈'=>'9','➉'=>'10','➊'=>'1','➋'=>'2','➌'=>'3','➍'=>'4','➎'=>'5','➏'=>'6','➐'=>'7','➑'=>'8','➒'=>'9','➓'=>'10'); diff --git a/phpBB/includes/utf/data/search_indexer_448.php b/phpBB/includes/utf/data/search_indexer_448.php index 32ac28a549..6cbf6643e1 100644 --- a/phpBB/includes/utf/data/search_indexer_448.php +++ b/phpBB/includes/utf/data/search_indexer_448.php @@ -1 +1 @@ -<?php return array('󠄀'=>'󠄀','󠄁'=>'󠄁','󠄂'=>'󠄂','󠄃'=>'󠄃','󠄄'=>'󠄄','󠄅'=>'󠄅','󠄆'=>'󠄆','󠄇'=>'󠄇','󠄈'=>'󠄈','󠄉'=>'󠄉','󠄊'=>'󠄊','󠄋'=>'󠄋','󠄌'=>'󠄌','󠄍'=>'󠄍','󠄎'=>'󠄎','󠄏'=>'󠄏','󠄐'=>'󠄐','󠄑'=>'󠄑','󠄒'=>'󠄒','󠄓'=>'󠄓','󠄔'=>'󠄔','󠄕'=>'󠄕','󠄖'=>'󠄖','󠄗'=>'󠄗','󠄘'=>'󠄘','󠄙'=>'󠄙','󠄚'=>'󠄚','󠄛'=>'󠄛','󠄜'=>'󠄜','󠄝'=>'󠄝','󠄞'=>'󠄞','󠄟'=>'󠄟','󠄠'=>'󠄠','󠄡'=>'󠄡','󠄢'=>'󠄢','󠄣'=>'󠄣','󠄤'=>'󠄤','󠄥'=>'󠄥','󠄦'=>'󠄦','󠄧'=>'󠄧','󠄨'=>'󠄨','󠄩'=>'󠄩','󠄪'=>'󠄪','󠄫'=>'󠄫','󠄬'=>'󠄬','󠄭'=>'󠄭','󠄮'=>'󠄮','󠄯'=>'󠄯','󠄰'=>'󠄰','󠄱'=>'󠄱','󠄲'=>'󠄲','󠄳'=>'󠄳','󠄴'=>'󠄴','󠄵'=>'󠄵','󠄶'=>'󠄶','󠄷'=>'󠄷','󠄸'=>'󠄸','󠄹'=>'󠄹','󠄺'=>'󠄺','󠄻'=>'󠄻','󠄼'=>'󠄼','󠄽'=>'󠄽','󠄾'=>'󠄾','󠄿'=>'󠄿','󠅀'=>'󠅀','󠅁'=>'󠅁','󠅂'=>'󠅂','󠅃'=>'󠅃','󠅄'=>'󠅄','󠅅'=>'󠅅','󠅆'=>'󠅆','󠅇'=>'󠅇','󠅈'=>'󠅈','󠅉'=>'󠅉','󠅊'=>'󠅊','󠅋'=>'󠅋','󠅌'=>'󠅌','󠅍'=>'󠅍','󠅎'=>'󠅎','󠅏'=>'󠅏','󠅐'=>'󠅐','󠅑'=>'󠅑','󠅒'=>'󠅒','󠅓'=>'󠅓','󠅔'=>'󠅔','󠅕'=>'󠅕','󠅖'=>'󠅖','󠅗'=>'󠅗','󠅘'=>'󠅘','󠅙'=>'󠅙','󠅚'=>'󠅚','󠅛'=>'󠅛','󠅜'=>'󠅜','󠅝'=>'󠅝','󠅞'=>'󠅞','󠅟'=>'󠅟','󠅠'=>'󠅠','󠅡'=>'󠅡','󠅢'=>'󠅢','󠅣'=>'󠅣','󠅤'=>'󠅤','󠅥'=>'󠅥','󠅦'=>'󠅦','󠅧'=>'󠅧','󠅨'=>'󠅨','󠅩'=>'󠅩','󠅪'=>'󠅪','󠅫'=>'󠅫','󠅬'=>'󠅬','󠅭'=>'󠅭','󠅮'=>'󠅮','󠅯'=>'󠅯','󠅰'=>'󠅰','󠅱'=>'󠅱','󠅲'=>'󠅲','󠅳'=>'󠅳','󠅴'=>'󠅴','󠅵'=>'󠅵','󠅶'=>'󠅶','󠅷'=>'󠅷','󠅸'=>'󠅸','󠅹'=>'󠅹','󠅺'=>'󠅺','󠅻'=>'󠅻','󠅼'=>'󠅼','󠅽'=>'󠅽','󠅾'=>'󠅾','󠅿'=>'󠅿','󠆀'=>'󠆀','󠆁'=>'󠆁','󠆂'=>'󠆂','󠆃'=>'󠆃','󠆄'=>'󠆄','󠆅'=>'󠆅','󠆆'=>'󠆆','󠆇'=>'󠆇','󠆈'=>'󠆈','󠆉'=>'󠆉','󠆊'=>'󠆊','󠆋'=>'󠆋','󠆌'=>'󠆌','󠆍'=>'󠆍','󠆎'=>'󠆎','󠆏'=>'󠆏','󠆐'=>'󠆐','󠆑'=>'󠆑','󠆒'=>'󠆒','󠆓'=>'󠆓','󠆔'=>'󠆔','󠆕'=>'󠆕','󠆖'=>'󠆖','󠆗'=>'󠆗','󠆘'=>'󠆘','󠆙'=>'󠆙','󠆚'=>'󠆚','󠆛'=>'󠆛','󠆜'=>'󠆜','󠆝'=>'󠆝','󠆞'=>'󠆞','󠆟'=>'󠆟','󠆠'=>'󠆠','󠆡'=>'󠆡','󠆢'=>'󠆢','󠆣'=>'󠆣','󠆤'=>'󠆤','󠆥'=>'󠆥','󠆦'=>'󠆦','󠆧'=>'󠆧','󠆨'=>'󠆨','󠆩'=>'󠆩','󠆪'=>'󠆪','󠆫'=>'󠆫','󠆬'=>'󠆬','󠆭'=>'󠆭','󠆮'=>'󠆮','󠆯'=>'󠆯','󠆰'=>'󠆰','󠆱'=>'󠆱','󠆲'=>'󠆲','󠆳'=>'󠆳','󠆴'=>'󠆴','󠆵'=>'󠆵','󠆶'=>'󠆶','󠆷'=>'󠆷','󠆸'=>'󠆸','󠆹'=>'󠆹','󠆺'=>'󠆺','󠆻'=>'󠆻','󠆼'=>'󠆼','󠆽'=>'󠆽','󠆾'=>'󠆾','󠆿'=>'󠆿','󠇀'=>'󠇀','󠇁'=>'󠇁','󠇂'=>'󠇂','󠇃'=>'󠇃','󠇄'=>'󠇄','󠇅'=>'󠇅','󠇆'=>'󠇆','󠇇'=>'󠇇','󠇈'=>'󠇈','󠇉'=>'󠇉','󠇊'=>'󠇊','󠇋'=>'󠇋','󠇌'=>'󠇌','󠇍'=>'󠇍','󠇎'=>'󠇎','󠇏'=>'󠇏','󠇐'=>'󠇐','󠇑'=>'󠇑','󠇒'=>'󠇒','󠇓'=>'󠇓','󠇔'=>'󠇔','󠇕'=>'󠇕','󠇖'=>'󠇖','󠇗'=>'󠇗','󠇘'=>'󠇘','󠇙'=>'󠇙','󠇚'=>'󠇚','󠇛'=>'󠇛','󠇜'=>'󠇜','󠇝'=>'󠇝','󠇞'=>'󠇞','󠇟'=>'󠇟','󠇠'=>'󠇠','󠇡'=>'󠇡','󠇢'=>'󠇢','󠇣'=>'󠇣','󠇤'=>'󠇤','󠇥'=>'󠇥','󠇦'=>'󠇦','󠇧'=>'󠇧','󠇨'=>'󠇨','󠇩'=>'󠇩','󠇪'=>'󠇪','󠇫'=>'󠇫','󠇬'=>'󠇬','󠇭'=>'󠇭','󠇮'=>'󠇮','󠇯'=>'󠇯');
\ No newline at end of file +<?php return array('󠄀'=>'󠄀','󠄁'=>'󠄁','󠄂'=>'󠄂','󠄃'=>'󠄃','󠄄'=>'󠄄','󠄅'=>'󠄅','󠄆'=>'󠄆','󠄇'=>'󠄇','󠄈'=>'󠄈','󠄉'=>'󠄉','󠄊'=>'󠄊','󠄋'=>'󠄋','󠄌'=>'󠄌','󠄍'=>'󠄍','󠄎'=>'󠄎','󠄏'=>'󠄏','󠄐'=>'󠄐','󠄑'=>'󠄑','󠄒'=>'󠄒','󠄓'=>'󠄓','󠄔'=>'󠄔','󠄕'=>'󠄕','󠄖'=>'󠄖','󠄗'=>'󠄗','󠄘'=>'󠄘','󠄙'=>'󠄙','󠄚'=>'󠄚','󠄛'=>'󠄛','󠄜'=>'󠄜','󠄝'=>'󠄝','󠄞'=>'󠄞','󠄟'=>'󠄟','󠄠'=>'󠄠','󠄡'=>'󠄡','󠄢'=>'󠄢','󠄣'=>'󠄣','󠄤'=>'󠄤','󠄥'=>'󠄥','󠄦'=>'󠄦','󠄧'=>'󠄧','󠄨'=>'󠄨','󠄩'=>'󠄩','󠄪'=>'󠄪','󠄫'=>'󠄫','󠄬'=>'󠄬','󠄭'=>'󠄭','󠄮'=>'󠄮','󠄯'=>'󠄯','󠄰'=>'󠄰','󠄱'=>'󠄱','󠄲'=>'󠄲','󠄳'=>'󠄳','󠄴'=>'󠄴','󠄵'=>'󠄵','󠄶'=>'󠄶','󠄷'=>'󠄷','󠄸'=>'󠄸','󠄹'=>'󠄹','󠄺'=>'󠄺','󠄻'=>'󠄻','󠄼'=>'󠄼','󠄽'=>'󠄽','󠄾'=>'󠄾','󠄿'=>'󠄿','󠅀'=>'󠅀','󠅁'=>'󠅁','󠅂'=>'󠅂','󠅃'=>'󠅃','󠅄'=>'󠅄','󠅅'=>'󠅅','󠅆'=>'󠅆','󠅇'=>'󠅇','󠅈'=>'󠅈','󠅉'=>'󠅉','󠅊'=>'󠅊','󠅋'=>'󠅋','󠅌'=>'󠅌','󠅍'=>'󠅍','󠅎'=>'󠅎','󠅏'=>'󠅏','󠅐'=>'󠅐','󠅑'=>'󠅑','󠅒'=>'󠅒','󠅓'=>'󠅓','󠅔'=>'󠅔','󠅕'=>'󠅕','󠅖'=>'󠅖','󠅗'=>'󠅗','󠅘'=>'󠅘','󠅙'=>'󠅙','󠅚'=>'󠅚','󠅛'=>'󠅛','󠅜'=>'󠅜','󠅝'=>'󠅝','󠅞'=>'󠅞','󠅟'=>'󠅟','󠅠'=>'󠅠','󠅡'=>'󠅡','󠅢'=>'󠅢','󠅣'=>'󠅣','󠅤'=>'󠅤','󠅥'=>'󠅥','󠅦'=>'󠅦','󠅧'=>'󠅧','󠅨'=>'󠅨','󠅩'=>'󠅩','󠅪'=>'󠅪','󠅫'=>'󠅫','󠅬'=>'󠅬','󠅭'=>'󠅭','󠅮'=>'󠅮','󠅯'=>'󠅯','󠅰'=>'󠅰','󠅱'=>'󠅱','󠅲'=>'󠅲','󠅳'=>'󠅳','󠅴'=>'󠅴','󠅵'=>'󠅵','󠅶'=>'󠅶','󠅷'=>'󠅷','󠅸'=>'󠅸','󠅹'=>'󠅹','󠅺'=>'󠅺','󠅻'=>'󠅻','󠅼'=>'󠅼','󠅽'=>'󠅽','󠅾'=>'󠅾','󠅿'=>'󠅿','󠆀'=>'󠆀','󠆁'=>'󠆁','󠆂'=>'󠆂','󠆃'=>'󠆃','󠆄'=>'󠆄','󠆅'=>'󠆅','󠆆'=>'󠆆','󠆇'=>'󠆇','󠆈'=>'󠆈','󠆉'=>'󠆉','󠆊'=>'󠆊','󠆋'=>'󠆋','󠆌'=>'󠆌','󠆍'=>'󠆍','󠆎'=>'󠆎','󠆏'=>'󠆏','󠆐'=>'󠆐','󠆑'=>'󠆑','󠆒'=>'󠆒','󠆓'=>'󠆓','󠆔'=>'󠆔','󠆕'=>'󠆕','󠆖'=>'󠆖','󠆗'=>'󠆗','󠆘'=>'󠆘','󠆙'=>'󠆙','󠆚'=>'󠆚','󠆛'=>'󠆛','󠆜'=>'󠆜','󠆝'=>'󠆝','󠆞'=>'󠆞','󠆟'=>'󠆟','󠆠'=>'󠆠','󠆡'=>'󠆡','󠆢'=>'󠆢','󠆣'=>'󠆣','󠆤'=>'󠆤','󠆥'=>'󠆥','󠆦'=>'󠆦','󠆧'=>'󠆧','󠆨'=>'󠆨','󠆩'=>'󠆩','󠆪'=>'󠆪','󠆫'=>'󠆫','󠆬'=>'󠆬','󠆭'=>'󠆭','󠆮'=>'󠆮','󠆯'=>'󠆯','󠆰'=>'󠆰','󠆱'=>'󠆱','󠆲'=>'󠆲','󠆳'=>'󠆳','󠆴'=>'󠆴','󠆵'=>'󠆵','󠆶'=>'󠆶','󠆷'=>'󠆷','󠆸'=>'󠆸','󠆹'=>'󠆹','󠆺'=>'󠆺','󠆻'=>'󠆻','󠆼'=>'󠆼','󠆽'=>'󠆽','󠆾'=>'󠆾','󠆿'=>'󠆿','󠇀'=>'󠇀','󠇁'=>'󠇁','󠇂'=>'󠇂','󠇃'=>'󠇃','󠇄'=>'󠇄','󠇅'=>'󠇅','󠇆'=>'󠇆','󠇇'=>'󠇇','󠇈'=>'󠇈','󠇉'=>'󠇉','󠇊'=>'󠇊','󠇋'=>'󠇋','󠇌'=>'󠇌','󠇍'=>'󠇍','󠇎'=>'󠇎','󠇏'=>'󠇏','󠇐'=>'󠇐','󠇑'=>'󠇑','󠇒'=>'󠇒','󠇓'=>'󠇓','󠇔'=>'󠇔','󠇕'=>'󠇕','󠇖'=>'󠇖','󠇗'=>'󠇗','󠇘'=>'󠇘','󠇙'=>'󠇙','󠇚'=>'󠇚','󠇛'=>'󠇛','󠇜'=>'󠇜','󠇝'=>'󠇝','󠇞'=>'󠇞','󠇟'=>'󠇟','󠇠'=>'󠇠','󠇡'=>'󠇡','󠇢'=>'󠇢','󠇣'=>'󠇣','󠇤'=>'󠇤','󠇥'=>'󠇥','󠇦'=>'󠇦','󠇧'=>'󠇧','󠇨'=>'󠇨','󠇩'=>'󠇩','󠇪'=>'󠇪','󠇫'=>'󠇫','󠇬'=>'󠇬','󠇭'=>'󠇭','󠇮'=>'󠇮','󠇯'=>'󠇯'); diff --git a/phpBB/includes/utf/data/search_indexer_5.php b/phpBB/includes/utf/data/search_indexer_5.php index 0f1228a394..cef8fe91fc 100644 --- a/phpBB/includes/utf/data/search_indexer_5.php +++ b/phpBB/includes/utf/data/search_indexer_5.php @@ -1 +1 @@ -<?php return array('Ⰰ'=>'ⰰ','Ⰱ'=>'ⰱ','Ⰲ'=>'ⰲ','Ⰳ'=>'ⰳ','Ⰴ'=>'ⰴ','Ⰵ'=>'ⰵ','Ⰶ'=>'ⰶ','Ⰷ'=>'ⰷ','Ⰸ'=>'ⰸ','Ⰹ'=>'ⰹ','Ⰺ'=>'ⰺ','Ⰻ'=>'ⰻ','Ⰼ'=>'ⰼ','Ⰽ'=>'ⰽ','Ⰾ'=>'ⰾ','Ⰿ'=>'ⰿ','Ⱀ'=>'ⱀ','Ⱁ'=>'ⱁ','Ⱂ'=>'ⱂ','Ⱃ'=>'ⱃ','Ⱄ'=>'ⱄ','Ⱅ'=>'ⱅ','Ⱆ'=>'ⱆ','Ⱇ'=>'ⱇ','Ⱈ'=>'ⱈ','Ⱉ'=>'ⱉ','Ⱊ'=>'ⱊ','Ⱋ'=>'ⱋ','Ⱌ'=>'ⱌ','Ⱍ'=>'ⱍ','Ⱎ'=>'ⱎ','Ⱏ'=>'ⱏ','Ⱐ'=>'ⱐ','Ⱑ'=>'ⱑ','Ⱒ'=>'ⱒ','Ⱓ'=>'ⱓ','Ⱔ'=>'ⱔ','Ⱕ'=>'ⱕ','Ⱖ'=>'ⱖ','Ⱗ'=>'ⱗ','Ⱘ'=>'ⱘ','Ⱙ'=>'ⱙ','Ⱚ'=>'ⱚ','Ⱛ'=>'ⱛ','Ⱜ'=>'ⱜ','Ⱝ'=>'ⱝ','Ⱞ'=>'ⱞ','ⰰ'=>'ⰰ','ⰱ'=>'ⰱ','ⰲ'=>'ⰲ','ⰳ'=>'ⰳ','ⰴ'=>'ⰴ','ⰵ'=>'ⰵ','ⰶ'=>'ⰶ','ⰷ'=>'ⰷ','ⰸ'=>'ⰸ','ⰹ'=>'ⰹ','ⰺ'=>'ⰺ','ⰻ'=>'ⰻ','ⰼ'=>'ⰼ','ⰽ'=>'ⰽ','ⰾ'=>'ⰾ','ⰿ'=>'ⰿ','ⱀ'=>'ⱀ','ⱁ'=>'ⱁ','ⱂ'=>'ⱂ','ⱃ'=>'ⱃ','ⱄ'=>'ⱄ','ⱅ'=>'ⱅ','ⱆ'=>'ⱆ','ⱇ'=>'ⱇ','ⱈ'=>'ⱈ','ⱉ'=>'ⱉ','ⱊ'=>'ⱊ','ⱋ'=>'ⱋ','ⱌ'=>'ⱌ','ⱍ'=>'ⱍ','ⱎ'=>'ⱎ','ⱏ'=>'ⱏ','ⱐ'=>'ⱐ','ⱑ'=>'ⱑ','ⱒ'=>'ⱒ','ⱓ'=>'ⱓ','ⱔ'=>'ⱔ','ⱕ'=>'ⱕ','ⱖ'=>'ⱖ','ⱗ'=>'ⱗ','ⱘ'=>'ⱘ','ⱙ'=>'ⱙ','ⱚ'=>'ⱚ','ⱛ'=>'ⱛ','ⱜ'=>'ⱜ','ⱝ'=>'ⱝ','ⱞ'=>'ⱞ','Ⱡ'=>'ⱡ','ⱡ'=>'ⱡ','Ɫ'=>'ɫ','Ᵽ'=>'ᵽ','Ɽ'=>'ɽ','ⱥ'=>'ⱥ','ⱦ'=>'ⱦ','Ⱨ'=>'ⱨ','ⱨ'=>'ⱨ','Ⱪ'=>'ⱪ','ⱪ'=>'ⱪ','Ⱬ'=>'ⱬ','ⱬ'=>'ⱬ','ⱴ'=>'ⱴ','Ⱶ'=>'ⱶ','ⱶ'=>'ⱶ','ⱷ'=>'ⱷ','Ⲁ'=>'ⲁ','ⲁ'=>'ⲁ','Ⲃ'=>'ⲃ','ⲃ'=>'ⲃ','Ⲅ'=>'ⲅ','ⲅ'=>'ⲅ','Ⲇ'=>'ⲇ','ⲇ'=>'ⲇ','Ⲉ'=>'ⲉ','ⲉ'=>'ⲉ','Ⲋ'=>'ⲋ','ⲋ'=>'ⲋ','Ⲍ'=>'ⲍ','ⲍ'=>'ⲍ','Ⲏ'=>'ⲏ','ⲏ'=>'ⲏ','Ⲑ'=>'ⲑ','ⲑ'=>'ⲑ','Ⲓ'=>'ⲓ','ⲓ'=>'ⲓ','Ⲕ'=>'ⲕ','ⲕ'=>'ⲕ','Ⲗ'=>'ⲗ','ⲗ'=>'ⲗ','Ⲙ'=>'ⲙ','ⲙ'=>'ⲙ','Ⲛ'=>'ⲛ','ⲛ'=>'ⲛ','Ⲝ'=>'ⲝ','ⲝ'=>'ⲝ','Ⲟ'=>'ⲟ','ⲟ'=>'ⲟ','Ⲡ'=>'ⲡ','ⲡ'=>'ⲡ','Ⲣ'=>'ⲣ','ⲣ'=>'ⲣ','Ⲥ'=>'ⲥ','ⲥ'=>'ⲥ','Ⲧ'=>'ⲧ','ⲧ'=>'ⲧ','Ⲩ'=>'ⲩ','ⲩ'=>'ⲩ','Ⲫ'=>'ⲫ','ⲫ'=>'ⲫ','Ⲭ'=>'ⲭ','ⲭ'=>'ⲭ','Ⲯ'=>'ⲯ','ⲯ'=>'ⲯ','Ⲱ'=>'ⲱ','ⲱ'=>'ⲱ','Ⲳ'=>'ⲳ','ⲳ'=>'ⲳ','Ⲵ'=>'ⲵ','ⲵ'=>'ⲵ','Ⲷ'=>'ⲷ','ⲷ'=>'ⲷ','Ⲹ'=>'ⲹ','ⲹ'=>'ⲹ','Ⲻ'=>'ⲻ','ⲻ'=>'ⲻ','Ⲽ'=>'ⲽ','ⲽ'=>'ⲽ','Ⲿ'=>'ⲿ','ⲿ'=>'ⲿ','Ⳁ'=>'ⳁ','ⳁ'=>'ⳁ','Ⳃ'=>'ⳃ','ⳃ'=>'ⳃ','Ⳅ'=>'ⳅ','ⳅ'=>'ⳅ','Ⳇ'=>'ⳇ','ⳇ'=>'ⳇ','Ⳉ'=>'ⳉ','ⳉ'=>'ⳉ','Ⳋ'=>'ⳋ','ⳋ'=>'ⳋ','Ⳍ'=>'ⳍ','ⳍ'=>'ⳍ','Ⳏ'=>'ⳏ','ⳏ'=>'ⳏ','Ⳑ'=>'ⳑ','ⳑ'=>'ⳑ','Ⳓ'=>'ⳓ','ⳓ'=>'ⳓ','Ⳕ'=>'ⳕ','ⳕ'=>'ⳕ','Ⳗ'=>'ⳗ','ⳗ'=>'ⳗ','Ⳙ'=>'ⳙ','ⳙ'=>'ⳙ','Ⳛ'=>'ⳛ','ⳛ'=>'ⳛ','Ⳝ'=>'ⳝ','ⳝ'=>'ⳝ','Ⳟ'=>'ⳟ','ⳟ'=>'ⳟ','Ⳡ'=>'ⳡ','ⳡ'=>'ⳡ','Ⳣ'=>'ⳣ','ⳣ'=>'ⳣ','ⳤ'=>'ⳤ','⳽'=>'1/2','ⴀ'=>'ⴀ','ⴁ'=>'ⴁ','ⴂ'=>'ⴂ','ⴃ'=>'ⴃ','ⴄ'=>'ⴄ','ⴅ'=>'ⴅ','ⴆ'=>'ⴆ','ⴇ'=>'ⴇ','ⴈ'=>'ⴈ','ⴉ'=>'ⴉ','ⴊ'=>'ⴊ','ⴋ'=>'ⴋ','ⴌ'=>'ⴌ','ⴍ'=>'ⴍ','ⴎ'=>'ⴎ','ⴏ'=>'ⴏ','ⴐ'=>'ⴐ','ⴑ'=>'ⴑ','ⴒ'=>'ⴒ','ⴓ'=>'ⴓ','ⴔ'=>'ⴔ','ⴕ'=>'ⴕ','ⴖ'=>'ⴖ','ⴗ'=>'ⴗ','ⴘ'=>'ⴘ','ⴙ'=>'ⴙ','ⴚ'=>'ⴚ','ⴛ'=>'ⴛ','ⴜ'=>'ⴜ','ⴝ'=>'ⴝ','ⴞ'=>'ⴞ','ⴟ'=>'ⴟ','ⴠ'=>'ⴠ','ⴡ'=>'ⴡ','ⴢ'=>'ⴢ','ⴣ'=>'ⴣ','ⴤ'=>'ⴤ','ⴥ'=>'ⴥ','ⴰ'=>'ⴰ','ⴱ'=>'ⴱ','ⴲ'=>'ⴲ','ⴳ'=>'ⴳ','ⴴ'=>'ⴴ','ⴵ'=>'ⴵ','ⴶ'=>'ⴶ','ⴷ'=>'ⴷ','ⴸ'=>'ⴸ','ⴹ'=>'ⴹ','ⴺ'=>'ⴺ','ⴻ'=>'ⴻ','ⴼ'=>'ⴼ','ⴽ'=>'ⴽ','ⴾ'=>'ⴾ','ⴿ'=>'ⴿ','ⵀ'=>'ⵀ','ⵁ'=>'ⵁ','ⵂ'=>'ⵂ','ⵃ'=>'ⵃ','ⵄ'=>'ⵄ','ⵅ'=>'ⵅ','ⵆ'=>'ⵆ','ⵇ'=>'ⵇ','ⵈ'=>'ⵈ','ⵉ'=>'ⵉ','ⵊ'=>'ⵊ','ⵋ'=>'ⵋ','ⵌ'=>'ⵌ','ⵍ'=>'ⵍ','ⵎ'=>'ⵎ','ⵏ'=>'ⵏ','ⵐ'=>'ⵐ','ⵑ'=>'ⵑ','ⵒ'=>'ⵒ','ⵓ'=>'ⵓ','ⵔ'=>'ⵔ','ⵕ'=>'ⵕ','ⵖ'=>'ⵖ','ⵗ'=>'ⵗ','ⵘ'=>'ⵘ','ⵙ'=>'ⵙ','ⵚ'=>'ⵚ','ⵛ'=>'ⵛ','ⵜ'=>'ⵜ','ⵝ'=>'ⵝ','ⵞ'=>'ⵞ','ⵟ'=>'ⵟ','ⵠ'=>'ⵠ','ⵡ'=>'ⵡ','ⵢ'=>'ⵢ','ⵣ'=>'ⵣ','ⵤ'=>'ⵤ','ⵥ'=>'ⵥ','ⵯ'=>'ⵯ','ⶀ'=>'ⶀ','ⶁ'=>'ⶁ','ⶂ'=>'ⶂ','ⶃ'=>'ⶃ','ⶄ'=>'ⶄ','ⶅ'=>'ⶅ','ⶆ'=>'ⶆ','ⶇ'=>'ⶇ','ⶈ'=>'ⶈ','ⶉ'=>'ⶉ','ⶊ'=>'ⶊ','ⶋ'=>'ⶋ','ⶌ'=>'ⶌ','ⶍ'=>'ⶍ','ⶎ'=>'ⶎ','ⶏ'=>'ⶏ','ⶐ'=>'ⶐ','ⶑ'=>'ⶑ','ⶒ'=>'ⶒ','ⶓ'=>'ⶓ','ⶔ'=>'ⶔ','ⶕ'=>'ⶕ','ⶖ'=>'ⶖ','ⶠ'=>'ⶠ','ⶡ'=>'ⶡ','ⶢ'=>'ⶢ','ⶣ'=>'ⶣ','ⶤ'=>'ⶤ','ⶥ'=>'ⶥ','ⶦ'=>'ⶦ','ⶨ'=>'ⶨ','ⶩ'=>'ⶩ','ⶪ'=>'ⶪ','ⶫ'=>'ⶫ','ⶬ'=>'ⶬ','ⶭ'=>'ⶭ','ⶮ'=>'ⶮ','ⶰ'=>'ⶰ','ⶱ'=>'ⶱ','ⶲ'=>'ⶲ','ⶳ'=>'ⶳ','ⶴ'=>'ⶴ','ⶵ'=>'ⶵ','ⶶ'=>'ⶶ','ⶸ'=>'ⶸ','ⶹ'=>'ⶹ','ⶺ'=>'ⶺ','ⶻ'=>'ⶻ','ⶼ'=>'ⶼ','ⶽ'=>'ⶽ','ⶾ'=>'ⶾ','ⷀ'=>'ⷀ','ⷁ'=>'ⷁ','ⷂ'=>'ⷂ','ⷃ'=>'ⷃ','ⷄ'=>'ⷄ','ⷅ'=>'ⷅ','ⷆ'=>'ⷆ','ⷈ'=>'ⷈ','ⷉ'=>'ⷉ','ⷊ'=>'ⷊ','ⷋ'=>'ⷋ','ⷌ'=>'ⷌ','ⷍ'=>'ⷍ','ⷎ'=>'ⷎ','ⷐ'=>'ⷐ','ⷑ'=>'ⷑ','ⷒ'=>'ⷒ','ⷓ'=>'ⷓ','ⷔ'=>'ⷔ','ⷕ'=>'ⷕ','ⷖ'=>'ⷖ','ⷘ'=>'ⷘ','ⷙ'=>'ⷙ','ⷚ'=>'ⷚ','ⷛ'=>'ⷛ','ⷜ'=>'ⷜ','ⷝ'=>'ⷝ','ⷞ'=>'ⷞ');
\ No newline at end of file +<?php return array('Ⰰ'=>'ⰰ','Ⰱ'=>'ⰱ','Ⰲ'=>'ⰲ','Ⰳ'=>'ⰳ','Ⰴ'=>'ⰴ','Ⰵ'=>'ⰵ','Ⰶ'=>'ⰶ','Ⰷ'=>'ⰷ','Ⰸ'=>'ⰸ','Ⰹ'=>'ⰹ','Ⰺ'=>'ⰺ','Ⰻ'=>'ⰻ','Ⰼ'=>'ⰼ','Ⰽ'=>'ⰽ','Ⰾ'=>'ⰾ','Ⰿ'=>'ⰿ','Ⱀ'=>'ⱀ','Ⱁ'=>'ⱁ','Ⱂ'=>'ⱂ','Ⱃ'=>'ⱃ','Ⱄ'=>'ⱄ','Ⱅ'=>'ⱅ','Ⱆ'=>'ⱆ','Ⱇ'=>'ⱇ','Ⱈ'=>'ⱈ','Ⱉ'=>'ⱉ','Ⱊ'=>'ⱊ','Ⱋ'=>'ⱋ','Ⱌ'=>'ⱌ','Ⱍ'=>'ⱍ','Ⱎ'=>'ⱎ','Ⱏ'=>'ⱏ','Ⱐ'=>'ⱐ','Ⱑ'=>'ⱑ','Ⱒ'=>'ⱒ','Ⱓ'=>'ⱓ','Ⱔ'=>'ⱔ','Ⱕ'=>'ⱕ','Ⱖ'=>'ⱖ','Ⱗ'=>'ⱗ','Ⱘ'=>'ⱘ','Ⱙ'=>'ⱙ','Ⱚ'=>'ⱚ','Ⱛ'=>'ⱛ','Ⱜ'=>'ⱜ','Ⱝ'=>'ⱝ','Ⱞ'=>'ⱞ','ⰰ'=>'ⰰ','ⰱ'=>'ⰱ','ⰲ'=>'ⰲ','ⰳ'=>'ⰳ','ⰴ'=>'ⰴ','ⰵ'=>'ⰵ','ⰶ'=>'ⰶ','ⰷ'=>'ⰷ','ⰸ'=>'ⰸ','ⰹ'=>'ⰹ','ⰺ'=>'ⰺ','ⰻ'=>'ⰻ','ⰼ'=>'ⰼ','ⰽ'=>'ⰽ','ⰾ'=>'ⰾ','ⰿ'=>'ⰿ','ⱀ'=>'ⱀ','ⱁ'=>'ⱁ','ⱂ'=>'ⱂ','ⱃ'=>'ⱃ','ⱄ'=>'ⱄ','ⱅ'=>'ⱅ','ⱆ'=>'ⱆ','ⱇ'=>'ⱇ','ⱈ'=>'ⱈ','ⱉ'=>'ⱉ','ⱊ'=>'ⱊ','ⱋ'=>'ⱋ','ⱌ'=>'ⱌ','ⱍ'=>'ⱍ','ⱎ'=>'ⱎ','ⱏ'=>'ⱏ','ⱐ'=>'ⱐ','ⱑ'=>'ⱑ','ⱒ'=>'ⱒ','ⱓ'=>'ⱓ','ⱔ'=>'ⱔ','ⱕ'=>'ⱕ','ⱖ'=>'ⱖ','ⱗ'=>'ⱗ','ⱘ'=>'ⱘ','ⱙ'=>'ⱙ','ⱚ'=>'ⱚ','ⱛ'=>'ⱛ','ⱜ'=>'ⱜ','ⱝ'=>'ⱝ','ⱞ'=>'ⱞ','Ⱡ'=>'ⱡ','ⱡ'=>'ⱡ','Ɫ'=>'ɫ','Ᵽ'=>'ᵽ','Ɽ'=>'ɽ','ⱥ'=>'ⱥ','ⱦ'=>'ⱦ','Ⱨ'=>'ⱨ','ⱨ'=>'ⱨ','Ⱪ'=>'ⱪ','ⱪ'=>'ⱪ','Ⱬ'=>'ⱬ','ⱬ'=>'ⱬ','ⱴ'=>'ⱴ','Ⱶ'=>'ⱶ','ⱶ'=>'ⱶ','ⱷ'=>'ⱷ','Ⲁ'=>'ⲁ','ⲁ'=>'ⲁ','Ⲃ'=>'ⲃ','ⲃ'=>'ⲃ','Ⲅ'=>'ⲅ','ⲅ'=>'ⲅ','Ⲇ'=>'ⲇ','ⲇ'=>'ⲇ','Ⲉ'=>'ⲉ','ⲉ'=>'ⲉ','Ⲋ'=>'ⲋ','ⲋ'=>'ⲋ','Ⲍ'=>'ⲍ','ⲍ'=>'ⲍ','Ⲏ'=>'ⲏ','ⲏ'=>'ⲏ','Ⲑ'=>'ⲑ','ⲑ'=>'ⲑ','Ⲓ'=>'ⲓ','ⲓ'=>'ⲓ','Ⲕ'=>'ⲕ','ⲕ'=>'ⲕ','Ⲗ'=>'ⲗ','ⲗ'=>'ⲗ','Ⲙ'=>'ⲙ','ⲙ'=>'ⲙ','Ⲛ'=>'ⲛ','ⲛ'=>'ⲛ','Ⲝ'=>'ⲝ','ⲝ'=>'ⲝ','Ⲟ'=>'ⲟ','ⲟ'=>'ⲟ','Ⲡ'=>'ⲡ','ⲡ'=>'ⲡ','Ⲣ'=>'ⲣ','ⲣ'=>'ⲣ','Ⲥ'=>'ⲥ','ⲥ'=>'ⲥ','Ⲧ'=>'ⲧ','ⲧ'=>'ⲧ','Ⲩ'=>'ⲩ','ⲩ'=>'ⲩ','Ⲫ'=>'ⲫ','ⲫ'=>'ⲫ','Ⲭ'=>'ⲭ','ⲭ'=>'ⲭ','Ⲯ'=>'ⲯ','ⲯ'=>'ⲯ','Ⲱ'=>'ⲱ','ⲱ'=>'ⲱ','Ⲳ'=>'ⲳ','ⲳ'=>'ⲳ','Ⲵ'=>'ⲵ','ⲵ'=>'ⲵ','Ⲷ'=>'ⲷ','ⲷ'=>'ⲷ','Ⲹ'=>'ⲹ','ⲹ'=>'ⲹ','Ⲻ'=>'ⲻ','ⲻ'=>'ⲻ','Ⲽ'=>'ⲽ','ⲽ'=>'ⲽ','Ⲿ'=>'ⲿ','ⲿ'=>'ⲿ','Ⳁ'=>'ⳁ','ⳁ'=>'ⳁ','Ⳃ'=>'ⳃ','ⳃ'=>'ⳃ','Ⳅ'=>'ⳅ','ⳅ'=>'ⳅ','Ⳇ'=>'ⳇ','ⳇ'=>'ⳇ','Ⳉ'=>'ⳉ','ⳉ'=>'ⳉ','Ⳋ'=>'ⳋ','ⳋ'=>'ⳋ','Ⳍ'=>'ⳍ','ⳍ'=>'ⳍ','Ⳏ'=>'ⳏ','ⳏ'=>'ⳏ','Ⳑ'=>'ⳑ','ⳑ'=>'ⳑ','Ⳓ'=>'ⳓ','ⳓ'=>'ⳓ','Ⳕ'=>'ⳕ','ⳕ'=>'ⳕ','Ⳗ'=>'ⳗ','ⳗ'=>'ⳗ','Ⳙ'=>'ⳙ','ⳙ'=>'ⳙ','Ⳛ'=>'ⳛ','ⳛ'=>'ⳛ','Ⳝ'=>'ⳝ','ⳝ'=>'ⳝ','Ⳟ'=>'ⳟ','ⳟ'=>'ⳟ','Ⳡ'=>'ⳡ','ⳡ'=>'ⳡ','Ⳣ'=>'ⳣ','ⳣ'=>'ⳣ','ⳤ'=>'ⳤ','⳽'=>'1/2','ⴀ'=>'ⴀ','ⴁ'=>'ⴁ','ⴂ'=>'ⴂ','ⴃ'=>'ⴃ','ⴄ'=>'ⴄ','ⴅ'=>'ⴅ','ⴆ'=>'ⴆ','ⴇ'=>'ⴇ','ⴈ'=>'ⴈ','ⴉ'=>'ⴉ','ⴊ'=>'ⴊ','ⴋ'=>'ⴋ','ⴌ'=>'ⴌ','ⴍ'=>'ⴍ','ⴎ'=>'ⴎ','ⴏ'=>'ⴏ','ⴐ'=>'ⴐ','ⴑ'=>'ⴑ','ⴒ'=>'ⴒ','ⴓ'=>'ⴓ','ⴔ'=>'ⴔ','ⴕ'=>'ⴕ','ⴖ'=>'ⴖ','ⴗ'=>'ⴗ','ⴘ'=>'ⴘ','ⴙ'=>'ⴙ','ⴚ'=>'ⴚ','ⴛ'=>'ⴛ','ⴜ'=>'ⴜ','ⴝ'=>'ⴝ','ⴞ'=>'ⴞ','ⴟ'=>'ⴟ','ⴠ'=>'ⴠ','ⴡ'=>'ⴡ','ⴢ'=>'ⴢ','ⴣ'=>'ⴣ','ⴤ'=>'ⴤ','ⴥ'=>'ⴥ','ⴰ'=>'ⴰ','ⴱ'=>'ⴱ','ⴲ'=>'ⴲ','ⴳ'=>'ⴳ','ⴴ'=>'ⴴ','ⴵ'=>'ⴵ','ⴶ'=>'ⴶ','ⴷ'=>'ⴷ','ⴸ'=>'ⴸ','ⴹ'=>'ⴹ','ⴺ'=>'ⴺ','ⴻ'=>'ⴻ','ⴼ'=>'ⴼ','ⴽ'=>'ⴽ','ⴾ'=>'ⴾ','ⴿ'=>'ⴿ','ⵀ'=>'ⵀ','ⵁ'=>'ⵁ','ⵂ'=>'ⵂ','ⵃ'=>'ⵃ','ⵄ'=>'ⵄ','ⵅ'=>'ⵅ','ⵆ'=>'ⵆ','ⵇ'=>'ⵇ','ⵈ'=>'ⵈ','ⵉ'=>'ⵉ','ⵊ'=>'ⵊ','ⵋ'=>'ⵋ','ⵌ'=>'ⵌ','ⵍ'=>'ⵍ','ⵎ'=>'ⵎ','ⵏ'=>'ⵏ','ⵐ'=>'ⵐ','ⵑ'=>'ⵑ','ⵒ'=>'ⵒ','ⵓ'=>'ⵓ','ⵔ'=>'ⵔ','ⵕ'=>'ⵕ','ⵖ'=>'ⵖ','ⵗ'=>'ⵗ','ⵘ'=>'ⵘ','ⵙ'=>'ⵙ','ⵚ'=>'ⵚ','ⵛ'=>'ⵛ','ⵜ'=>'ⵜ','ⵝ'=>'ⵝ','ⵞ'=>'ⵞ','ⵟ'=>'ⵟ','ⵠ'=>'ⵠ','ⵡ'=>'ⵡ','ⵢ'=>'ⵢ','ⵣ'=>'ⵣ','ⵤ'=>'ⵤ','ⵥ'=>'ⵥ','ⵯ'=>'ⵯ','ⶀ'=>'ⶀ','ⶁ'=>'ⶁ','ⶂ'=>'ⶂ','ⶃ'=>'ⶃ','ⶄ'=>'ⶄ','ⶅ'=>'ⶅ','ⶆ'=>'ⶆ','ⶇ'=>'ⶇ','ⶈ'=>'ⶈ','ⶉ'=>'ⶉ','ⶊ'=>'ⶊ','ⶋ'=>'ⶋ','ⶌ'=>'ⶌ','ⶍ'=>'ⶍ','ⶎ'=>'ⶎ','ⶏ'=>'ⶏ','ⶐ'=>'ⶐ','ⶑ'=>'ⶑ','ⶒ'=>'ⶒ','ⶓ'=>'ⶓ','ⶔ'=>'ⶔ','ⶕ'=>'ⶕ','ⶖ'=>'ⶖ','ⶠ'=>'ⶠ','ⶡ'=>'ⶡ','ⶢ'=>'ⶢ','ⶣ'=>'ⶣ','ⶤ'=>'ⶤ','ⶥ'=>'ⶥ','ⶦ'=>'ⶦ','ⶨ'=>'ⶨ','ⶩ'=>'ⶩ','ⶪ'=>'ⶪ','ⶫ'=>'ⶫ','ⶬ'=>'ⶬ','ⶭ'=>'ⶭ','ⶮ'=>'ⶮ','ⶰ'=>'ⶰ','ⶱ'=>'ⶱ','ⶲ'=>'ⶲ','ⶳ'=>'ⶳ','ⶴ'=>'ⶴ','ⶵ'=>'ⶵ','ⶶ'=>'ⶶ','ⶸ'=>'ⶸ','ⶹ'=>'ⶹ','ⶺ'=>'ⶺ','ⶻ'=>'ⶻ','ⶼ'=>'ⶼ','ⶽ'=>'ⶽ','ⶾ'=>'ⶾ','ⷀ'=>'ⷀ','ⷁ'=>'ⷁ','ⷂ'=>'ⷂ','ⷃ'=>'ⷃ','ⷄ'=>'ⷄ','ⷅ'=>'ⷅ','ⷆ'=>'ⷆ','ⷈ'=>'ⷈ','ⷉ'=>'ⷉ','ⷊ'=>'ⷊ','ⷋ'=>'ⷋ','ⷌ'=>'ⷌ','ⷍ'=>'ⷍ','ⷎ'=>'ⷎ','ⷐ'=>'ⷐ','ⷑ'=>'ⷑ','ⷒ'=>'ⷒ','ⷓ'=>'ⷓ','ⷔ'=>'ⷔ','ⷕ'=>'ⷕ','ⷖ'=>'ⷖ','ⷘ'=>'ⷘ','ⷙ'=>'ⷙ','ⷚ'=>'ⷚ','ⷛ'=>'ⷛ','ⷜ'=>'ⷜ','ⷝ'=>'ⷝ','ⷞ'=>'ⷞ'); diff --git a/phpBB/includes/utf/data/search_indexer_58.php b/phpBB/includes/utf/data/search_indexer_58.php index 8902bc7995..ec86a4bd62 100644 --- a/phpBB/includes/utf/data/search_indexer_58.php +++ b/phpBB/includes/utf/data/search_indexer_58.php @@ -1 +1 @@ -<?php return array('𝅥'=>'𝅥','𝅦'=>'𝅦','𝅧'=>'𝅧','𝅨'=>'𝅨','𝅩'=>'𝅩','𝅭'=>'𝅭','𝅮'=>'𝅮','𝅯'=>'𝅯','𝅰'=>'𝅰','𝅱'=>'𝅱','𝅲'=>'𝅲','𝅻'=>'𝅻','𝅼'=>'𝅼','𝅽'=>'𝅽','𝅾'=>'𝅾','𝅿'=>'𝅿','𝆀'=>'𝆀','𝆁'=>'𝆁','𝆂'=>'𝆂','𝆅'=>'𝆅','𝆆'=>'𝆆','𝆇'=>'𝆇','𝆈'=>'𝆈','𝆉'=>'𝆉','𝆊'=>'𝆊','𝆋'=>'𝆋','𝆪'=>'𝆪','𝆫'=>'𝆫','𝆬'=>'𝆬','𝆭'=>'𝆭','𝉂'=>'𝉂','𝉃'=>'𝉃','𝉄'=>'𝉄','𝍠'=>'1','𝍡'=>'2','𝍢'=>'3','𝍣'=>'4','𝍤'=>'5','𝍥'=>'6','𝍦'=>'7','𝍧'=>'8','𝍨'=>'9','𝍩'=>'10','𝍪'=>'20','𝍫'=>'30','𝍬'=>'40','𝍭'=>'50','𝍮'=>'60','𝍯'=>'70','𝍰'=>'80','𝍱'=>'90','𝐀'=>'𝐀','𝐁'=>'𝐁','𝐂'=>'𝐂','𝐃'=>'𝐃','𝐄'=>'𝐄','𝐅'=>'𝐅','𝐆'=>'𝐆','𝐇'=>'𝐇','𝐈'=>'𝐈','𝐉'=>'𝐉','𝐊'=>'𝐊','𝐋'=>'𝐋','𝐌'=>'𝐌','𝐍'=>'𝐍','𝐎'=>'𝐎','𝐏'=>'𝐏','𝐐'=>'𝐐','𝐑'=>'𝐑','𝐒'=>'𝐒','𝐓'=>'𝐓','𝐔'=>'𝐔','𝐕'=>'𝐕','𝐖'=>'𝐖','𝐗'=>'𝐗','𝐘'=>'𝐘','𝐙'=>'𝐙','𝐚'=>'𝐚','𝐛'=>'𝐛','𝐜'=>'𝐜','𝐝'=>'𝐝','𝐞'=>'𝐞','𝐟'=>'𝐟','𝐠'=>'𝐠','𝐡'=>'𝐡','𝐢'=>'𝐢','𝐣'=>'𝐣','𝐤'=>'𝐤','𝐥'=>'𝐥','𝐦'=>'𝐦','𝐧'=>'𝐧','𝐨'=>'𝐨','𝐩'=>'𝐩','𝐪'=>'𝐪','𝐫'=>'𝐫','𝐬'=>'𝐬','𝐭'=>'𝐭','𝐮'=>'𝐮','𝐯'=>'𝐯','𝐰'=>'𝐰','𝐱'=>'𝐱','𝐲'=>'𝐲','𝐳'=>'𝐳','𝐴'=>'𝐴','𝐵'=>'𝐵','𝐶'=>'𝐶','𝐷'=>'𝐷','𝐸'=>'𝐸','𝐹'=>'𝐹','𝐺'=>'𝐺','𝐻'=>'𝐻','𝐼'=>'𝐼','𝐽'=>'𝐽','𝐾'=>'𝐾','𝐿'=>'𝐿','𝑀'=>'𝑀','𝑁'=>'𝑁','𝑂'=>'𝑂','𝑃'=>'𝑃','𝑄'=>'𝑄','𝑅'=>'𝑅','𝑆'=>'𝑆','𝑇'=>'𝑇','𝑈'=>'𝑈','𝑉'=>'𝑉','𝑊'=>'𝑊','𝑋'=>'𝑋','𝑌'=>'𝑌','𝑍'=>'𝑍','𝑎'=>'𝑎','𝑏'=>'𝑏','𝑐'=>'𝑐','𝑑'=>'𝑑','𝑒'=>'𝑒','𝑓'=>'𝑓','𝑔'=>'𝑔','𝑖'=>'𝑖','𝑗'=>'𝑗','𝑘'=>'𝑘','𝑙'=>'𝑙','𝑚'=>'𝑚','𝑛'=>'𝑛','𝑜'=>'𝑜','𝑝'=>'𝑝','𝑞'=>'𝑞','𝑟'=>'𝑟','𝑠'=>'𝑠','𝑡'=>'𝑡','𝑢'=>'𝑢','𝑣'=>'𝑣','𝑤'=>'𝑤','𝑥'=>'𝑥','𝑦'=>'𝑦','𝑧'=>'𝑧','𝑨'=>'𝑨','𝑩'=>'𝑩','𝑪'=>'𝑪','𝑫'=>'𝑫','𝑬'=>'𝑬','𝑭'=>'𝑭','𝑮'=>'𝑮','𝑯'=>'𝑯','𝑰'=>'𝑰','𝑱'=>'𝑱','𝑲'=>'𝑲','𝑳'=>'𝑳','𝑴'=>'𝑴','𝑵'=>'𝑵','𝑶'=>'𝑶','𝑷'=>'𝑷','𝑸'=>'𝑸','𝑹'=>'𝑹','𝑺'=>'𝑺','𝑻'=>'𝑻','𝑼'=>'𝑼','𝑽'=>'𝑽','𝑾'=>'𝑾','𝑿'=>'𝑿','𝒀'=>'𝒀','𝒁'=>'𝒁','𝒂'=>'𝒂','𝒃'=>'𝒃','𝒄'=>'𝒄','𝒅'=>'𝒅','𝒆'=>'𝒆','𝒇'=>'𝒇','𝒈'=>'𝒈','𝒉'=>'𝒉','𝒊'=>'𝒊','𝒋'=>'𝒋','𝒌'=>'𝒌','𝒍'=>'𝒍','𝒎'=>'𝒎','𝒏'=>'𝒏','𝒐'=>'𝒐','𝒑'=>'𝒑','𝒒'=>'𝒒','𝒓'=>'𝒓','𝒔'=>'𝒔','𝒕'=>'𝒕','𝒖'=>'𝒖','𝒗'=>'𝒗','𝒘'=>'𝒘','𝒙'=>'𝒙','𝒚'=>'𝒚','𝒛'=>'𝒛','𝒜'=>'𝒜','𝒞'=>'𝒞','𝒟'=>'𝒟','𝒢'=>'𝒢','𝒥'=>'𝒥','𝒦'=>'𝒦','𝒩'=>'𝒩','𝒪'=>'𝒪','𝒫'=>'𝒫','𝒬'=>'𝒬','𝒮'=>'𝒮','𝒯'=>'𝒯','𝒰'=>'𝒰','𝒱'=>'𝒱','𝒲'=>'𝒲','𝒳'=>'𝒳','𝒴'=>'𝒴','𝒵'=>'𝒵','𝒶'=>'𝒶','𝒷'=>'𝒷','𝒸'=>'𝒸','𝒹'=>'𝒹','𝒻'=>'𝒻','𝒽'=>'𝒽','𝒾'=>'𝒾','𝒿'=>'𝒿','𝓀'=>'𝓀','𝓁'=>'𝓁','𝓂'=>'𝓂','𝓃'=>'𝓃','𝓅'=>'𝓅','𝓆'=>'𝓆','𝓇'=>'𝓇','𝓈'=>'𝓈','𝓉'=>'𝓉','𝓊'=>'𝓊','𝓋'=>'𝓋','𝓌'=>'𝓌','𝓍'=>'𝓍','𝓎'=>'𝓎','𝓏'=>'𝓏','𝓐'=>'𝓐','𝓑'=>'𝓑','𝓒'=>'𝓒','𝓓'=>'𝓓','𝓔'=>'𝓔','𝓕'=>'𝓕','𝓖'=>'𝓖','𝓗'=>'𝓗','𝓘'=>'𝓘','𝓙'=>'𝓙','𝓚'=>'𝓚','𝓛'=>'𝓛','𝓜'=>'𝓜','𝓝'=>'𝓝','𝓞'=>'𝓞','𝓟'=>'𝓟','𝓠'=>'𝓠','𝓡'=>'𝓡','𝓢'=>'𝓢','𝓣'=>'𝓣','𝓤'=>'𝓤','𝓥'=>'𝓥','𝓦'=>'𝓦','𝓧'=>'𝓧','𝓨'=>'𝓨','𝓩'=>'𝓩','𝓪'=>'𝓪','𝓫'=>'𝓫','𝓬'=>'𝓬','𝓭'=>'𝓭','𝓮'=>'𝓮','𝓯'=>'𝓯','𝓰'=>'𝓰','𝓱'=>'𝓱','𝓲'=>'𝓲','𝓳'=>'𝓳','𝓴'=>'𝓴','𝓵'=>'𝓵','𝓶'=>'𝓶','𝓷'=>'𝓷','𝓸'=>'𝓸','𝓹'=>'𝓹','𝓺'=>'𝓺','𝓻'=>'𝓻','𝓼'=>'𝓼','𝓽'=>'𝓽','𝓾'=>'𝓾','𝓿'=>'𝓿','𝔀'=>'𝔀','𝔁'=>'𝔁','𝔂'=>'𝔂','𝔃'=>'𝔃','𝔄'=>'𝔄','𝔅'=>'𝔅','𝔇'=>'𝔇','𝔈'=>'𝔈','𝔉'=>'𝔉','𝔊'=>'𝔊','𝔍'=>'𝔍','𝔎'=>'𝔎','𝔏'=>'𝔏','𝔐'=>'𝔐','𝔑'=>'𝔑','𝔒'=>'𝔒','𝔓'=>'𝔓','𝔔'=>'𝔔','𝔖'=>'𝔖','𝔗'=>'𝔗','𝔘'=>'𝔘','𝔙'=>'𝔙','𝔚'=>'𝔚','𝔛'=>'𝔛','𝔜'=>'𝔜','𝔞'=>'𝔞','𝔟'=>'𝔟','𝔠'=>'𝔠','𝔡'=>'𝔡','𝔢'=>'𝔢','𝔣'=>'𝔣','𝔤'=>'𝔤','𝔥'=>'𝔥','𝔦'=>'𝔦','𝔧'=>'𝔧','𝔨'=>'𝔨','𝔩'=>'𝔩','𝔪'=>'𝔪','𝔫'=>'𝔫','𝔬'=>'𝔬','𝔭'=>'𝔭','𝔮'=>'𝔮','𝔯'=>'𝔯','𝔰'=>'𝔰','𝔱'=>'𝔱','𝔲'=>'𝔲','𝔳'=>'𝔳','𝔴'=>'𝔴','𝔵'=>'𝔵','𝔶'=>'𝔶','𝔷'=>'𝔷','𝔸'=>'𝔸','𝔹'=>'𝔹','𝔻'=>'𝔻','𝔼'=>'𝔼','𝔽'=>'𝔽','𝔾'=>'𝔾','𝕀'=>'𝕀','𝕁'=>'𝕁','𝕂'=>'𝕂','𝕃'=>'𝕃','𝕄'=>'𝕄','𝕆'=>'𝕆','𝕊'=>'𝕊','𝕋'=>'𝕋','𝕌'=>'𝕌','𝕍'=>'𝕍','𝕎'=>'𝕎','𝕏'=>'𝕏','𝕐'=>'𝕐','𝕒'=>'𝕒','𝕓'=>'𝕓','𝕔'=>'𝕔','𝕕'=>'𝕕','𝕖'=>'𝕖','𝕗'=>'𝕗','𝕘'=>'𝕘','𝕙'=>'𝕙','𝕚'=>'𝕚','𝕛'=>'𝕛','𝕜'=>'𝕜','𝕝'=>'𝕝','𝕞'=>'𝕞','𝕟'=>'𝕟','𝕠'=>'𝕠','𝕡'=>'𝕡','𝕢'=>'𝕢','𝕣'=>'𝕣','𝕤'=>'𝕤','𝕥'=>'𝕥','𝕦'=>'𝕦','𝕧'=>'𝕧','𝕨'=>'𝕨','𝕩'=>'𝕩','𝕪'=>'𝕪','𝕫'=>'𝕫','𝕬'=>'𝕬','𝕭'=>'𝕭','𝕮'=>'𝕮','𝕯'=>'𝕯','𝕰'=>'𝕰','𝕱'=>'𝕱','𝕲'=>'𝕲','𝕳'=>'𝕳','𝕴'=>'𝕴','𝕵'=>'𝕵','𝕶'=>'𝕶','𝕷'=>'𝕷','𝕸'=>'𝕸','𝕹'=>'𝕹','𝕺'=>'𝕺','𝕻'=>'𝕻','𝕼'=>'𝕼','𝕽'=>'𝕽','𝕾'=>'𝕾','𝕿'=>'𝕿','𝖀'=>'𝖀','𝖁'=>'𝖁','𝖂'=>'𝖂','𝖃'=>'𝖃','𝖄'=>'𝖄','𝖅'=>'𝖅','𝖆'=>'𝖆','𝖇'=>'𝖇','𝖈'=>'𝖈','𝖉'=>'𝖉','𝖊'=>'𝖊','𝖋'=>'𝖋','𝖌'=>'𝖌','𝖍'=>'𝖍','𝖎'=>'𝖎','𝖏'=>'𝖏','𝖐'=>'𝖐','𝖑'=>'𝖑','𝖒'=>'𝖒','𝖓'=>'𝖓','𝖔'=>'𝖔','𝖕'=>'𝖕','𝖖'=>'𝖖','𝖗'=>'𝖗','𝖘'=>'𝖘','𝖙'=>'𝖙','𝖚'=>'𝖚','𝖛'=>'𝖛','𝖜'=>'𝖜','𝖝'=>'𝖝','𝖞'=>'𝖞','𝖟'=>'𝖟','𝖠'=>'𝖠','𝖡'=>'𝖡','𝖢'=>'𝖢','𝖣'=>'𝖣','𝖤'=>'𝖤','𝖥'=>'𝖥','𝖦'=>'𝖦','𝖧'=>'𝖧','𝖨'=>'𝖨','𝖩'=>'𝖩','𝖪'=>'𝖪','𝖫'=>'𝖫','𝖬'=>'𝖬','𝖭'=>'𝖭','𝖮'=>'𝖮','𝖯'=>'𝖯','𝖰'=>'𝖰','𝖱'=>'𝖱','𝖲'=>'𝖲','𝖳'=>'𝖳','𝖴'=>'𝖴','𝖵'=>'𝖵','𝖶'=>'𝖶','𝖷'=>'𝖷','𝖸'=>'𝖸','𝖹'=>'𝖹','𝖺'=>'𝖺','𝖻'=>'𝖻','𝖼'=>'𝖼','𝖽'=>'𝖽','𝖾'=>'𝖾','𝖿'=>'𝖿','𝗀'=>'𝗀','𝗁'=>'𝗁','𝗂'=>'𝗂','𝗃'=>'𝗃','𝗄'=>'𝗄','𝗅'=>'𝗅','𝗆'=>'𝗆','𝗇'=>'𝗇','𝗈'=>'𝗈','𝗉'=>'𝗉','𝗊'=>'𝗊','𝗋'=>'𝗋','𝗌'=>'𝗌','𝗍'=>'𝗍','𝗎'=>'𝗎','𝗏'=>'𝗏','𝗐'=>'𝗐','𝗑'=>'𝗑','𝗒'=>'𝗒','𝗓'=>'𝗓','𝗔'=>'𝗔','𝗕'=>'𝗕','𝗖'=>'𝗖','𝗗'=>'𝗗','𝗘'=>'𝗘','𝗙'=>'𝗙','𝗚'=>'𝗚','𝗛'=>'𝗛','𝗜'=>'𝗜','𝗝'=>'𝗝','𝗞'=>'𝗞','𝗟'=>'𝗟','𝗠'=>'𝗠','𝗡'=>'𝗡','𝗢'=>'𝗢','𝗣'=>'𝗣','𝗤'=>'𝗤','𝗥'=>'𝗥','𝗦'=>'𝗦','𝗧'=>'𝗧','𝗨'=>'𝗨','𝗩'=>'𝗩','𝗪'=>'𝗪','𝗫'=>'𝗫','𝗬'=>'𝗬','𝗭'=>'𝗭','𝗮'=>'𝗮','𝗯'=>'𝗯','𝗰'=>'𝗰','𝗱'=>'𝗱','𝗲'=>'𝗲','𝗳'=>'𝗳','𝗴'=>'𝗴','𝗵'=>'𝗵','𝗶'=>'𝗶','𝗷'=>'𝗷','𝗸'=>'𝗸','𝗹'=>'𝗹','𝗺'=>'𝗺','𝗻'=>'𝗻','𝗼'=>'𝗼','𝗽'=>'𝗽','𝗾'=>'𝗾','𝗿'=>'𝗿','𝘀'=>'𝘀','𝘁'=>'𝘁','𝘂'=>'𝘂','𝘃'=>'𝘃','𝘄'=>'𝘄','𝘅'=>'𝘅','𝘆'=>'𝘆','𝘇'=>'𝘇','𝘈'=>'𝘈','𝘉'=>'𝘉','𝘊'=>'𝘊','𝘋'=>'𝘋','𝘌'=>'𝘌','𝘍'=>'𝘍','𝘎'=>'𝘎','𝘏'=>'𝘏','𝘐'=>'𝘐','𝘑'=>'𝘑','𝘒'=>'𝘒','𝘓'=>'𝘓','𝘔'=>'𝘔','𝘕'=>'𝘕','𝘖'=>'𝘖','𝘗'=>'𝘗','𝘘'=>'𝘘','𝘙'=>'𝘙','𝘚'=>'𝘚','𝘛'=>'𝘛','𝘜'=>'𝘜','𝘝'=>'𝘝','𝘞'=>'𝘞','𝘟'=>'𝘟','𝘠'=>'𝘠','𝘡'=>'𝘡','𝘢'=>'𝘢','𝘣'=>'𝘣','𝘤'=>'𝘤','𝘥'=>'𝘥','𝘦'=>'𝘦','𝘧'=>'𝘧','𝘨'=>'𝘨','𝘩'=>'𝘩','𝘪'=>'𝘪','𝘫'=>'𝘫','𝘬'=>'𝘬','𝘭'=>'𝘭','𝘮'=>'𝘮','𝘯'=>'𝘯','𝘰'=>'𝘰','𝘱'=>'𝘱','𝘲'=>'𝘲','𝘳'=>'𝘳','𝘴'=>'𝘴','𝘵'=>'𝘵','𝘶'=>'𝘶','𝘷'=>'𝘷','𝘸'=>'𝘸','𝘹'=>'𝘹','𝘺'=>'𝘺','𝘻'=>'𝘻','𝘼'=>'𝘼','𝘽'=>'𝘽','𝘾'=>'𝘾','𝘿'=>'𝘿','𝙀'=>'𝙀','𝙁'=>'𝙁','𝙂'=>'𝙂','𝙃'=>'𝙃','𝙄'=>'𝙄','𝙅'=>'𝙅','𝙆'=>'𝙆','𝙇'=>'𝙇','𝙈'=>'𝙈','𝙉'=>'𝙉','𝙊'=>'𝙊','𝙋'=>'𝙋','𝙌'=>'𝙌','𝙍'=>'𝙍','𝙎'=>'𝙎','𝙏'=>'𝙏','𝙐'=>'𝙐','𝙑'=>'𝙑','𝙒'=>'𝙒','𝙓'=>'𝙓','𝙔'=>'𝙔','𝙕'=>'𝙕','𝙖'=>'𝙖','𝙗'=>'𝙗','𝙘'=>'𝙘','𝙙'=>'𝙙','𝙚'=>'𝙚','𝙛'=>'𝙛','𝙜'=>'𝙜','𝙝'=>'𝙝','𝙞'=>'𝙞','𝙟'=>'𝙟','𝙠'=>'𝙠','𝙡'=>'𝙡','𝙢'=>'𝙢','𝙣'=>'𝙣','𝙤'=>'𝙤','𝙥'=>'𝙥','𝙦'=>'𝙦','𝙧'=>'𝙧','𝙨'=>'𝙨','𝙩'=>'𝙩','𝙪'=>'𝙪','𝙫'=>'𝙫','𝙬'=>'𝙬','𝙭'=>'𝙭','𝙮'=>'𝙮','𝙯'=>'𝙯','𝙰'=>'𝙰','𝙱'=>'𝙱','𝙲'=>'𝙲','𝙳'=>'𝙳','𝙴'=>'𝙴','𝙵'=>'𝙵','𝙶'=>'𝙶','𝙷'=>'𝙷','𝙸'=>'𝙸','𝙹'=>'𝙹','𝙺'=>'𝙺','𝙻'=>'𝙻','𝙼'=>'𝙼','𝙽'=>'𝙽','𝙾'=>'𝙾','𝙿'=>'𝙿','𝚀'=>'𝚀','𝚁'=>'𝚁','𝚂'=>'𝚂','𝚃'=>'𝚃','𝚄'=>'𝚄','𝚅'=>'𝚅','𝚆'=>'𝚆','𝚇'=>'𝚇','𝚈'=>'𝚈','𝚉'=>'𝚉','𝚊'=>'𝚊','𝚋'=>'𝚋','𝚌'=>'𝚌','𝚍'=>'𝚍','𝚎'=>'𝚎','𝚏'=>'𝚏','𝚐'=>'𝚐','𝚑'=>'𝚑','𝚒'=>'𝚒','𝚓'=>'𝚓','𝚔'=>'𝚔','𝚕'=>'𝚕','𝚖'=>'𝚖','𝚗'=>'𝚗','𝚘'=>'𝚘','𝚙'=>'𝚙','𝚚'=>'𝚚','𝚛'=>'𝚛','𝚜'=>'𝚜','𝚝'=>'𝚝','𝚞'=>'𝚞','𝚟'=>'𝚟','𝚠'=>'𝚠','𝚡'=>'𝚡','𝚢'=>'𝚢','𝚣'=>'𝚣','𝚤'=>'𝚤','𝚥'=>'𝚥','𝚨'=>'𝚨','𝚩'=>'𝚩','𝚪'=>'𝚪','𝚫'=>'𝚫','𝚬'=>'𝚬','𝚭'=>'𝚭','𝚮'=>'𝚮','𝚯'=>'𝚯','𝚰'=>'𝚰','𝚱'=>'𝚱','𝚲'=>'𝚲','𝚳'=>'𝚳','𝚴'=>'𝚴','𝚵'=>'𝚵','𝚶'=>'𝚶','𝚷'=>'𝚷','𝚸'=>'𝚸','𝚹'=>'𝚹','𝚺'=>'𝚺','𝚻'=>'𝚻','𝚼'=>'𝚼','𝚽'=>'𝚽','𝚾'=>'𝚾','𝚿'=>'𝚿','𝛀'=>'𝛀','𝛂'=>'𝛂','𝛃'=>'𝛃','𝛄'=>'𝛄','𝛅'=>'𝛅','𝛆'=>'𝛆','𝛇'=>'𝛇','𝛈'=>'𝛈','𝛉'=>'𝛉','𝛊'=>'𝛊','𝛋'=>'𝛋','𝛌'=>'𝛌','𝛍'=>'𝛍','𝛎'=>'𝛎','𝛏'=>'𝛏','𝛐'=>'𝛐','𝛑'=>'𝛑','𝛒'=>'𝛒','𝛓'=>'𝛓','𝛔'=>'𝛔','𝛕'=>'𝛕','𝛖'=>'𝛖','𝛗'=>'𝛗','𝛘'=>'𝛘','𝛙'=>'𝛙','𝛚'=>'𝛚','𝛜'=>'𝛜','𝛝'=>'𝛝','𝛞'=>'𝛞','𝛟'=>'𝛟','𝛠'=>'𝛠','𝛡'=>'𝛡','𝛢'=>'𝛢','𝛣'=>'𝛣','𝛤'=>'𝛤','𝛥'=>'𝛥','𝛦'=>'𝛦','𝛧'=>'𝛧','𝛨'=>'𝛨','𝛩'=>'𝛩','𝛪'=>'𝛪','𝛫'=>'𝛫','𝛬'=>'𝛬','𝛭'=>'𝛭','𝛮'=>'𝛮','𝛯'=>'𝛯','𝛰'=>'𝛰','𝛱'=>'𝛱','𝛲'=>'𝛲','𝛳'=>'𝛳','𝛴'=>'𝛴','𝛵'=>'𝛵','𝛶'=>'𝛶','𝛷'=>'𝛷','𝛸'=>'𝛸','𝛹'=>'𝛹','𝛺'=>'𝛺','𝛼'=>'𝛼','𝛽'=>'𝛽','𝛾'=>'𝛾','𝛿'=>'𝛿','𝜀'=>'𝜀','𝜁'=>'𝜁','𝜂'=>'𝜂','𝜃'=>'𝜃','𝜄'=>'𝜄','𝜅'=>'𝜅','𝜆'=>'𝜆','𝜇'=>'𝜇','𝜈'=>'𝜈','𝜉'=>'𝜉','𝜊'=>'𝜊','𝜋'=>'𝜋','𝜌'=>'𝜌','𝜍'=>'𝜍','𝜎'=>'𝜎','𝜏'=>'𝜏','𝜐'=>'𝜐','𝜑'=>'𝜑','𝜒'=>'𝜒','𝜓'=>'𝜓','𝜔'=>'𝜔','𝜖'=>'𝜖','𝜗'=>'𝜗','𝜘'=>'𝜘','𝜙'=>'𝜙','𝜚'=>'𝜚','𝜛'=>'𝜛','𝜜'=>'𝜜','𝜝'=>'𝜝','𝜞'=>'𝜞','𝜟'=>'𝜟','𝜠'=>'𝜠','𝜡'=>'𝜡','𝜢'=>'𝜢','𝜣'=>'𝜣','𝜤'=>'𝜤','𝜥'=>'𝜥','𝜦'=>'𝜦','𝜧'=>'𝜧','𝜨'=>'𝜨','𝜩'=>'𝜩','𝜪'=>'𝜪','𝜫'=>'𝜫','𝜬'=>'𝜬','𝜭'=>'𝜭','𝜮'=>'𝜮','𝜯'=>'𝜯','𝜰'=>'𝜰','𝜱'=>'𝜱','𝜲'=>'𝜲','𝜳'=>'𝜳','𝜴'=>'𝜴','𝜶'=>'𝜶','𝜷'=>'𝜷','𝜸'=>'𝜸','𝜹'=>'𝜹','𝜺'=>'𝜺','𝜻'=>'𝜻','𝜼'=>'𝜼','𝜽'=>'𝜽','𝜾'=>'𝜾','𝜿'=>'𝜿','𝝀'=>'𝝀','𝝁'=>'𝝁','𝝂'=>'𝝂','𝝃'=>'𝝃','𝝄'=>'𝝄','𝝅'=>'𝝅','𝝆'=>'𝝆','𝝇'=>'𝝇','𝝈'=>'𝝈','𝝉'=>'𝝉','𝝊'=>'𝝊','𝝋'=>'𝝋','𝝌'=>'𝝌','𝝍'=>'𝝍','𝝎'=>'𝝎','𝝐'=>'𝝐','𝝑'=>'𝝑','𝝒'=>'𝝒','𝝓'=>'𝝓','𝝔'=>'𝝔','𝝕'=>'𝝕','𝝖'=>'𝝖','𝝗'=>'𝝗','𝝘'=>'𝝘','𝝙'=>'𝝙','𝝚'=>'𝝚','𝝛'=>'𝝛','𝝜'=>'𝝜','𝝝'=>'𝝝','𝝞'=>'𝝞','𝝟'=>'𝝟','𝝠'=>'𝝠','𝝡'=>'𝝡','𝝢'=>'𝝢','𝝣'=>'𝝣','𝝤'=>'𝝤','𝝥'=>'𝝥','𝝦'=>'𝝦','𝝧'=>'𝝧','𝝨'=>'𝝨','𝝩'=>'𝝩','𝝪'=>'𝝪','𝝫'=>'𝝫','𝝬'=>'𝝬','𝝭'=>'𝝭','𝝮'=>'𝝮','𝝰'=>'𝝰','𝝱'=>'𝝱','𝝲'=>'𝝲','𝝳'=>'𝝳','𝝴'=>'𝝴','𝝵'=>'𝝵','𝝶'=>'𝝶','𝝷'=>'𝝷','𝝸'=>'𝝸','𝝹'=>'𝝹','𝝺'=>'𝝺','𝝻'=>'𝝻','𝝼'=>'𝝼','𝝽'=>'𝝽','𝝾'=>'𝝾','𝝿'=>'𝝿','𝞀'=>'𝞀','𝞁'=>'𝞁','𝞂'=>'𝞂','𝞃'=>'𝞃','𝞄'=>'𝞄','𝞅'=>'𝞅','𝞆'=>'𝞆','𝞇'=>'𝞇','𝞈'=>'𝞈','𝞊'=>'𝞊','𝞋'=>'𝞋','𝞌'=>'𝞌','𝞍'=>'𝞍','𝞎'=>'𝞎','𝞏'=>'𝞏','𝞐'=>'𝞐','𝞑'=>'𝞑','𝞒'=>'𝞒','𝞓'=>'𝞓','𝞔'=>'𝞔','𝞕'=>'𝞕','𝞖'=>'𝞖','𝞗'=>'𝞗','𝞘'=>'𝞘','𝞙'=>'𝞙','𝞚'=>'𝞚','𝞛'=>'𝞛','𝞜'=>'𝞜','𝞝'=>'𝞝','𝞞'=>'𝞞','𝞟'=>'𝞟','𝞠'=>'𝞠','𝞡'=>'𝞡','𝞢'=>'𝞢','𝞣'=>'𝞣','𝞤'=>'𝞤','𝞥'=>'𝞥','𝞦'=>'𝞦','𝞧'=>'𝞧','𝞨'=>'𝞨','𝞪'=>'𝞪','𝞫'=>'𝞫','𝞬'=>'𝞬','𝞭'=>'𝞭','𝞮'=>'𝞮','𝞯'=>'𝞯','𝞰'=>'𝞰','𝞱'=>'𝞱','𝞲'=>'𝞲','𝞳'=>'𝞳','𝞴'=>'𝞴','𝞵'=>'𝞵','𝞶'=>'𝞶','𝞷'=>'𝞷','𝞸'=>'𝞸','𝞹'=>'𝞹','𝞺'=>'𝞺','𝞻'=>'𝞻','𝞼'=>'𝞼','𝞽'=>'𝞽','𝞾'=>'𝞾','𝞿'=>'𝞿','𝟀'=>'𝟀','𝟁'=>'𝟁','𝟂'=>'𝟂','𝟄'=>'𝟄','𝟅'=>'𝟅','𝟆'=>'𝟆','𝟇'=>'𝟇','𝟈'=>'𝟈','𝟉'=>'𝟉','𝟊'=>'𝟊','𝟋'=>'𝟋','𝟎'=>'0','𝟏'=>'1','𝟐'=>'2','𝟑'=>'3','𝟒'=>'4','𝟓'=>'5','𝟔'=>'6','𝟕'=>'7','𝟖'=>'8','𝟗'=>'9','𝟘'=>'0','𝟙'=>'1','𝟚'=>'2','𝟛'=>'3','𝟜'=>'4','𝟝'=>'5','𝟞'=>'6','𝟟'=>'7','𝟠'=>'8','𝟡'=>'9','𝟢'=>'0','𝟣'=>'1','𝟤'=>'2','𝟥'=>'3','𝟦'=>'4','𝟧'=>'5','𝟨'=>'6','𝟩'=>'7','𝟪'=>'8','𝟫'=>'9','𝟬'=>'0','𝟭'=>'1','𝟮'=>'2','𝟯'=>'3','𝟰'=>'4','𝟱'=>'5','𝟲'=>'6','𝟳'=>'7','𝟴'=>'8','𝟵'=>'9','𝟶'=>'0','𝟷'=>'1','𝟸'=>'2','𝟹'=>'3','𝟺'=>'4','𝟻'=>'5','𝟼'=>'6','𝟽'=>'7','𝟾'=>'8','𝟿'=>'9');
\ No newline at end of file +<?php return array('𝅥'=>'𝅥','𝅦'=>'𝅦','𝅧'=>'𝅧','𝅨'=>'𝅨','𝅩'=>'𝅩','𝅭'=>'𝅭','𝅮'=>'𝅮','𝅯'=>'𝅯','𝅰'=>'𝅰','𝅱'=>'𝅱','𝅲'=>'𝅲','𝅻'=>'𝅻','𝅼'=>'𝅼','𝅽'=>'𝅽','𝅾'=>'𝅾','𝅿'=>'𝅿','𝆀'=>'𝆀','𝆁'=>'𝆁','𝆂'=>'𝆂','𝆅'=>'𝆅','𝆆'=>'𝆆','𝆇'=>'𝆇','𝆈'=>'𝆈','𝆉'=>'𝆉','𝆊'=>'𝆊','𝆋'=>'𝆋','𝆪'=>'𝆪','𝆫'=>'𝆫','𝆬'=>'𝆬','𝆭'=>'𝆭','𝉂'=>'𝉂','𝉃'=>'𝉃','𝉄'=>'𝉄','𝍠'=>'1','𝍡'=>'2','𝍢'=>'3','𝍣'=>'4','𝍤'=>'5','𝍥'=>'6','𝍦'=>'7','𝍧'=>'8','𝍨'=>'9','𝍩'=>'10','𝍪'=>'20','𝍫'=>'30','𝍬'=>'40','𝍭'=>'50','𝍮'=>'60','𝍯'=>'70','𝍰'=>'80','𝍱'=>'90','𝐀'=>'𝐀','𝐁'=>'𝐁','𝐂'=>'𝐂','𝐃'=>'𝐃','𝐄'=>'𝐄','𝐅'=>'𝐅','𝐆'=>'𝐆','𝐇'=>'𝐇','𝐈'=>'𝐈','𝐉'=>'𝐉','𝐊'=>'𝐊','𝐋'=>'𝐋','𝐌'=>'𝐌','𝐍'=>'𝐍','𝐎'=>'𝐎','𝐏'=>'𝐏','𝐐'=>'𝐐','𝐑'=>'𝐑','𝐒'=>'𝐒','𝐓'=>'𝐓','𝐔'=>'𝐔','𝐕'=>'𝐕','𝐖'=>'𝐖','𝐗'=>'𝐗','𝐘'=>'𝐘','𝐙'=>'𝐙','𝐚'=>'𝐚','𝐛'=>'𝐛','𝐜'=>'𝐜','𝐝'=>'𝐝','𝐞'=>'𝐞','𝐟'=>'𝐟','𝐠'=>'𝐠','𝐡'=>'𝐡','𝐢'=>'𝐢','𝐣'=>'𝐣','𝐤'=>'𝐤','𝐥'=>'𝐥','𝐦'=>'𝐦','𝐧'=>'𝐧','𝐨'=>'𝐨','𝐩'=>'𝐩','𝐪'=>'𝐪','𝐫'=>'𝐫','𝐬'=>'𝐬','𝐭'=>'𝐭','𝐮'=>'𝐮','𝐯'=>'𝐯','𝐰'=>'𝐰','𝐱'=>'𝐱','𝐲'=>'𝐲','𝐳'=>'𝐳','𝐴'=>'𝐴','𝐵'=>'𝐵','𝐶'=>'𝐶','𝐷'=>'𝐷','𝐸'=>'𝐸','𝐹'=>'𝐹','𝐺'=>'𝐺','𝐻'=>'𝐻','𝐼'=>'𝐼','𝐽'=>'𝐽','𝐾'=>'𝐾','𝐿'=>'𝐿','𝑀'=>'𝑀','𝑁'=>'𝑁','𝑂'=>'𝑂','𝑃'=>'𝑃','𝑄'=>'𝑄','𝑅'=>'𝑅','𝑆'=>'𝑆','𝑇'=>'𝑇','𝑈'=>'𝑈','𝑉'=>'𝑉','𝑊'=>'𝑊','𝑋'=>'𝑋','𝑌'=>'𝑌','𝑍'=>'𝑍','𝑎'=>'𝑎','𝑏'=>'𝑏','𝑐'=>'𝑐','𝑑'=>'𝑑','𝑒'=>'𝑒','𝑓'=>'𝑓','𝑔'=>'𝑔','𝑖'=>'𝑖','𝑗'=>'𝑗','𝑘'=>'𝑘','𝑙'=>'𝑙','𝑚'=>'𝑚','𝑛'=>'𝑛','𝑜'=>'𝑜','𝑝'=>'𝑝','𝑞'=>'𝑞','𝑟'=>'𝑟','𝑠'=>'𝑠','𝑡'=>'𝑡','𝑢'=>'𝑢','𝑣'=>'𝑣','𝑤'=>'𝑤','𝑥'=>'𝑥','𝑦'=>'𝑦','𝑧'=>'𝑧','𝑨'=>'𝑨','𝑩'=>'𝑩','𝑪'=>'𝑪','𝑫'=>'𝑫','𝑬'=>'𝑬','𝑭'=>'𝑭','𝑮'=>'𝑮','𝑯'=>'𝑯','𝑰'=>'𝑰','𝑱'=>'𝑱','𝑲'=>'𝑲','𝑳'=>'𝑳','𝑴'=>'𝑴','𝑵'=>'𝑵','𝑶'=>'𝑶','𝑷'=>'𝑷','𝑸'=>'𝑸','𝑹'=>'𝑹','𝑺'=>'𝑺','𝑻'=>'𝑻','𝑼'=>'𝑼','𝑽'=>'𝑽','𝑾'=>'𝑾','𝑿'=>'𝑿','𝒀'=>'𝒀','𝒁'=>'𝒁','𝒂'=>'𝒂','𝒃'=>'𝒃','𝒄'=>'𝒄','𝒅'=>'𝒅','𝒆'=>'𝒆','𝒇'=>'𝒇','𝒈'=>'𝒈','𝒉'=>'𝒉','𝒊'=>'𝒊','𝒋'=>'𝒋','𝒌'=>'𝒌','𝒍'=>'𝒍','𝒎'=>'𝒎','𝒏'=>'𝒏','𝒐'=>'𝒐','𝒑'=>'𝒑','𝒒'=>'𝒒','𝒓'=>'𝒓','𝒔'=>'𝒔','𝒕'=>'𝒕','𝒖'=>'𝒖','𝒗'=>'𝒗','𝒘'=>'𝒘','𝒙'=>'𝒙','𝒚'=>'𝒚','𝒛'=>'𝒛','𝒜'=>'𝒜','𝒞'=>'𝒞','𝒟'=>'𝒟','𝒢'=>'𝒢','𝒥'=>'𝒥','𝒦'=>'𝒦','𝒩'=>'𝒩','𝒪'=>'𝒪','𝒫'=>'𝒫','𝒬'=>'𝒬','𝒮'=>'𝒮','𝒯'=>'𝒯','𝒰'=>'𝒰','𝒱'=>'𝒱','𝒲'=>'𝒲','𝒳'=>'𝒳','𝒴'=>'𝒴','𝒵'=>'𝒵','𝒶'=>'𝒶','𝒷'=>'𝒷','𝒸'=>'𝒸','𝒹'=>'𝒹','𝒻'=>'𝒻','𝒽'=>'𝒽','𝒾'=>'𝒾','𝒿'=>'𝒿','𝓀'=>'𝓀','𝓁'=>'𝓁','𝓂'=>'𝓂','𝓃'=>'𝓃','𝓅'=>'𝓅','𝓆'=>'𝓆','𝓇'=>'𝓇','𝓈'=>'𝓈','𝓉'=>'𝓉','𝓊'=>'𝓊','𝓋'=>'𝓋','𝓌'=>'𝓌','𝓍'=>'𝓍','𝓎'=>'𝓎','𝓏'=>'𝓏','𝓐'=>'𝓐','𝓑'=>'𝓑','𝓒'=>'𝓒','𝓓'=>'𝓓','𝓔'=>'𝓔','𝓕'=>'𝓕','𝓖'=>'𝓖','𝓗'=>'𝓗','𝓘'=>'𝓘','𝓙'=>'𝓙','𝓚'=>'𝓚','𝓛'=>'𝓛','𝓜'=>'𝓜','𝓝'=>'𝓝','𝓞'=>'𝓞','𝓟'=>'𝓟','𝓠'=>'𝓠','𝓡'=>'𝓡','𝓢'=>'𝓢','𝓣'=>'𝓣','𝓤'=>'𝓤','𝓥'=>'𝓥','𝓦'=>'𝓦','𝓧'=>'𝓧','𝓨'=>'𝓨','𝓩'=>'𝓩','𝓪'=>'𝓪','𝓫'=>'𝓫','𝓬'=>'𝓬','𝓭'=>'𝓭','𝓮'=>'𝓮','𝓯'=>'𝓯','𝓰'=>'𝓰','𝓱'=>'𝓱','𝓲'=>'𝓲','𝓳'=>'𝓳','𝓴'=>'𝓴','𝓵'=>'𝓵','𝓶'=>'𝓶','𝓷'=>'𝓷','𝓸'=>'𝓸','𝓹'=>'𝓹','𝓺'=>'𝓺','𝓻'=>'𝓻','𝓼'=>'𝓼','𝓽'=>'𝓽','𝓾'=>'𝓾','𝓿'=>'𝓿','𝔀'=>'𝔀','𝔁'=>'𝔁','𝔂'=>'𝔂','𝔃'=>'𝔃','𝔄'=>'𝔄','𝔅'=>'𝔅','𝔇'=>'𝔇','𝔈'=>'𝔈','𝔉'=>'𝔉','𝔊'=>'𝔊','𝔍'=>'𝔍','𝔎'=>'𝔎','𝔏'=>'𝔏','𝔐'=>'𝔐','𝔑'=>'𝔑','𝔒'=>'𝔒','𝔓'=>'𝔓','𝔔'=>'𝔔','𝔖'=>'𝔖','𝔗'=>'𝔗','𝔘'=>'𝔘','𝔙'=>'𝔙','𝔚'=>'𝔚','𝔛'=>'𝔛','𝔜'=>'𝔜','𝔞'=>'𝔞','𝔟'=>'𝔟','𝔠'=>'𝔠','𝔡'=>'𝔡','𝔢'=>'𝔢','𝔣'=>'𝔣','𝔤'=>'𝔤','𝔥'=>'𝔥','𝔦'=>'𝔦','𝔧'=>'𝔧','𝔨'=>'𝔨','𝔩'=>'𝔩','𝔪'=>'𝔪','𝔫'=>'𝔫','𝔬'=>'𝔬','𝔭'=>'𝔭','𝔮'=>'𝔮','𝔯'=>'𝔯','𝔰'=>'𝔰','𝔱'=>'𝔱','𝔲'=>'𝔲','𝔳'=>'𝔳','𝔴'=>'𝔴','𝔵'=>'𝔵','𝔶'=>'𝔶','𝔷'=>'𝔷','𝔸'=>'𝔸','𝔹'=>'𝔹','𝔻'=>'𝔻','𝔼'=>'𝔼','𝔽'=>'𝔽','𝔾'=>'𝔾','𝕀'=>'𝕀','𝕁'=>'𝕁','𝕂'=>'𝕂','𝕃'=>'𝕃','𝕄'=>'𝕄','𝕆'=>'𝕆','𝕊'=>'𝕊','𝕋'=>'𝕋','𝕌'=>'𝕌','𝕍'=>'𝕍','𝕎'=>'𝕎','𝕏'=>'𝕏','𝕐'=>'𝕐','𝕒'=>'𝕒','𝕓'=>'𝕓','𝕔'=>'𝕔','𝕕'=>'𝕕','𝕖'=>'𝕖','𝕗'=>'𝕗','𝕘'=>'𝕘','𝕙'=>'𝕙','𝕚'=>'𝕚','𝕛'=>'𝕛','𝕜'=>'𝕜','𝕝'=>'𝕝','𝕞'=>'𝕞','𝕟'=>'𝕟','𝕠'=>'𝕠','𝕡'=>'𝕡','𝕢'=>'𝕢','𝕣'=>'𝕣','𝕤'=>'𝕤','𝕥'=>'𝕥','𝕦'=>'𝕦','𝕧'=>'𝕧','𝕨'=>'𝕨','𝕩'=>'𝕩','𝕪'=>'𝕪','𝕫'=>'𝕫','𝕬'=>'𝕬','𝕭'=>'𝕭','𝕮'=>'𝕮','𝕯'=>'𝕯','𝕰'=>'𝕰','𝕱'=>'𝕱','𝕲'=>'𝕲','𝕳'=>'𝕳','𝕴'=>'𝕴','𝕵'=>'𝕵','𝕶'=>'𝕶','𝕷'=>'𝕷','𝕸'=>'𝕸','𝕹'=>'𝕹','𝕺'=>'𝕺','𝕻'=>'𝕻','𝕼'=>'𝕼','𝕽'=>'𝕽','𝕾'=>'𝕾','𝕿'=>'𝕿','𝖀'=>'𝖀','𝖁'=>'𝖁','𝖂'=>'𝖂','𝖃'=>'𝖃','𝖄'=>'𝖄','𝖅'=>'𝖅','𝖆'=>'𝖆','𝖇'=>'𝖇','𝖈'=>'𝖈','𝖉'=>'𝖉','𝖊'=>'𝖊','𝖋'=>'𝖋','𝖌'=>'𝖌','𝖍'=>'𝖍','𝖎'=>'𝖎','𝖏'=>'𝖏','𝖐'=>'𝖐','𝖑'=>'𝖑','𝖒'=>'𝖒','𝖓'=>'𝖓','𝖔'=>'𝖔','𝖕'=>'𝖕','𝖖'=>'𝖖','𝖗'=>'𝖗','𝖘'=>'𝖘','𝖙'=>'𝖙','𝖚'=>'𝖚','𝖛'=>'𝖛','𝖜'=>'𝖜','𝖝'=>'𝖝','𝖞'=>'𝖞','𝖟'=>'𝖟','𝖠'=>'𝖠','𝖡'=>'𝖡','𝖢'=>'𝖢','𝖣'=>'𝖣','𝖤'=>'𝖤','𝖥'=>'𝖥','𝖦'=>'𝖦','𝖧'=>'𝖧','𝖨'=>'𝖨','𝖩'=>'𝖩','𝖪'=>'𝖪','𝖫'=>'𝖫','𝖬'=>'𝖬','𝖭'=>'𝖭','𝖮'=>'𝖮','𝖯'=>'𝖯','𝖰'=>'𝖰','𝖱'=>'𝖱','𝖲'=>'𝖲','𝖳'=>'𝖳','𝖴'=>'𝖴','𝖵'=>'𝖵','𝖶'=>'𝖶','𝖷'=>'𝖷','𝖸'=>'𝖸','𝖹'=>'𝖹','𝖺'=>'𝖺','𝖻'=>'𝖻','𝖼'=>'𝖼','𝖽'=>'𝖽','𝖾'=>'𝖾','𝖿'=>'𝖿','𝗀'=>'𝗀','𝗁'=>'𝗁','𝗂'=>'𝗂','𝗃'=>'𝗃','𝗄'=>'𝗄','𝗅'=>'𝗅','𝗆'=>'𝗆','𝗇'=>'𝗇','𝗈'=>'𝗈','𝗉'=>'𝗉','𝗊'=>'𝗊','𝗋'=>'𝗋','𝗌'=>'𝗌','𝗍'=>'𝗍','𝗎'=>'𝗎','𝗏'=>'𝗏','𝗐'=>'𝗐','𝗑'=>'𝗑','𝗒'=>'𝗒','𝗓'=>'𝗓','𝗔'=>'𝗔','𝗕'=>'𝗕','𝗖'=>'𝗖','𝗗'=>'𝗗','𝗘'=>'𝗘','𝗙'=>'𝗙','𝗚'=>'𝗚','𝗛'=>'𝗛','𝗜'=>'𝗜','𝗝'=>'𝗝','𝗞'=>'𝗞','𝗟'=>'𝗟','𝗠'=>'𝗠','𝗡'=>'𝗡','𝗢'=>'𝗢','𝗣'=>'𝗣','𝗤'=>'𝗤','𝗥'=>'𝗥','𝗦'=>'𝗦','𝗧'=>'𝗧','𝗨'=>'𝗨','𝗩'=>'𝗩','𝗪'=>'𝗪','𝗫'=>'𝗫','𝗬'=>'𝗬','𝗭'=>'𝗭','𝗮'=>'𝗮','𝗯'=>'𝗯','𝗰'=>'𝗰','𝗱'=>'𝗱','𝗲'=>'𝗲','𝗳'=>'𝗳','𝗴'=>'𝗴','𝗵'=>'𝗵','𝗶'=>'𝗶','𝗷'=>'𝗷','𝗸'=>'𝗸','𝗹'=>'𝗹','𝗺'=>'𝗺','𝗻'=>'𝗻','𝗼'=>'𝗼','𝗽'=>'𝗽','𝗾'=>'𝗾','𝗿'=>'𝗿','𝘀'=>'𝘀','𝘁'=>'𝘁','𝘂'=>'𝘂','𝘃'=>'𝘃','𝘄'=>'𝘄','𝘅'=>'𝘅','𝘆'=>'𝘆','𝘇'=>'𝘇','𝘈'=>'𝘈','𝘉'=>'𝘉','𝘊'=>'𝘊','𝘋'=>'𝘋','𝘌'=>'𝘌','𝘍'=>'𝘍','𝘎'=>'𝘎','𝘏'=>'𝘏','𝘐'=>'𝘐','𝘑'=>'𝘑','𝘒'=>'𝘒','𝘓'=>'𝘓','𝘔'=>'𝘔','𝘕'=>'𝘕','𝘖'=>'𝘖','𝘗'=>'𝘗','𝘘'=>'𝘘','𝘙'=>'𝘙','𝘚'=>'𝘚','𝘛'=>'𝘛','𝘜'=>'𝘜','𝘝'=>'𝘝','𝘞'=>'𝘞','𝘟'=>'𝘟','𝘠'=>'𝘠','𝘡'=>'𝘡','𝘢'=>'𝘢','𝘣'=>'𝘣','𝘤'=>'𝘤','𝘥'=>'𝘥','𝘦'=>'𝘦','𝘧'=>'𝘧','𝘨'=>'𝘨','𝘩'=>'𝘩','𝘪'=>'𝘪','𝘫'=>'𝘫','𝘬'=>'𝘬','𝘭'=>'𝘭','𝘮'=>'𝘮','𝘯'=>'𝘯','𝘰'=>'𝘰','𝘱'=>'𝘱','𝘲'=>'𝘲','𝘳'=>'𝘳','𝘴'=>'𝘴','𝘵'=>'𝘵','𝘶'=>'𝘶','𝘷'=>'𝘷','𝘸'=>'𝘸','𝘹'=>'𝘹','𝘺'=>'𝘺','𝘻'=>'𝘻','𝘼'=>'𝘼','𝘽'=>'𝘽','𝘾'=>'𝘾','𝘿'=>'𝘿','𝙀'=>'𝙀','𝙁'=>'𝙁','𝙂'=>'𝙂','𝙃'=>'𝙃','𝙄'=>'𝙄','𝙅'=>'𝙅','𝙆'=>'𝙆','𝙇'=>'𝙇','𝙈'=>'𝙈','𝙉'=>'𝙉','𝙊'=>'𝙊','𝙋'=>'𝙋','𝙌'=>'𝙌','𝙍'=>'𝙍','𝙎'=>'𝙎','𝙏'=>'𝙏','𝙐'=>'𝙐','𝙑'=>'𝙑','𝙒'=>'𝙒','𝙓'=>'𝙓','𝙔'=>'𝙔','𝙕'=>'𝙕','𝙖'=>'𝙖','𝙗'=>'𝙗','𝙘'=>'𝙘','𝙙'=>'𝙙','𝙚'=>'𝙚','𝙛'=>'𝙛','𝙜'=>'𝙜','𝙝'=>'𝙝','𝙞'=>'𝙞','𝙟'=>'𝙟','𝙠'=>'𝙠','𝙡'=>'𝙡','𝙢'=>'𝙢','𝙣'=>'𝙣','𝙤'=>'𝙤','𝙥'=>'𝙥','𝙦'=>'𝙦','𝙧'=>'𝙧','𝙨'=>'𝙨','𝙩'=>'𝙩','𝙪'=>'𝙪','𝙫'=>'𝙫','𝙬'=>'𝙬','𝙭'=>'𝙭','𝙮'=>'𝙮','𝙯'=>'𝙯','𝙰'=>'𝙰','𝙱'=>'𝙱','𝙲'=>'𝙲','𝙳'=>'𝙳','𝙴'=>'𝙴','𝙵'=>'𝙵','𝙶'=>'𝙶','𝙷'=>'𝙷','𝙸'=>'𝙸','𝙹'=>'𝙹','𝙺'=>'𝙺','𝙻'=>'𝙻','𝙼'=>'𝙼','𝙽'=>'𝙽','𝙾'=>'𝙾','𝙿'=>'𝙿','𝚀'=>'𝚀','𝚁'=>'𝚁','𝚂'=>'𝚂','𝚃'=>'𝚃','𝚄'=>'𝚄','𝚅'=>'𝚅','𝚆'=>'𝚆','𝚇'=>'𝚇','𝚈'=>'𝚈','𝚉'=>'𝚉','𝚊'=>'𝚊','𝚋'=>'𝚋','𝚌'=>'𝚌','𝚍'=>'𝚍','𝚎'=>'𝚎','𝚏'=>'𝚏','𝚐'=>'𝚐','𝚑'=>'𝚑','𝚒'=>'𝚒','𝚓'=>'𝚓','𝚔'=>'𝚔','𝚕'=>'𝚕','𝚖'=>'𝚖','𝚗'=>'𝚗','𝚘'=>'𝚘','𝚙'=>'𝚙','𝚚'=>'𝚚','𝚛'=>'𝚛','𝚜'=>'𝚜','𝚝'=>'𝚝','𝚞'=>'𝚞','𝚟'=>'𝚟','𝚠'=>'𝚠','𝚡'=>'𝚡','𝚢'=>'𝚢','𝚣'=>'𝚣','𝚤'=>'𝚤','𝚥'=>'𝚥','𝚨'=>'𝚨','𝚩'=>'𝚩','𝚪'=>'𝚪','𝚫'=>'𝚫','𝚬'=>'𝚬','𝚭'=>'𝚭','𝚮'=>'𝚮','𝚯'=>'𝚯','𝚰'=>'𝚰','𝚱'=>'𝚱','𝚲'=>'𝚲','𝚳'=>'𝚳','𝚴'=>'𝚴','𝚵'=>'𝚵','𝚶'=>'𝚶','𝚷'=>'𝚷','𝚸'=>'𝚸','𝚹'=>'𝚹','𝚺'=>'𝚺','𝚻'=>'𝚻','𝚼'=>'𝚼','𝚽'=>'𝚽','𝚾'=>'𝚾','𝚿'=>'𝚿','𝛀'=>'𝛀','𝛂'=>'𝛂','𝛃'=>'𝛃','𝛄'=>'𝛄','𝛅'=>'𝛅','𝛆'=>'𝛆','𝛇'=>'𝛇','𝛈'=>'𝛈','𝛉'=>'𝛉','𝛊'=>'𝛊','𝛋'=>'𝛋','𝛌'=>'𝛌','𝛍'=>'𝛍','𝛎'=>'𝛎','𝛏'=>'𝛏','𝛐'=>'𝛐','𝛑'=>'𝛑','𝛒'=>'𝛒','𝛓'=>'𝛓','𝛔'=>'𝛔','𝛕'=>'𝛕','𝛖'=>'𝛖','𝛗'=>'𝛗','𝛘'=>'𝛘','𝛙'=>'𝛙','𝛚'=>'𝛚','𝛜'=>'𝛜','𝛝'=>'𝛝','𝛞'=>'𝛞','𝛟'=>'𝛟','𝛠'=>'𝛠','𝛡'=>'𝛡','𝛢'=>'𝛢','𝛣'=>'𝛣','𝛤'=>'𝛤','𝛥'=>'𝛥','𝛦'=>'𝛦','𝛧'=>'𝛧','𝛨'=>'𝛨','𝛩'=>'𝛩','𝛪'=>'𝛪','𝛫'=>'𝛫','𝛬'=>'𝛬','𝛭'=>'𝛭','𝛮'=>'𝛮','𝛯'=>'𝛯','𝛰'=>'𝛰','𝛱'=>'𝛱','𝛲'=>'𝛲','𝛳'=>'𝛳','𝛴'=>'𝛴','𝛵'=>'𝛵','𝛶'=>'𝛶','𝛷'=>'𝛷','𝛸'=>'𝛸','𝛹'=>'𝛹','𝛺'=>'𝛺','𝛼'=>'𝛼','𝛽'=>'𝛽','𝛾'=>'𝛾','𝛿'=>'𝛿','𝜀'=>'𝜀','𝜁'=>'𝜁','𝜂'=>'𝜂','𝜃'=>'𝜃','𝜄'=>'𝜄','𝜅'=>'𝜅','𝜆'=>'𝜆','𝜇'=>'𝜇','𝜈'=>'𝜈','𝜉'=>'𝜉','𝜊'=>'𝜊','𝜋'=>'𝜋','𝜌'=>'𝜌','𝜍'=>'𝜍','𝜎'=>'𝜎','𝜏'=>'𝜏','𝜐'=>'𝜐','𝜑'=>'𝜑','𝜒'=>'𝜒','𝜓'=>'𝜓','𝜔'=>'𝜔','𝜖'=>'𝜖','𝜗'=>'𝜗','𝜘'=>'𝜘','𝜙'=>'𝜙','𝜚'=>'𝜚','𝜛'=>'𝜛','𝜜'=>'𝜜','𝜝'=>'𝜝','𝜞'=>'𝜞','𝜟'=>'𝜟','𝜠'=>'𝜠','𝜡'=>'𝜡','𝜢'=>'𝜢','𝜣'=>'𝜣','𝜤'=>'𝜤','𝜥'=>'𝜥','𝜦'=>'𝜦','𝜧'=>'𝜧','𝜨'=>'𝜨','𝜩'=>'𝜩','𝜪'=>'𝜪','𝜫'=>'𝜫','𝜬'=>'𝜬','𝜭'=>'𝜭','𝜮'=>'𝜮','𝜯'=>'𝜯','𝜰'=>'𝜰','𝜱'=>'𝜱','𝜲'=>'𝜲','𝜳'=>'𝜳','𝜴'=>'𝜴','𝜶'=>'𝜶','𝜷'=>'𝜷','𝜸'=>'𝜸','𝜹'=>'𝜹','𝜺'=>'𝜺','𝜻'=>'𝜻','𝜼'=>'𝜼','𝜽'=>'𝜽','𝜾'=>'𝜾','𝜿'=>'𝜿','𝝀'=>'𝝀','𝝁'=>'𝝁','𝝂'=>'𝝂','𝝃'=>'𝝃','𝝄'=>'𝝄','𝝅'=>'𝝅','𝝆'=>'𝝆','𝝇'=>'𝝇','𝝈'=>'𝝈','𝝉'=>'𝝉','𝝊'=>'𝝊','𝝋'=>'𝝋','𝝌'=>'𝝌','𝝍'=>'𝝍','𝝎'=>'𝝎','𝝐'=>'𝝐','𝝑'=>'𝝑','𝝒'=>'𝝒','𝝓'=>'𝝓','𝝔'=>'𝝔','𝝕'=>'𝝕','𝝖'=>'𝝖','𝝗'=>'𝝗','𝝘'=>'𝝘','𝝙'=>'𝝙','𝝚'=>'𝝚','𝝛'=>'𝝛','𝝜'=>'𝝜','𝝝'=>'𝝝','𝝞'=>'𝝞','𝝟'=>'𝝟','𝝠'=>'𝝠','𝝡'=>'𝝡','𝝢'=>'𝝢','𝝣'=>'𝝣','𝝤'=>'𝝤','𝝥'=>'𝝥','𝝦'=>'𝝦','𝝧'=>'𝝧','𝝨'=>'𝝨','𝝩'=>'𝝩','𝝪'=>'𝝪','𝝫'=>'𝝫','𝝬'=>'𝝬','𝝭'=>'𝝭','𝝮'=>'𝝮','𝝰'=>'𝝰','𝝱'=>'𝝱','𝝲'=>'𝝲','𝝳'=>'𝝳','𝝴'=>'𝝴','𝝵'=>'𝝵','𝝶'=>'𝝶','𝝷'=>'𝝷','𝝸'=>'𝝸','𝝹'=>'𝝹','𝝺'=>'𝝺','𝝻'=>'𝝻','𝝼'=>'𝝼','𝝽'=>'𝝽','𝝾'=>'𝝾','𝝿'=>'𝝿','𝞀'=>'𝞀','𝞁'=>'𝞁','𝞂'=>'𝞂','𝞃'=>'𝞃','𝞄'=>'𝞄','𝞅'=>'𝞅','𝞆'=>'𝞆','𝞇'=>'𝞇','𝞈'=>'𝞈','𝞊'=>'𝞊','𝞋'=>'𝞋','𝞌'=>'𝞌','𝞍'=>'𝞍','𝞎'=>'𝞎','𝞏'=>'𝞏','𝞐'=>'𝞐','𝞑'=>'𝞑','𝞒'=>'𝞒','𝞓'=>'𝞓','𝞔'=>'𝞔','𝞕'=>'𝞕','𝞖'=>'𝞖','𝞗'=>'𝞗','𝞘'=>'𝞘','𝞙'=>'𝞙','𝞚'=>'𝞚','𝞛'=>'𝞛','𝞜'=>'𝞜','𝞝'=>'𝞝','𝞞'=>'𝞞','𝞟'=>'𝞟','𝞠'=>'𝞠','𝞡'=>'𝞡','𝞢'=>'𝞢','𝞣'=>'𝞣','𝞤'=>'𝞤','𝞥'=>'𝞥','𝞦'=>'𝞦','𝞧'=>'𝞧','𝞨'=>'𝞨','𝞪'=>'𝞪','𝞫'=>'𝞫','𝞬'=>'𝞬','𝞭'=>'𝞭','𝞮'=>'𝞮','𝞯'=>'𝞯','𝞰'=>'𝞰','𝞱'=>'𝞱','𝞲'=>'𝞲','𝞳'=>'𝞳','𝞴'=>'𝞴','𝞵'=>'𝞵','𝞶'=>'𝞶','𝞷'=>'𝞷','𝞸'=>'𝞸','𝞹'=>'𝞹','𝞺'=>'𝞺','𝞻'=>'𝞻','𝞼'=>'𝞼','𝞽'=>'𝞽','𝞾'=>'𝞾','𝞿'=>'𝞿','𝟀'=>'𝟀','𝟁'=>'𝟁','𝟂'=>'𝟂','𝟄'=>'𝟄','𝟅'=>'𝟅','𝟆'=>'𝟆','𝟇'=>'𝟇','𝟈'=>'𝟈','𝟉'=>'𝟉','𝟊'=>'𝟊','𝟋'=>'𝟋','𝟎'=>'0','𝟏'=>'1','𝟐'=>'2','𝟑'=>'3','𝟒'=>'4','𝟓'=>'5','𝟔'=>'6','𝟕'=>'7','𝟖'=>'8','𝟗'=>'9','𝟘'=>'0','𝟙'=>'1','𝟚'=>'2','𝟛'=>'3','𝟜'=>'4','𝟝'=>'5','𝟞'=>'6','𝟟'=>'7','𝟠'=>'8','𝟡'=>'9','𝟢'=>'0','𝟣'=>'1','𝟤'=>'2','𝟥'=>'3','𝟦'=>'4','𝟧'=>'5','𝟨'=>'6','𝟩'=>'7','𝟪'=>'8','𝟫'=>'9','𝟬'=>'0','𝟭'=>'1','𝟮'=>'2','𝟯'=>'3','𝟰'=>'4','𝟱'=>'5','𝟲'=>'6','𝟳'=>'7','𝟴'=>'8','𝟵'=>'9','𝟶'=>'0','𝟷'=>'1','𝟸'=>'2','𝟹'=>'3','𝟺'=>'4','𝟻'=>'5','𝟼'=>'6','𝟽'=>'7','𝟾'=>'8','𝟿'=>'9'); diff --git a/phpBB/includes/utf/data/search_indexer_6.php b/phpBB/includes/utf/data/search_indexer_6.php index f6d2ac0665..1ccce03a51 100644 --- a/phpBB/includes/utf/data/search_indexer_6.php +++ b/phpBB/includes/utf/data/search_indexer_6.php @@ -1 +1 @@ -<?php return array('々'=>'々','〆'=>'〆','〇'=>'0','〡'=>'1','〢'=>'2','〣'=>'3','〤'=>'4','〥'=>'5','〦'=>'6','〧'=>'7','〨'=>'8','〩'=>'9','〪'=>'〪','〫'=>'〫','〬'=>'〬','〭'=>'〭','〮'=>'〮','〯'=>'〯','〱'=>'〱','〲'=>'〲','〳'=>'〳','〴'=>'〴','〵'=>'〵','〸'=>'10','〹'=>'20','〺'=>'30','〻'=>'〻','〼'=>'〼','ぁ'=>'ぁ','あ'=>'あ','ぃ'=>'ぃ','い'=>'い','ぅ'=>'ぅ','う'=>'う','ぇ'=>'ぇ','え'=>'え','ぉ'=>'ぉ','お'=>'お','か'=>'か','が'=>'が','き'=>'き','ぎ'=>'ぎ','く'=>'く','ぐ'=>'ぐ','け'=>'け','げ'=>'げ','こ'=>'こ','ご'=>'ご','さ'=>'さ','ざ'=>'ざ','し'=>'し','じ'=>'じ','す'=>'す','ず'=>'ず','せ'=>'せ','ぜ'=>'ぜ','そ'=>'そ','ぞ'=>'ぞ','た'=>'た','だ'=>'だ','ち'=>'ち','ぢ'=>'ぢ','っ'=>'っ','つ'=>'つ','づ'=>'づ','て'=>'て','で'=>'で','と'=>'と','ど'=>'ど','な'=>'な','に'=>'に','ぬ'=>'ぬ','ね'=>'ね','の'=>'の','は'=>'は','ば'=>'ば','ぱ'=>'ぱ','ひ'=>'ひ','び'=>'び','ぴ'=>'ぴ','ふ'=>'ふ','ぶ'=>'ぶ','ぷ'=>'ぷ','へ'=>'へ','べ'=>'べ','ぺ'=>'ぺ','ほ'=>'ほ','ぼ'=>'ぼ','ぽ'=>'ぽ','ま'=>'ま','み'=>'み','む'=>'む','め'=>'め','も'=>'も','ゃ'=>'ゃ','や'=>'や','ゅ'=>'ゅ','ゆ'=>'ゆ','ょ'=>'ょ','よ'=>'よ','ら'=>'ら','り'=>'り','る'=>'る','れ'=>'れ','ろ'=>'ろ','ゎ'=>'ゎ','わ'=>'わ','ゐ'=>'ゐ','ゑ'=>'ゑ','を'=>'を','ん'=>'ん','ゔ'=>'ゔ','ゕ'=>'ゕ','ゖ'=>'ゖ','゙'=>'゙','゚'=>'゚','ゝ'=>'ゝ','ゞ'=>'ゞ','ゟ'=>'ゟ','ァ'=>'ァ','ア'=>'ア','ィ'=>'ィ','イ'=>'イ','ゥ'=>'ゥ','ウ'=>'ウ','ェ'=>'ェ','エ'=>'エ','ォ'=>'ォ','オ'=>'オ','カ'=>'カ','ガ'=>'ガ','キ'=>'キ','ギ'=>'ギ','ク'=>'ク','グ'=>'グ','ケ'=>'ケ','ゲ'=>'ゲ','コ'=>'コ','ゴ'=>'ゴ','サ'=>'サ','ザ'=>'ザ','シ'=>'シ','ジ'=>'ジ','ス'=>'ス','ズ'=>'ズ','セ'=>'セ','ゼ'=>'ゼ','ソ'=>'ソ','ゾ'=>'ゾ','タ'=>'タ','ダ'=>'ダ','チ'=>'チ','ヂ'=>'ヂ','ッ'=>'ッ','ツ'=>'ツ','ヅ'=>'ヅ','テ'=>'テ','デ'=>'デ','ト'=>'ト','ド'=>'ド','ナ'=>'ナ','ニ'=>'ニ','ヌ'=>'ヌ','ネ'=>'ネ','ノ'=>'ノ','ハ'=>'ハ','バ'=>'バ','パ'=>'パ','ヒ'=>'ヒ','ビ'=>'ビ','ピ'=>'ピ','フ'=>'フ','ブ'=>'ブ','プ'=>'プ','ヘ'=>'ヘ','ベ'=>'ベ','ペ'=>'ペ','ホ'=>'ホ','ボ'=>'ボ','ポ'=>'ポ','マ'=>'マ','ミ'=>'ミ','ム'=>'ム','メ'=>'メ','モ'=>'モ','ャ'=>'ャ','ヤ'=>'ヤ','ュ'=>'ュ','ユ'=>'ユ','ョ'=>'ョ','ヨ'=>'ヨ','ラ'=>'ラ','リ'=>'リ','ル'=>'ル','レ'=>'レ','ロ'=>'ロ','ヮ'=>'ヮ','ワ'=>'ワ','ヰ'=>'ヰ','ヱ'=>'ヱ','ヲ'=>'ヲ','ン'=>'ン','ヴ'=>'ヴ','ヵ'=>'ヵ','ヶ'=>'ヶ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ー'=>'ー','ヽ'=>'ヽ','ヾ'=>'ヾ','ヿ'=>'ヿ','ㄅ'=>'ㄅ','ㄆ'=>'ㄆ','ㄇ'=>'ㄇ','ㄈ'=>'ㄈ','ㄉ'=>'ㄉ','ㄊ'=>'ㄊ','ㄋ'=>'ㄋ','ㄌ'=>'ㄌ','ㄍ'=>'ㄍ','ㄎ'=>'ㄎ','ㄏ'=>'ㄏ','ㄐ'=>'ㄐ','ㄑ'=>'ㄑ','ㄒ'=>'ㄒ','ㄓ'=>'ㄓ','ㄔ'=>'ㄔ','ㄕ'=>'ㄕ','ㄖ'=>'ㄖ','ㄗ'=>'ㄗ','ㄘ'=>'ㄘ','ㄙ'=>'ㄙ','ㄚ'=>'ㄚ','ㄛ'=>'ㄛ','ㄜ'=>'ㄜ','ㄝ'=>'ㄝ','ㄞ'=>'ㄞ','ㄟ'=>'ㄟ','ㄠ'=>'ㄠ','ㄡ'=>'ㄡ','ㄢ'=>'ㄢ','ㄣ'=>'ㄣ','ㄤ'=>'ㄤ','ㄥ'=>'ㄥ','ㄦ'=>'ㄦ','ㄧ'=>'ㄧ','ㄨ'=>'ㄨ','ㄩ'=>'ㄩ','ㄪ'=>'ㄪ','ㄫ'=>'ㄫ','ㄬ'=>'ㄬ','ㄱ'=>'ㄱ','ㄲ'=>'ㄲ','ㄳ'=>'ㄳ','ㄴ'=>'ㄴ','ㄵ'=>'ㄵ','ㄶ'=>'ㄶ','ㄷ'=>'ㄷ','ㄸ'=>'ㄸ','ㄹ'=>'ㄹ','ㄺ'=>'ㄺ','ㄻ'=>'ㄻ','ㄼ'=>'ㄼ','ㄽ'=>'ㄽ','ㄾ'=>'ㄾ','ㄿ'=>'ㄿ','ㅀ'=>'ㅀ','ㅁ'=>'ㅁ','ㅂ'=>'ㅂ','ㅃ'=>'ㅃ','ㅄ'=>'ㅄ','ㅅ'=>'ㅅ','ㅆ'=>'ㅆ','ㅇ'=>'ㅇ','ㅈ'=>'ㅈ','ㅉ'=>'ㅉ','ㅊ'=>'ㅊ','ㅋ'=>'ㅋ','ㅌ'=>'ㅌ','ㅍ'=>'ㅍ','ㅎ'=>'ㅎ','ㅏ'=>'ㅏ','ㅐ'=>'ㅐ','ㅑ'=>'ㅑ','ㅒ'=>'ㅒ','ㅓ'=>'ㅓ','ㅔ'=>'ㅔ','ㅕ'=>'ㅕ','ㅖ'=>'ㅖ','ㅗ'=>'ㅗ','ㅘ'=>'ㅘ','ㅙ'=>'ㅙ','ㅚ'=>'ㅚ','ㅛ'=>'ㅛ','ㅜ'=>'ㅜ','ㅝ'=>'ㅝ','ㅞ'=>'ㅞ','ㅟ'=>'ㅟ','ㅠ'=>'ㅠ','ㅡ'=>'ㅡ','ㅢ'=>'ㅢ','ㅣ'=>'ㅣ','ㅤ'=>'ㅤ','ㅥ'=>'ㅥ','ㅦ'=>'ㅦ','ㅧ'=>'ㅧ','ㅨ'=>'ㅨ','ㅩ'=>'ㅩ','ㅪ'=>'ㅪ','ㅫ'=>'ㅫ','ㅬ'=>'ㅬ','ㅭ'=>'ㅭ','ㅮ'=>'ㅮ','ㅯ'=>'ㅯ','ㅰ'=>'ㅰ','ㅱ'=>'ㅱ','ㅲ'=>'ㅲ','ㅳ'=>'ㅳ','ㅴ'=>'ㅴ','ㅵ'=>'ㅵ','ㅶ'=>'ㅶ','ㅷ'=>'ㅷ','ㅸ'=>'ㅸ','ㅹ'=>'ㅹ','ㅺ'=>'ㅺ','ㅻ'=>'ㅻ','ㅼ'=>'ㅼ','ㅽ'=>'ㅽ','ㅾ'=>'ㅾ','ㅿ'=>'ㅿ','ㆀ'=>'ㆀ','ㆁ'=>'ㆁ','ㆂ'=>'ㆂ','ㆃ'=>'ㆃ','ㆄ'=>'ㆄ','ㆅ'=>'ㆅ','ㆆ'=>'ㆆ','ㆇ'=>'ㆇ','ㆈ'=>'ㆈ','ㆉ'=>'ㆉ','ㆊ'=>'ㆊ','ㆋ'=>'ㆋ','ㆌ'=>'ㆌ','ㆍ'=>'ㆍ','ㆎ'=>'ㆎ','㆒'=>'1','㆓'=>'2','㆔'=>'3','㆕'=>'4','ㆠ'=>'ㆠ','ㆡ'=>'ㆡ','ㆢ'=>'ㆢ','ㆣ'=>'ㆣ','ㆤ'=>'ㆤ','ㆥ'=>'ㆥ','ㆦ'=>'ㆦ','ㆧ'=>'ㆧ','ㆨ'=>'ㆨ','ㆩ'=>'ㆩ','ㆪ'=>'ㆪ','ㆫ'=>'ㆫ','ㆬ'=>'ㆬ','ㆭ'=>'ㆭ','ㆮ'=>'ㆮ','ㆯ'=>'ㆯ','ㆰ'=>'ㆰ','ㆱ'=>'ㆱ','ㆲ'=>'ㆲ','ㆳ'=>'ㆳ','ㆴ'=>'ㆴ','ㆵ'=>'ㆵ','ㆶ'=>'ㆶ','ㆷ'=>'ㆷ','ㇰ'=>'ㇰ','ㇱ'=>'ㇱ','ㇲ'=>'ㇲ','ㇳ'=>'ㇳ','ㇴ'=>'ㇴ','ㇵ'=>'ㇵ','ㇶ'=>'ㇶ','ㇷ'=>'ㇷ','ㇸ'=>'ㇸ','ㇹ'=>'ㇹ','ㇺ'=>'ㇺ','ㇻ'=>'ㇻ','ㇼ'=>'ㇼ','ㇽ'=>'ㇽ','ㇾ'=>'ㇾ','ㇿ'=>'ㇿ','㈠'=>'1','㈡'=>'2','㈢'=>'3','㈣'=>'4','㈤'=>'5','㈥'=>'6','㈦'=>'7','㈧'=>'8','㈨'=>'9','㈩'=>'10','㉑'=>'21','㉒'=>'22','㉓'=>'23','㉔'=>'24','㉕'=>'25','㉖'=>'26','㉗'=>'27','㉘'=>'28','㉙'=>'29','㉚'=>'30','㉛'=>'31','㉜'=>'32','㉝'=>'33','㉞'=>'34','㉟'=>'35','㊀'=>'1','㊁'=>'2','㊂'=>'3','㊃'=>'4','㊄'=>'5','㊅'=>'6','㊆'=>'7','㊇'=>'8','㊈'=>'9','㊉'=>'10','㊱'=>'36','㊲'=>'37','㊳'=>'38','㊴'=>'39','㊵'=>'40','㊶'=>'41','㊷'=>'42','㊸'=>'43','㊹'=>'44','㊺'=>'45','㊻'=>'46','㊼'=>'47','㊽'=>'48','㊾'=>'49','㊿'=>'50','㐀'=>'㐀');
\ No newline at end of file +<?php return array('々'=>'々','〆'=>'〆','〇'=>'0','〡'=>'1','〢'=>'2','〣'=>'3','〤'=>'4','〥'=>'5','〦'=>'6','〧'=>'7','〨'=>'8','〩'=>'9','〪'=>'〪','〫'=>'〫','〬'=>'〬','〭'=>'〭','〮'=>'〮','〯'=>'〯','〱'=>'〱','〲'=>'〲','〳'=>'〳','〴'=>'〴','〵'=>'〵','〸'=>'10','〹'=>'20','〺'=>'30','〻'=>'〻','〼'=>'〼','ぁ'=>'ぁ','あ'=>'あ','ぃ'=>'ぃ','い'=>'い','ぅ'=>'ぅ','う'=>'う','ぇ'=>'ぇ','え'=>'え','ぉ'=>'ぉ','お'=>'お','か'=>'か','が'=>'が','き'=>'き','ぎ'=>'ぎ','く'=>'く','ぐ'=>'ぐ','け'=>'け','げ'=>'げ','こ'=>'こ','ご'=>'ご','さ'=>'さ','ざ'=>'ざ','し'=>'し','じ'=>'じ','す'=>'す','ず'=>'ず','せ'=>'せ','ぜ'=>'ぜ','そ'=>'そ','ぞ'=>'ぞ','た'=>'た','だ'=>'だ','ち'=>'ち','ぢ'=>'ぢ','っ'=>'っ','つ'=>'つ','づ'=>'づ','て'=>'て','で'=>'で','と'=>'と','ど'=>'ど','な'=>'な','に'=>'に','ぬ'=>'ぬ','ね'=>'ね','の'=>'の','は'=>'は','ば'=>'ば','ぱ'=>'ぱ','ひ'=>'ひ','び'=>'び','ぴ'=>'ぴ','ふ'=>'ふ','ぶ'=>'ぶ','ぷ'=>'ぷ','へ'=>'へ','べ'=>'べ','ぺ'=>'ぺ','ほ'=>'ほ','ぼ'=>'ぼ','ぽ'=>'ぽ','ま'=>'ま','み'=>'み','む'=>'む','め'=>'め','も'=>'も','ゃ'=>'ゃ','や'=>'や','ゅ'=>'ゅ','ゆ'=>'ゆ','ょ'=>'ょ','よ'=>'よ','ら'=>'ら','り'=>'り','る'=>'る','れ'=>'れ','ろ'=>'ろ','ゎ'=>'ゎ','わ'=>'わ','ゐ'=>'ゐ','ゑ'=>'ゑ','を'=>'を','ん'=>'ん','ゔ'=>'ゔ','ゕ'=>'ゕ','ゖ'=>'ゖ','゙'=>'゙','゚'=>'゚','ゝ'=>'ゝ','ゞ'=>'ゞ','ゟ'=>'ゟ','ァ'=>'ァ','ア'=>'ア','ィ'=>'ィ','イ'=>'イ','ゥ'=>'ゥ','ウ'=>'ウ','ェ'=>'ェ','エ'=>'エ','ォ'=>'ォ','オ'=>'オ','カ'=>'カ','ガ'=>'ガ','キ'=>'キ','ギ'=>'ギ','ク'=>'ク','グ'=>'グ','ケ'=>'ケ','ゲ'=>'ゲ','コ'=>'コ','ゴ'=>'ゴ','サ'=>'サ','ザ'=>'ザ','シ'=>'シ','ジ'=>'ジ','ス'=>'ス','ズ'=>'ズ','セ'=>'セ','ゼ'=>'ゼ','ソ'=>'ソ','ゾ'=>'ゾ','タ'=>'タ','ダ'=>'ダ','チ'=>'チ','ヂ'=>'ヂ','ッ'=>'ッ','ツ'=>'ツ','ヅ'=>'ヅ','テ'=>'テ','デ'=>'デ','ト'=>'ト','ド'=>'ド','ナ'=>'ナ','ニ'=>'ニ','ヌ'=>'ヌ','ネ'=>'ネ','ノ'=>'ノ','ハ'=>'ハ','バ'=>'バ','パ'=>'パ','ヒ'=>'ヒ','ビ'=>'ビ','ピ'=>'ピ','フ'=>'フ','ブ'=>'ブ','プ'=>'プ','ヘ'=>'ヘ','ベ'=>'ベ','ペ'=>'ペ','ホ'=>'ホ','ボ'=>'ボ','ポ'=>'ポ','マ'=>'マ','ミ'=>'ミ','ム'=>'ム','メ'=>'メ','モ'=>'モ','ャ'=>'ャ','ヤ'=>'ヤ','ュ'=>'ュ','ユ'=>'ユ','ョ'=>'ョ','ヨ'=>'ヨ','ラ'=>'ラ','リ'=>'リ','ル'=>'ル','レ'=>'レ','ロ'=>'ロ','ヮ'=>'ヮ','ワ'=>'ワ','ヰ'=>'ヰ','ヱ'=>'ヱ','ヲ'=>'ヲ','ン'=>'ン','ヴ'=>'ヴ','ヵ'=>'ヵ','ヶ'=>'ヶ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ー'=>'ー','ヽ'=>'ヽ','ヾ'=>'ヾ','ヿ'=>'ヿ','ㄅ'=>'ㄅ','ㄆ'=>'ㄆ','ㄇ'=>'ㄇ','ㄈ'=>'ㄈ','ㄉ'=>'ㄉ','ㄊ'=>'ㄊ','ㄋ'=>'ㄋ','ㄌ'=>'ㄌ','ㄍ'=>'ㄍ','ㄎ'=>'ㄎ','ㄏ'=>'ㄏ','ㄐ'=>'ㄐ','ㄑ'=>'ㄑ','ㄒ'=>'ㄒ','ㄓ'=>'ㄓ','ㄔ'=>'ㄔ','ㄕ'=>'ㄕ','ㄖ'=>'ㄖ','ㄗ'=>'ㄗ','ㄘ'=>'ㄘ','ㄙ'=>'ㄙ','ㄚ'=>'ㄚ','ㄛ'=>'ㄛ','ㄜ'=>'ㄜ','ㄝ'=>'ㄝ','ㄞ'=>'ㄞ','ㄟ'=>'ㄟ','ㄠ'=>'ㄠ','ㄡ'=>'ㄡ','ㄢ'=>'ㄢ','ㄣ'=>'ㄣ','ㄤ'=>'ㄤ','ㄥ'=>'ㄥ','ㄦ'=>'ㄦ','ㄧ'=>'ㄧ','ㄨ'=>'ㄨ','ㄩ'=>'ㄩ','ㄪ'=>'ㄪ','ㄫ'=>'ㄫ','ㄬ'=>'ㄬ','ㄱ'=>'ㄱ','ㄲ'=>'ㄲ','ㄳ'=>'ㄳ','ㄴ'=>'ㄴ','ㄵ'=>'ㄵ','ㄶ'=>'ㄶ','ㄷ'=>'ㄷ','ㄸ'=>'ㄸ','ㄹ'=>'ㄹ','ㄺ'=>'ㄺ','ㄻ'=>'ㄻ','ㄼ'=>'ㄼ','ㄽ'=>'ㄽ','ㄾ'=>'ㄾ','ㄿ'=>'ㄿ','ㅀ'=>'ㅀ','ㅁ'=>'ㅁ','ㅂ'=>'ㅂ','ㅃ'=>'ㅃ','ㅄ'=>'ㅄ','ㅅ'=>'ㅅ','ㅆ'=>'ㅆ','ㅇ'=>'ㅇ','ㅈ'=>'ㅈ','ㅉ'=>'ㅉ','ㅊ'=>'ㅊ','ㅋ'=>'ㅋ','ㅌ'=>'ㅌ','ㅍ'=>'ㅍ','ㅎ'=>'ㅎ','ㅏ'=>'ㅏ','ㅐ'=>'ㅐ','ㅑ'=>'ㅑ','ㅒ'=>'ㅒ','ㅓ'=>'ㅓ','ㅔ'=>'ㅔ','ㅕ'=>'ㅕ','ㅖ'=>'ㅖ','ㅗ'=>'ㅗ','ㅘ'=>'ㅘ','ㅙ'=>'ㅙ','ㅚ'=>'ㅚ','ㅛ'=>'ㅛ','ㅜ'=>'ㅜ','ㅝ'=>'ㅝ','ㅞ'=>'ㅞ','ㅟ'=>'ㅟ','ㅠ'=>'ㅠ','ㅡ'=>'ㅡ','ㅢ'=>'ㅢ','ㅣ'=>'ㅣ','ㅤ'=>'ㅤ','ㅥ'=>'ㅥ','ㅦ'=>'ㅦ','ㅧ'=>'ㅧ','ㅨ'=>'ㅨ','ㅩ'=>'ㅩ','ㅪ'=>'ㅪ','ㅫ'=>'ㅫ','ㅬ'=>'ㅬ','ㅭ'=>'ㅭ','ㅮ'=>'ㅮ','ㅯ'=>'ㅯ','ㅰ'=>'ㅰ','ㅱ'=>'ㅱ','ㅲ'=>'ㅲ','ㅳ'=>'ㅳ','ㅴ'=>'ㅴ','ㅵ'=>'ㅵ','ㅶ'=>'ㅶ','ㅷ'=>'ㅷ','ㅸ'=>'ㅸ','ㅹ'=>'ㅹ','ㅺ'=>'ㅺ','ㅻ'=>'ㅻ','ㅼ'=>'ㅼ','ㅽ'=>'ㅽ','ㅾ'=>'ㅾ','ㅿ'=>'ㅿ','ㆀ'=>'ㆀ','ㆁ'=>'ㆁ','ㆂ'=>'ㆂ','ㆃ'=>'ㆃ','ㆄ'=>'ㆄ','ㆅ'=>'ㆅ','ㆆ'=>'ㆆ','ㆇ'=>'ㆇ','ㆈ'=>'ㆈ','ㆉ'=>'ㆉ','ㆊ'=>'ㆊ','ㆋ'=>'ㆋ','ㆌ'=>'ㆌ','ㆍ'=>'ㆍ','ㆎ'=>'ㆎ','㆒'=>'1','㆓'=>'2','㆔'=>'3','㆕'=>'4','ㆠ'=>'ㆠ','ㆡ'=>'ㆡ','ㆢ'=>'ㆢ','ㆣ'=>'ㆣ','ㆤ'=>'ㆤ','ㆥ'=>'ㆥ','ㆦ'=>'ㆦ','ㆧ'=>'ㆧ','ㆨ'=>'ㆨ','ㆩ'=>'ㆩ','ㆪ'=>'ㆪ','ㆫ'=>'ㆫ','ㆬ'=>'ㆬ','ㆭ'=>'ㆭ','ㆮ'=>'ㆮ','ㆯ'=>'ㆯ','ㆰ'=>'ㆰ','ㆱ'=>'ㆱ','ㆲ'=>'ㆲ','ㆳ'=>'ㆳ','ㆴ'=>'ㆴ','ㆵ'=>'ㆵ','ㆶ'=>'ㆶ','ㆷ'=>'ㆷ','ㇰ'=>'ㇰ','ㇱ'=>'ㇱ','ㇲ'=>'ㇲ','ㇳ'=>'ㇳ','ㇴ'=>'ㇴ','ㇵ'=>'ㇵ','ㇶ'=>'ㇶ','ㇷ'=>'ㇷ','ㇸ'=>'ㇸ','ㇹ'=>'ㇹ','ㇺ'=>'ㇺ','ㇻ'=>'ㇻ','ㇼ'=>'ㇼ','ㇽ'=>'ㇽ','ㇾ'=>'ㇾ','ㇿ'=>'ㇿ','㈠'=>'1','㈡'=>'2','㈢'=>'3','㈣'=>'4','㈤'=>'5','㈥'=>'6','㈦'=>'7','㈧'=>'8','㈨'=>'9','㈩'=>'10','㉑'=>'21','㉒'=>'22','㉓'=>'23','㉔'=>'24','㉕'=>'25','㉖'=>'26','㉗'=>'27','㉘'=>'28','㉙'=>'29','㉚'=>'30','㉛'=>'31','㉜'=>'32','㉝'=>'33','㉞'=>'34','㉟'=>'35','㊀'=>'1','㊁'=>'2','㊂'=>'3','㊃'=>'4','㊄'=>'5','㊅'=>'6','㊆'=>'7','㊇'=>'8','㊈'=>'9','㊉'=>'10','㊱'=>'36','㊲'=>'37','㊳'=>'38','㊴'=>'39','㊵'=>'40','㊶'=>'41','㊷'=>'42','㊸'=>'43','㊹'=>'44','㊺'=>'45','㊻'=>'46','㊼'=>'47','㊽'=>'48','㊾'=>'49','㊿'=>'50','㐀'=>'㐀'); diff --git a/phpBB/includes/utf/data/search_indexer_64.php b/phpBB/includes/utf/data/search_indexer_64.php index 44d0beb624..b5002d4c42 100644 --- a/phpBB/includes/utf/data/search_indexer_64.php +++ b/phpBB/includes/utf/data/search_indexer_64.php @@ -1 +1 @@ -<?php return array('𠀀'=>'𠀀');
\ No newline at end of file +<?php return array('𠀀'=>'𠀀'); diff --git a/phpBB/includes/utf/data/search_indexer_84.php b/phpBB/includes/utf/data/search_indexer_84.php index 5c3f1d54b8..c038215e58 100644 --- a/phpBB/includes/utf/data/search_indexer_84.php +++ b/phpBB/includes/utf/data/search_indexer_84.php @@ -1 +1 @@ -<?php return array('𪛖'=>'𪛖');
\ No newline at end of file +<?php return array('𪛖'=>'𪛖'); diff --git a/phpBB/includes/utf/data/search_indexer_9.php b/phpBB/includes/utf/data/search_indexer_9.php index bdf188291f..a358f784b9 100644 --- a/phpBB/includes/utf/data/search_indexer_9.php +++ b/phpBB/includes/utf/data/search_indexer_9.php @@ -1 +1 @@ -<?php return array('䶵'=>'䶵','一'=>'一');
\ No newline at end of file +<?php return array('䶵'=>'䶵','一'=>'一'); diff --git a/phpBB/includes/utf/data/search_indexer_95.php b/phpBB/includes/utf/data/search_indexer_95.php index b0f8eed3aa..63d27fbcd6 100644 --- a/phpBB/includes/utf/data/search_indexer_95.php +++ b/phpBB/includes/utf/data/search_indexer_95.php @@ -1 +1 @@ -<?php return array('丽'=>'丽','丸'=>'丸','乁'=>'乁','𠄢'=>'𠄢','你'=>'你','侮'=>'侮','侻'=>'侻','倂'=>'倂','偺'=>'偺','備'=>'備','僧'=>'僧','像'=>'像','㒞'=>'㒞','𠘺'=>'𠘺','免'=>'免','兔'=>'兔','兤'=>'兤','具'=>'具','𠔜'=>'𠔜','㒹'=>'㒹','內'=>'內','再'=>'再','𠕋'=>'𠕋','冗'=>'冗','冤'=>'冤','仌'=>'仌','冬'=>'冬','况'=>'况','𩇟'=>'𩇟','凵'=>'凵','刃'=>'刃','㓟'=>'㓟','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','㔕'=>'㔕','勇'=>'勇','勉'=>'勉','勤'=>'勤','勺'=>'勺','包'=>'包','匆'=>'匆','北'=>'北','卉'=>'卉','卑'=>'卑','博'=>'博','即'=>'即','卽'=>'卽','卿'=>'卿','卿'=>'卿','卿'=>'卿','𠨬'=>'𠨬','灰'=>'灰','及'=>'及','叟'=>'叟','𠭣'=>'𠭣','叫'=>'叫','叱'=>'叱','吆'=>'吆','咞'=>'咞','吸'=>'吸','呈'=>'呈','周'=>'周','咢'=>'咢','哶'=>'哶','唐'=>'唐','啓'=>'啓','啣'=>'啣','善'=>'善','善'=>'善','喙'=>'喙','喫'=>'喫','喳'=>'喳','嗂'=>'嗂','圖'=>'圖','嘆'=>'嘆','圗'=>'圗','噑'=>'噑','噴'=>'噴','切'=>'切','壮'=>'壮','城'=>'城','埴'=>'埴','堍'=>'堍','型'=>'型','堲'=>'堲','報'=>'報','墬'=>'墬','𡓤'=>'𡓤','売'=>'売','壷'=>'壷','夆'=>'夆','多'=>'多','夢'=>'夢','奢'=>'奢','𡚨'=>'𡚨','𡛪'=>'𡛪','姬'=>'姬','娛'=>'娛','娧'=>'娧','姘'=>'姘','婦'=>'婦','㛮'=>'㛮','㛼'=>'㛼','嬈'=>'嬈','嬾'=>'嬾','嬾'=>'嬾','𡧈'=>'𡧈','寃'=>'寃','寘'=>'寘','寧'=>'寧','寳'=>'寳','𡬘'=>'𡬘','寿'=>'寿','将'=>'将','当'=>'当','尢'=>'尢','㞁'=>'㞁','屠'=>'屠','屮'=>'屮','峀'=>'峀','岍'=>'岍','𡷤'=>'𡷤','嵃'=>'嵃','𡷦'=>'𡷦','嵮'=>'嵮','嵫'=>'嵫','嵼'=>'嵼','巡'=>'巡','巢'=>'巢','㠯'=>'㠯','巽'=>'巽','帨'=>'帨','帽'=>'帽','幩'=>'幩','㡢'=>'㡢','𢆃'=>'𢆃','㡼'=>'㡼','庰'=>'庰','庳'=>'庳','庶'=>'庶','廊'=>'廊','𪎒'=>'𪎒','廾'=>'廾','𢌱'=>'𢌱','𢌱'=>'𢌱','舁'=>'舁','弢'=>'弢','弢'=>'弢','㣇'=>'㣇','𣊸'=>'𣊸','𦇚'=>'𦇚','形'=>'形','彫'=>'彫','㣣'=>'㣣','徚'=>'徚','忍'=>'忍','志'=>'志','忹'=>'忹','悁'=>'悁','㤺'=>'㤺','㤜'=>'㤜','悔'=>'悔','𢛔'=>'𢛔','惇'=>'惇','慈'=>'慈','慌'=>'慌','慎'=>'慎','慌'=>'慌','慺'=>'慺','憎'=>'憎','憲'=>'憲','憤'=>'憤','憯'=>'憯','懞'=>'懞','懲'=>'懲','懶'=>'懶','成'=>'成','戛'=>'戛','扝'=>'扝','抱'=>'抱','拔'=>'拔','捐'=>'捐','𢬌'=>'𢬌','挽'=>'挽','拼'=>'拼','捨'=>'捨','掃'=>'掃','揤'=>'揤','𢯱'=>'𢯱','搢'=>'搢','揅'=>'揅','掩'=>'掩','㨮'=>'㨮','摩'=>'摩','摾'=>'摾','撝'=>'撝','摷'=>'摷','㩬'=>'㩬','敏'=>'敏','敬'=>'敬','𣀊'=>'𣀊','旣'=>'旣','書'=>'書','晉'=>'晉','㬙'=>'㬙','暑'=>'暑','㬈'=>'㬈','㫤'=>'㫤','冒'=>'冒','冕'=>'冕','最'=>'最','暜'=>'暜','肭'=>'肭','䏙'=>'䏙','朗'=>'朗','望'=>'望','朡'=>'朡','杞'=>'杞','杓'=>'杓','𣏃'=>'𣏃','㭉'=>'㭉','柺'=>'柺','枅'=>'枅','桒'=>'桒','梅'=>'梅','𣑭'=>'𣑭','梎'=>'梎','栟'=>'栟','椔'=>'椔','㮝'=>'㮝','楂'=>'楂','榣'=>'榣','槪'=>'槪','檨'=>'檨','𣚣'=>'𣚣','櫛'=>'櫛','㰘'=>'㰘','次'=>'次','𣢧'=>'𣢧','歔'=>'歔','㱎'=>'㱎','歲'=>'歲','殟'=>'殟','殺'=>'殺','殻'=>'殻','𣪍'=>'𣪍','𡴋'=>'𡴋','𣫺'=>'𣫺','汎'=>'汎','𣲼'=>'𣲼','沿'=>'沿','泍'=>'泍','汧'=>'汧','洖'=>'洖','派'=>'派','海'=>'海','流'=>'流','浩'=>'浩','浸'=>'浸','涅'=>'涅','𣴞'=>'𣴞','洴'=>'洴','港'=>'港','湮'=>'湮','㴳'=>'㴳','滋'=>'滋','滇'=>'滇','𣻑'=>'𣻑','淹'=>'淹','潮'=>'潮','𣽞'=>'𣽞','𣾎'=>'𣾎','濆'=>'濆','瀹'=>'瀹','瀞'=>'瀞','瀛'=>'瀛','㶖'=>'㶖','灊'=>'灊','災'=>'災','灷'=>'灷','炭'=>'炭','𠔥'=>'𠔥','煅'=>'煅','𤉣'=>'𤉣','熜'=>'熜','𤎫'=>'𤎫','爨'=>'爨','爵'=>'爵','牐'=>'牐','𤘈'=>'𤘈','犀'=>'犀','犕'=>'犕','𤜵'=>'𤜵','𤠔'=>'𤠔','獺'=>'獺','王'=>'王','㺬'=>'㺬','玥'=>'玥','㺸'=>'㺸','㺸'=>'㺸','瑇'=>'瑇','瑜'=>'瑜','瑱'=>'瑱','璅'=>'璅','瓊'=>'瓊','㼛'=>'㼛','甤'=>'甤','𤰶'=>'𤰶','甾'=>'甾','𤲒'=>'𤲒','異'=>'異','𢆟'=>'𢆟','瘐'=>'瘐','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'𥁄','㿼'=>'㿼','䀈'=>'䀈','直'=>'直','𥃳'=>'𥃳','𥃲'=>'𥃲','𥄙'=>'𥄙','𥄳'=>'𥄳','眞'=>'眞','真'=>'真','真'=>'真','睊'=>'睊','䀹'=>'䀹','瞋'=>'瞋','䁆'=>'䁆','䂖'=>'䂖','𥐝'=>'𥐝','硎'=>'硎','碌'=>'碌','磌'=>'磌','䃣'=>'䃣','𥘦'=>'𥘦','祖'=>'祖','𥚚'=>'𥚚','𥛅'=>'𥛅','福'=>'福','秫'=>'秫','䄯'=>'䄯','穀'=>'穀','穊'=>'穊','穏'=>'穏','𥥼'=>'𥥼','𥪧'=>'𥪧','𥪧'=>'𥪧','竮'=>'竮','䈂'=>'䈂','𥮫'=>'𥮫','篆'=>'篆','築'=>'築','䈧'=>'䈧','𥲀'=>'𥲀','糒'=>'糒','䊠'=>'䊠','糨'=>'糨','糣'=>'糣','紀'=>'紀','𥾆'=>'𥾆','絣'=>'絣','䌁'=>'䌁','緇'=>'緇','縂'=>'縂','繅'=>'繅','䌴'=>'䌴','𦈨'=>'𦈨','𦉇'=>'𦉇','䍙'=>'䍙','𦋙'=>'𦋙','罺'=>'罺','𦌾'=>'𦌾','羕'=>'羕','翺'=>'翺','者'=>'者','𦓚'=>'𦓚','𦔣'=>'𦔣','聠'=>'聠','𦖨'=>'𦖨','聰'=>'聰','𣍟'=>'𣍟','䏕'=>'䏕','育'=>'育','脃'=>'脃','䐋'=>'䐋','脾'=>'脾','媵'=>'媵','𦞧'=>'𦞧','𦞵'=>'𦞵','𣎓'=>'𣎓','𣎜'=>'𣎜','舁'=>'舁','舄'=>'舄','辞'=>'辞','䑫'=>'䑫','芑'=>'芑','芋'=>'芋','芝'=>'芝','劳'=>'劳','花'=>'花','芳'=>'芳','芽'=>'芽','苦'=>'苦','𦬼'=>'𦬼','若'=>'若','茝'=>'茝','荣'=>'荣','莭'=>'莭','茣'=>'茣','莽'=>'莽','菧'=>'菧','著'=>'著','荓'=>'荓','菊'=>'菊','菌'=>'菌','菜'=>'菜','𦰶'=>'𦰶','𦵫'=>'𦵫','𦳕'=>'𦳕','䔫'=>'䔫','蓱'=>'蓱','蓳'=>'蓳','蔖'=>'蔖','𧏊'=>'𧏊','蕤'=>'蕤','𦼬'=>'𦼬','䕝'=>'䕝','䕡'=>'䕡','𦾱'=>'𦾱','𧃒'=>'𧃒','䕫'=>'䕫','虐'=>'虐','虜'=>'虜','虧'=>'虧','虩'=>'虩','蚩'=>'蚩','蚈'=>'蚈','蜎'=>'蜎','蛢'=>'蛢','蝹'=>'蝹','蜨'=>'蜨','蝫'=>'蝫','螆'=>'螆','䗗'=>'䗗','蟡'=>'蟡','蠁'=>'蠁','䗹'=>'䗹','衠'=>'衠','衣'=>'衣','𧙧'=>'𧙧','裗'=>'裗','裞'=>'裞','䘵'=>'䘵','裺'=>'裺','㒻'=>'㒻','𧢮'=>'𧢮','𧥦'=>'𧥦','䚾'=>'䚾','䛇'=>'䛇','誠'=>'誠','諭'=>'諭','變'=>'變','豕'=>'豕','𧲨'=>'𧲨','貫'=>'貫','賁'=>'賁','贛'=>'贛','起'=>'起','𧼯'=>'𧼯','𠠄'=>'𠠄','跋'=>'跋','趼'=>'趼','跰'=>'跰','𠣞'=>'𠣞','軔'=>'軔','輸'=>'輸','𨗒'=>'𨗒','𨗭'=>'𨗭','邔'=>'邔','郱'=>'郱','鄑'=>'鄑','𨜮'=>'𨜮','鄛'=>'鄛','鈸'=>'鈸','鋗'=>'鋗','鋘'=>'鋘','鉼'=>'鉼','鏹'=>'鏹','鐕'=>'鐕','𨯺'=>'𨯺','開'=>'開','䦕'=>'䦕','閷'=>'閷','𨵷'=>'𨵷','䧦'=>'䧦','雃'=>'雃','嶲'=>'嶲','霣'=>'霣','𩅅'=>'𩅅','𩈚'=>'𩈚','䩮'=>'䩮','䩶'=>'䩶','韠'=>'韠','𩐊'=>'𩐊','䪲'=>'䪲','𩒖'=>'𩒖','頋'=>'頋','頋'=>'頋','頩'=>'頩','𩖶'=>'𩖶','飢'=>'飢','䬳'=>'䬳','餩'=>'餩','馧'=>'馧','駂'=>'駂','駾'=>'駾','䯎'=>'䯎','𩬰'=>'𩬰','鬒'=>'鬒','鱀'=>'鱀','鳽'=>'鳽','䳎'=>'䳎','䳭'=>'䳭','鵧'=>'鵧','𪃎'=>'𪃎','䳸'=>'䳸','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','麻'=>'麻','䵖'=>'䵖','黹'=>'黹','黾'=>'黾','鼅'=>'鼅','鼏'=>'鼏','鼖'=>'鼖','鼻'=>'鼻','𪘀'=>'𪘀');
\ No newline at end of file +<?php return array('丽'=>'丽','丸'=>'丸','乁'=>'乁','𠄢'=>'𠄢','你'=>'你','侮'=>'侮','侻'=>'侻','倂'=>'倂','偺'=>'偺','備'=>'備','僧'=>'僧','像'=>'像','㒞'=>'㒞','𠘺'=>'𠘺','免'=>'免','兔'=>'兔','兤'=>'兤','具'=>'具','𠔜'=>'𠔜','㒹'=>'㒹','內'=>'內','再'=>'再','𠕋'=>'𠕋','冗'=>'冗','冤'=>'冤','仌'=>'仌','冬'=>'冬','况'=>'况','𩇟'=>'𩇟','凵'=>'凵','刃'=>'刃','㓟'=>'㓟','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','㔕'=>'㔕','勇'=>'勇','勉'=>'勉','勤'=>'勤','勺'=>'勺','包'=>'包','匆'=>'匆','北'=>'北','卉'=>'卉','卑'=>'卑','博'=>'博','即'=>'即','卽'=>'卽','卿'=>'卿','卿'=>'卿','卿'=>'卿','𠨬'=>'𠨬','灰'=>'灰','及'=>'及','叟'=>'叟','𠭣'=>'𠭣','叫'=>'叫','叱'=>'叱','吆'=>'吆','咞'=>'咞','吸'=>'吸','呈'=>'呈','周'=>'周','咢'=>'咢','哶'=>'哶','唐'=>'唐','啓'=>'啓','啣'=>'啣','善'=>'善','善'=>'善','喙'=>'喙','喫'=>'喫','喳'=>'喳','嗂'=>'嗂','圖'=>'圖','嘆'=>'嘆','圗'=>'圗','噑'=>'噑','噴'=>'噴','切'=>'切','壮'=>'壮','城'=>'城','埴'=>'埴','堍'=>'堍','型'=>'型','堲'=>'堲','報'=>'報','墬'=>'墬','𡓤'=>'𡓤','売'=>'売','壷'=>'壷','夆'=>'夆','多'=>'多','夢'=>'夢','奢'=>'奢','𡚨'=>'𡚨','𡛪'=>'𡛪','姬'=>'姬','娛'=>'娛','娧'=>'娧','姘'=>'姘','婦'=>'婦','㛮'=>'㛮','㛼'=>'㛼','嬈'=>'嬈','嬾'=>'嬾','嬾'=>'嬾','𡧈'=>'𡧈','寃'=>'寃','寘'=>'寘','寧'=>'寧','寳'=>'寳','𡬘'=>'𡬘','寿'=>'寿','将'=>'将','当'=>'当','尢'=>'尢','㞁'=>'㞁','屠'=>'屠','屮'=>'屮','峀'=>'峀','岍'=>'岍','𡷤'=>'𡷤','嵃'=>'嵃','𡷦'=>'𡷦','嵮'=>'嵮','嵫'=>'嵫','嵼'=>'嵼','巡'=>'巡','巢'=>'巢','㠯'=>'㠯','巽'=>'巽','帨'=>'帨','帽'=>'帽','幩'=>'幩','㡢'=>'㡢','𢆃'=>'𢆃','㡼'=>'㡼','庰'=>'庰','庳'=>'庳','庶'=>'庶','廊'=>'廊','𪎒'=>'𪎒','廾'=>'廾','𢌱'=>'𢌱','𢌱'=>'𢌱','舁'=>'舁','弢'=>'弢','弢'=>'弢','㣇'=>'㣇','𣊸'=>'𣊸','𦇚'=>'𦇚','形'=>'形','彫'=>'彫','㣣'=>'㣣','徚'=>'徚','忍'=>'忍','志'=>'志','忹'=>'忹','悁'=>'悁','㤺'=>'㤺','㤜'=>'㤜','悔'=>'悔','𢛔'=>'𢛔','惇'=>'惇','慈'=>'慈','慌'=>'慌','慎'=>'慎','慌'=>'慌','慺'=>'慺','憎'=>'憎','憲'=>'憲','憤'=>'憤','憯'=>'憯','懞'=>'懞','懲'=>'懲','懶'=>'懶','成'=>'成','戛'=>'戛','扝'=>'扝','抱'=>'抱','拔'=>'拔','捐'=>'捐','𢬌'=>'𢬌','挽'=>'挽','拼'=>'拼','捨'=>'捨','掃'=>'掃','揤'=>'揤','𢯱'=>'𢯱','搢'=>'搢','揅'=>'揅','掩'=>'掩','㨮'=>'㨮','摩'=>'摩','摾'=>'摾','撝'=>'撝','摷'=>'摷','㩬'=>'㩬','敏'=>'敏','敬'=>'敬','𣀊'=>'𣀊','旣'=>'旣','書'=>'書','晉'=>'晉','㬙'=>'㬙','暑'=>'暑','㬈'=>'㬈','㫤'=>'㫤','冒'=>'冒','冕'=>'冕','最'=>'最','暜'=>'暜','肭'=>'肭','䏙'=>'䏙','朗'=>'朗','望'=>'望','朡'=>'朡','杞'=>'杞','杓'=>'杓','𣏃'=>'𣏃','㭉'=>'㭉','柺'=>'柺','枅'=>'枅','桒'=>'桒','梅'=>'梅','𣑭'=>'𣑭','梎'=>'梎','栟'=>'栟','椔'=>'椔','㮝'=>'㮝','楂'=>'楂','榣'=>'榣','槪'=>'槪','檨'=>'檨','𣚣'=>'𣚣','櫛'=>'櫛','㰘'=>'㰘','次'=>'次','𣢧'=>'𣢧','歔'=>'歔','㱎'=>'㱎','歲'=>'歲','殟'=>'殟','殺'=>'殺','殻'=>'殻','𣪍'=>'𣪍','𡴋'=>'𡴋','𣫺'=>'𣫺','汎'=>'汎','𣲼'=>'𣲼','沿'=>'沿','泍'=>'泍','汧'=>'汧','洖'=>'洖','派'=>'派','海'=>'海','流'=>'流','浩'=>'浩','浸'=>'浸','涅'=>'涅','𣴞'=>'𣴞','洴'=>'洴','港'=>'港','湮'=>'湮','㴳'=>'㴳','滋'=>'滋','滇'=>'滇','𣻑'=>'𣻑','淹'=>'淹','潮'=>'潮','𣽞'=>'𣽞','𣾎'=>'𣾎','濆'=>'濆','瀹'=>'瀹','瀞'=>'瀞','瀛'=>'瀛','㶖'=>'㶖','灊'=>'灊','災'=>'災','灷'=>'灷','炭'=>'炭','𠔥'=>'𠔥','煅'=>'煅','𤉣'=>'𤉣','熜'=>'熜','𤎫'=>'𤎫','爨'=>'爨','爵'=>'爵','牐'=>'牐','𤘈'=>'𤘈','犀'=>'犀','犕'=>'犕','𤜵'=>'𤜵','𤠔'=>'𤠔','獺'=>'獺','王'=>'王','㺬'=>'㺬','玥'=>'玥','㺸'=>'㺸','㺸'=>'㺸','瑇'=>'瑇','瑜'=>'瑜','瑱'=>'瑱','璅'=>'璅','瓊'=>'瓊','㼛'=>'㼛','甤'=>'甤','𤰶'=>'𤰶','甾'=>'甾','𤲒'=>'𤲒','異'=>'異','𢆟'=>'𢆟','瘐'=>'瘐','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'𥁄','㿼'=>'㿼','䀈'=>'䀈','直'=>'直','𥃳'=>'𥃳','𥃲'=>'𥃲','𥄙'=>'𥄙','𥄳'=>'𥄳','眞'=>'眞','真'=>'真','真'=>'真','睊'=>'睊','䀹'=>'䀹','瞋'=>'瞋','䁆'=>'䁆','䂖'=>'䂖','𥐝'=>'𥐝','硎'=>'硎','碌'=>'碌','磌'=>'磌','䃣'=>'䃣','𥘦'=>'𥘦','祖'=>'祖','𥚚'=>'𥚚','𥛅'=>'𥛅','福'=>'福','秫'=>'秫','䄯'=>'䄯','穀'=>'穀','穊'=>'穊','穏'=>'穏','𥥼'=>'𥥼','𥪧'=>'𥪧','𥪧'=>'𥪧','竮'=>'竮','䈂'=>'䈂','𥮫'=>'𥮫','篆'=>'篆','築'=>'築','䈧'=>'䈧','𥲀'=>'𥲀','糒'=>'糒','䊠'=>'䊠','糨'=>'糨','糣'=>'糣','紀'=>'紀','𥾆'=>'𥾆','絣'=>'絣','䌁'=>'䌁','緇'=>'緇','縂'=>'縂','繅'=>'繅','䌴'=>'䌴','𦈨'=>'𦈨','𦉇'=>'𦉇','䍙'=>'䍙','𦋙'=>'𦋙','罺'=>'罺','𦌾'=>'𦌾','羕'=>'羕','翺'=>'翺','者'=>'者','𦓚'=>'𦓚','𦔣'=>'𦔣','聠'=>'聠','𦖨'=>'𦖨','聰'=>'聰','𣍟'=>'𣍟','䏕'=>'䏕','育'=>'育','脃'=>'脃','䐋'=>'䐋','脾'=>'脾','媵'=>'媵','𦞧'=>'𦞧','𦞵'=>'𦞵','𣎓'=>'𣎓','𣎜'=>'𣎜','舁'=>'舁','舄'=>'舄','辞'=>'辞','䑫'=>'䑫','芑'=>'芑','芋'=>'芋','芝'=>'芝','劳'=>'劳','花'=>'花','芳'=>'芳','芽'=>'芽','苦'=>'苦','𦬼'=>'𦬼','若'=>'若','茝'=>'茝','荣'=>'荣','莭'=>'莭','茣'=>'茣','莽'=>'莽','菧'=>'菧','著'=>'著','荓'=>'荓','菊'=>'菊','菌'=>'菌','菜'=>'菜','𦰶'=>'𦰶','𦵫'=>'𦵫','𦳕'=>'𦳕','䔫'=>'䔫','蓱'=>'蓱','蓳'=>'蓳','蔖'=>'蔖','𧏊'=>'𧏊','蕤'=>'蕤','𦼬'=>'𦼬','䕝'=>'䕝','䕡'=>'䕡','𦾱'=>'𦾱','𧃒'=>'𧃒','䕫'=>'䕫','虐'=>'虐','虜'=>'虜','虧'=>'虧','虩'=>'虩','蚩'=>'蚩','蚈'=>'蚈','蜎'=>'蜎','蛢'=>'蛢','蝹'=>'蝹','蜨'=>'蜨','蝫'=>'蝫','螆'=>'螆','䗗'=>'䗗','蟡'=>'蟡','蠁'=>'蠁','䗹'=>'䗹','衠'=>'衠','衣'=>'衣','𧙧'=>'𧙧','裗'=>'裗','裞'=>'裞','䘵'=>'䘵','裺'=>'裺','㒻'=>'㒻','𧢮'=>'𧢮','𧥦'=>'𧥦','䚾'=>'䚾','䛇'=>'䛇','誠'=>'誠','諭'=>'諭','變'=>'變','豕'=>'豕','𧲨'=>'𧲨','貫'=>'貫','賁'=>'賁','贛'=>'贛','起'=>'起','𧼯'=>'𧼯','𠠄'=>'𠠄','跋'=>'跋','趼'=>'趼','跰'=>'跰','𠣞'=>'𠣞','軔'=>'軔','輸'=>'輸','𨗒'=>'𨗒','𨗭'=>'𨗭','邔'=>'邔','郱'=>'郱','鄑'=>'鄑','𨜮'=>'𨜮','鄛'=>'鄛','鈸'=>'鈸','鋗'=>'鋗','鋘'=>'鋘','鉼'=>'鉼','鏹'=>'鏹','鐕'=>'鐕','𨯺'=>'𨯺','開'=>'開','䦕'=>'䦕','閷'=>'閷','𨵷'=>'𨵷','䧦'=>'䧦','雃'=>'雃','嶲'=>'嶲','霣'=>'霣','𩅅'=>'𩅅','𩈚'=>'𩈚','䩮'=>'䩮','䩶'=>'䩶','韠'=>'韠','𩐊'=>'𩐊','䪲'=>'䪲','𩒖'=>'𩒖','頋'=>'頋','頋'=>'頋','頩'=>'頩','𩖶'=>'𩖶','飢'=>'飢','䬳'=>'䬳','餩'=>'餩','馧'=>'馧','駂'=>'駂','駾'=>'駾','䯎'=>'䯎','𩬰'=>'𩬰','鬒'=>'鬒','鱀'=>'鱀','鳽'=>'鳽','䳎'=>'䳎','䳭'=>'䳭','鵧'=>'鵧','𪃎'=>'𪃎','䳸'=>'䳸','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','麻'=>'麻','䵖'=>'䵖','黹'=>'黹','黾'=>'黾','鼅'=>'鼅','鼏'=>'鼏','鼖'=>'鼖','鼻'=>'鼻','𪘀'=>'𪘀'); diff --git a/phpBB/includes/utf/data/utf_canonical_comp.php b/phpBB/includes/utf/data/utf_canonical_comp.php index a3ed3ee602..2de3149ee8 100644 --- a/phpBB/includes/utf/data/utf_canonical_comp.php +++ b/phpBB/includes/utf/data/utf_canonical_comp.php @@ -1,2 +1,2 @@ <?php -$GLOBALS['utf_canonical_comp']=array('À'=>'À','Á'=>'Á','Â'=>'Â','Ã'=>'Ã','Ä'=>'Ä','Å'=>'Å','Ç'=>'Ç','È'=>'È','É'=>'É','Ê'=>'Ê','Ë'=>'Ë','Ì'=>'Ì','Í'=>'Í','Î'=>'Î','Ï'=>'Ï','Ñ'=>'Ñ','Ò'=>'Ò','Ó'=>'Ó','Ô'=>'Ô','Õ'=>'Õ','Ö'=>'Ö','Ù'=>'Ù','Ú'=>'Ú','Û'=>'Û','Ü'=>'Ü','Ý'=>'Ý','à'=>'à','á'=>'á','â'=>'â','ã'=>'ã','ä'=>'ä','å'=>'å','ç'=>'ç','è'=>'è','é'=>'é','ê'=>'ê','ë'=>'ë','ì'=>'ì','í'=>'í','î'=>'î','ï'=>'ï','ñ'=>'ñ','ò'=>'ò','ó'=>'ó','ô'=>'ô','õ'=>'õ','ö'=>'ö','ù'=>'ù','ú'=>'ú','û'=>'û','ü'=>'ü','ý'=>'ý','ÿ'=>'ÿ','Ā'=>'Ā','ā'=>'ā','Ă'=>'Ă','ă'=>'ă','Ą'=>'Ą','ą'=>'ą','Ć'=>'Ć','ć'=>'ć','Ĉ'=>'Ĉ','ĉ'=>'ĉ','Ċ'=>'Ċ','ċ'=>'ċ','Č'=>'Č','č'=>'č','Ď'=>'Ď','ď'=>'ď','Ē'=>'Ē','ē'=>'ē','Ĕ'=>'Ĕ','ĕ'=>'ĕ','Ė'=>'Ė','ė'=>'ė','Ę'=>'Ę','ę'=>'ę','Ě'=>'Ě','ě'=>'ě','Ĝ'=>'Ĝ','ĝ'=>'ĝ','Ğ'=>'Ğ','ğ'=>'ğ','Ġ'=>'Ġ','ġ'=>'ġ','Ģ'=>'Ģ','ģ'=>'ģ','Ĥ'=>'Ĥ','ĥ'=>'ĥ','Ĩ'=>'Ĩ','ĩ'=>'ĩ','Ī'=>'Ī','ī'=>'ī','Ĭ'=>'Ĭ','ĭ'=>'ĭ','Į'=>'Į','į'=>'į','İ'=>'İ','Ĵ'=>'Ĵ','ĵ'=>'ĵ','Ķ'=>'Ķ','ķ'=>'ķ','Ĺ'=>'Ĺ','ĺ'=>'ĺ','Ļ'=>'Ļ','ļ'=>'ļ','Ľ'=>'Ľ','ľ'=>'ľ','Ń'=>'Ń','ń'=>'ń','Ņ'=>'Ņ','ņ'=>'ņ','Ň'=>'Ň','ň'=>'ň','Ō'=>'Ō','ō'=>'ō','Ŏ'=>'Ŏ','ŏ'=>'ŏ','Ő'=>'Ő','ő'=>'ő','Ŕ'=>'Ŕ','ŕ'=>'ŕ','Ŗ'=>'Ŗ','ŗ'=>'ŗ','Ř'=>'Ř','ř'=>'ř','Ś'=>'Ś','ś'=>'ś','Ŝ'=>'Ŝ','ŝ'=>'ŝ','Ş'=>'Ş','ş'=>'ş','Š'=>'Š','š'=>'š','Ţ'=>'Ţ','ţ'=>'ţ','Ť'=>'Ť','ť'=>'ť','Ũ'=>'Ũ','ũ'=>'ũ','Ū'=>'Ū','ū'=>'ū','Ŭ'=>'Ŭ','ŭ'=>'ŭ','Ů'=>'Ů','ů'=>'ů','Ű'=>'Ű','ű'=>'ű','Ų'=>'Ų','ų'=>'ų','Ŵ'=>'Ŵ','ŵ'=>'ŵ','Ŷ'=>'Ŷ','ŷ'=>'ŷ','Ÿ'=>'Ÿ','Ź'=>'Ź','ź'=>'ź','Ż'=>'Ż','ż'=>'ż','Ž'=>'Ž','ž'=>'ž','Ơ'=>'Ơ','ơ'=>'ơ','Ư'=>'Ư','ư'=>'ư','Ǎ'=>'Ǎ','ǎ'=>'ǎ','Ǐ'=>'Ǐ','ǐ'=>'ǐ','Ǒ'=>'Ǒ','ǒ'=>'ǒ','Ǔ'=>'Ǔ','ǔ'=>'ǔ','Ǖ'=>'Ǖ','ǖ'=>'ǖ','Ǘ'=>'Ǘ','ǘ'=>'ǘ','Ǚ'=>'Ǚ','ǚ'=>'ǚ','Ǜ'=>'Ǜ','ǜ'=>'ǜ','Ǟ'=>'Ǟ','ǟ'=>'ǟ','Ǡ'=>'Ǡ','ǡ'=>'ǡ','Ǣ'=>'Ǣ','ǣ'=>'ǣ','Ǧ'=>'Ǧ','ǧ'=>'ǧ','Ǩ'=>'Ǩ','ǩ'=>'ǩ','Ǫ'=>'Ǫ','ǫ'=>'ǫ','Ǭ'=>'Ǭ','ǭ'=>'ǭ','Ǯ'=>'Ǯ','ǯ'=>'ǯ','ǰ'=>'ǰ','Ǵ'=>'Ǵ','ǵ'=>'ǵ','Ǹ'=>'Ǹ','ǹ'=>'ǹ','Ǻ'=>'Ǻ','ǻ'=>'ǻ','Ǽ'=>'Ǽ','ǽ'=>'ǽ','Ǿ'=>'Ǿ','ǿ'=>'ǿ','Ȁ'=>'Ȁ','ȁ'=>'ȁ','Ȃ'=>'Ȃ','ȃ'=>'ȃ','Ȅ'=>'Ȅ','ȅ'=>'ȅ','Ȇ'=>'Ȇ','ȇ'=>'ȇ','Ȉ'=>'Ȉ','ȉ'=>'ȉ','Ȋ'=>'Ȋ','ȋ'=>'ȋ','Ȍ'=>'Ȍ','ȍ'=>'ȍ','Ȏ'=>'Ȏ','ȏ'=>'ȏ','Ȑ'=>'Ȑ','ȑ'=>'ȑ','Ȓ'=>'Ȓ','ȓ'=>'ȓ','Ȕ'=>'Ȕ','ȕ'=>'ȕ','Ȗ'=>'Ȗ','ȗ'=>'ȗ','Ș'=>'Ș','ș'=>'ș','Ț'=>'Ț','ț'=>'ț','Ȟ'=>'Ȟ','ȟ'=>'ȟ','Ȧ'=>'Ȧ','ȧ'=>'ȧ','Ȩ'=>'Ȩ','ȩ'=>'ȩ','Ȫ'=>'Ȫ','ȫ'=>'ȫ','Ȭ'=>'Ȭ','ȭ'=>'ȭ','Ȯ'=>'Ȯ','ȯ'=>'ȯ','Ȱ'=>'Ȱ','ȱ'=>'ȱ','Ȳ'=>'Ȳ','ȳ'=>'ȳ','̈́'=>'̈́','΅'=>'΅','Ά'=>'Ά','Έ'=>'Έ','Ή'=>'Ή','Ί'=>'Ί','Ό'=>'Ό','Ύ'=>'Ύ','Ώ'=>'Ώ','ΐ'=>'ΐ','Ϊ'=>'Ϊ','Ϋ'=>'Ϋ','ά'=>'ά','έ'=>'έ','ή'=>'ή','ί'=>'ί','ΰ'=>'ΰ','ϊ'=>'ϊ','ϋ'=>'ϋ','ό'=>'ό','ύ'=>'ύ','ώ'=>'ώ','ϓ'=>'ϓ','ϔ'=>'ϔ','Ѐ'=>'Ѐ','Ё'=>'Ё','Ѓ'=>'Ѓ','Ї'=>'Ї','Ќ'=>'Ќ','Ѝ'=>'Ѝ','Ў'=>'Ў','Й'=>'Й','й'=>'й','ѐ'=>'ѐ','ё'=>'ё','ѓ'=>'ѓ','ї'=>'ї','ќ'=>'ќ','ѝ'=>'ѝ','ў'=>'ў','Ѷ'=>'Ѷ','ѷ'=>'ѷ','Ӂ'=>'Ӂ','ӂ'=>'ӂ','Ӑ'=>'Ӑ','ӑ'=>'ӑ','Ӓ'=>'Ӓ','ӓ'=>'ӓ','Ӗ'=>'Ӗ','ӗ'=>'ӗ','Ӛ'=>'Ӛ','ӛ'=>'ӛ','Ӝ'=>'Ӝ','ӝ'=>'ӝ','Ӟ'=>'Ӟ','ӟ'=>'ӟ','Ӣ'=>'Ӣ','ӣ'=>'ӣ','Ӥ'=>'Ӥ','ӥ'=>'ӥ','Ӧ'=>'Ӧ','ӧ'=>'ӧ','Ӫ'=>'Ӫ','ӫ'=>'ӫ','Ӭ'=>'Ӭ','ӭ'=>'ӭ','Ӯ'=>'Ӯ','ӯ'=>'ӯ','Ӱ'=>'Ӱ','ӱ'=>'ӱ','Ӳ'=>'Ӳ','ӳ'=>'ӳ','Ӵ'=>'Ӵ','ӵ'=>'ӵ','Ӹ'=>'Ӹ','ӹ'=>'ӹ','آ'=>'آ','أ'=>'أ','ؤ'=>'ؤ','إ'=>'إ','ئ'=>'ئ','ۀ'=>'ۀ','ۂ'=>'ۂ','ۓ'=>'ۓ','ऩ'=>'ऩ','ऱ'=>'ऱ','ऴ'=>'ऴ','ো'=>'ো','ৌ'=>'ৌ','ୈ'=>'ୈ','ୋ'=>'ୋ','ୌ'=>'ୌ','ஔ'=>'ஔ','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','ై'=>'ై','ೀ'=>'ೀ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','ේ'=>'ේ','ො'=>'ො','ෝ'=>'ෝ','ෞ'=>'ෞ','ཱི'=>'ཱི','ཱུ'=>'ཱུ','ཱྀ'=>'ཱྀ','ဦ'=>'ဦ','ᬆ'=>'ᬆ','ᬈ'=>'ᬈ','ᬊ'=>'ᬊ','ᬌ'=>'ᬌ','ᬎ'=>'ᬎ','ᬒ'=>'ᬒ','ᬻ'=>'ᬻ','ᬽ'=>'ᬽ','ᭀ'=>'ᭀ','ᭁ'=>'ᭁ','ᭃ'=>'ᭃ','Ḁ'=>'Ḁ','ḁ'=>'ḁ','Ḃ'=>'Ḃ','ḃ'=>'ḃ','Ḅ'=>'Ḅ','ḅ'=>'ḅ','Ḇ'=>'Ḇ','ḇ'=>'ḇ','Ḉ'=>'Ḉ','ḉ'=>'ḉ','Ḋ'=>'Ḋ','ḋ'=>'ḋ','Ḍ'=>'Ḍ','ḍ'=>'ḍ','Ḏ'=>'Ḏ','ḏ'=>'ḏ','Ḑ'=>'Ḑ','ḑ'=>'ḑ','Ḓ'=>'Ḓ','ḓ'=>'ḓ','Ḕ'=>'Ḕ','ḕ'=>'ḕ','Ḗ'=>'Ḗ','ḗ'=>'ḗ','Ḙ'=>'Ḙ','ḙ'=>'ḙ','Ḛ'=>'Ḛ','ḛ'=>'ḛ','Ḝ'=>'Ḝ','ḝ'=>'ḝ','Ḟ'=>'Ḟ','ḟ'=>'ḟ','Ḡ'=>'Ḡ','ḡ'=>'ḡ','Ḣ'=>'Ḣ','ḣ'=>'ḣ','Ḥ'=>'Ḥ','ḥ'=>'ḥ','Ḧ'=>'Ḧ','ḧ'=>'ḧ','Ḩ'=>'Ḩ','ḩ'=>'ḩ','Ḫ'=>'Ḫ','ḫ'=>'ḫ','Ḭ'=>'Ḭ','ḭ'=>'ḭ','Ḯ'=>'Ḯ','ḯ'=>'ḯ','Ḱ'=>'Ḱ','ḱ'=>'ḱ','Ḳ'=>'Ḳ','ḳ'=>'ḳ','Ḵ'=>'Ḵ','ḵ'=>'ḵ','Ḷ'=>'Ḷ','ḷ'=>'ḷ','Ḹ'=>'Ḹ','ḹ'=>'ḹ','Ḻ'=>'Ḻ','ḻ'=>'ḻ','Ḽ'=>'Ḽ','ḽ'=>'ḽ','Ḿ'=>'Ḿ','ḿ'=>'ḿ','Ṁ'=>'Ṁ','ṁ'=>'ṁ','Ṃ'=>'Ṃ','ṃ'=>'ṃ','Ṅ'=>'Ṅ','ṅ'=>'ṅ','Ṇ'=>'Ṇ','ṇ'=>'ṇ','Ṉ'=>'Ṉ','ṉ'=>'ṉ','Ṋ'=>'Ṋ','ṋ'=>'ṋ','Ṍ'=>'Ṍ','ṍ'=>'ṍ','Ṏ'=>'Ṏ','ṏ'=>'ṏ','Ṑ'=>'Ṑ','ṑ'=>'ṑ','Ṓ'=>'Ṓ','ṓ'=>'ṓ','Ṕ'=>'Ṕ','ṕ'=>'ṕ','Ṗ'=>'Ṗ','ṗ'=>'ṗ','Ṙ'=>'Ṙ','ṙ'=>'ṙ','Ṛ'=>'Ṛ','ṛ'=>'ṛ','Ṝ'=>'Ṝ','ṝ'=>'ṝ','Ṟ'=>'Ṟ','ṟ'=>'ṟ','Ṡ'=>'Ṡ','ṡ'=>'ṡ','Ṣ'=>'Ṣ','ṣ'=>'ṣ','Ṥ'=>'Ṥ','ṥ'=>'ṥ','Ṧ'=>'Ṧ','ṧ'=>'ṧ','Ṩ'=>'Ṩ','ṩ'=>'ṩ','Ṫ'=>'Ṫ','ṫ'=>'ṫ','Ṭ'=>'Ṭ','ṭ'=>'ṭ','Ṯ'=>'Ṯ','ṯ'=>'ṯ','Ṱ'=>'Ṱ','ṱ'=>'ṱ','Ṳ'=>'Ṳ','ṳ'=>'ṳ','Ṵ'=>'Ṵ','ṵ'=>'ṵ','Ṷ'=>'Ṷ','ṷ'=>'ṷ','Ṹ'=>'Ṹ','ṹ'=>'ṹ','Ṻ'=>'Ṻ','ṻ'=>'ṻ','Ṽ'=>'Ṽ','ṽ'=>'ṽ','Ṿ'=>'Ṿ','ṿ'=>'ṿ','Ẁ'=>'Ẁ','ẁ'=>'ẁ','Ẃ'=>'Ẃ','ẃ'=>'ẃ','Ẅ'=>'Ẅ','ẅ'=>'ẅ','Ẇ'=>'Ẇ','ẇ'=>'ẇ','Ẉ'=>'Ẉ','ẉ'=>'ẉ','Ẋ'=>'Ẋ','ẋ'=>'ẋ','Ẍ'=>'Ẍ','ẍ'=>'ẍ','Ẏ'=>'Ẏ','ẏ'=>'ẏ','Ẑ'=>'Ẑ','ẑ'=>'ẑ','Ẓ'=>'Ẓ','ẓ'=>'ẓ','Ẕ'=>'Ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẛ'=>'ẛ','Ạ'=>'Ạ','ạ'=>'ạ','Ả'=>'Ả','ả'=>'ả','Ấ'=>'Ấ','ấ'=>'ấ','Ầ'=>'Ầ','ầ'=>'ầ','Ẩ'=>'Ẩ','ẩ'=>'ẩ','Ẫ'=>'Ẫ','ẫ'=>'ẫ','Ậ'=>'Ậ','ậ'=>'ậ','Ắ'=>'Ắ','ắ'=>'ắ','Ằ'=>'Ằ','ằ'=>'ằ','Ẳ'=>'Ẳ','ẳ'=>'ẳ','Ẵ'=>'Ẵ','ẵ'=>'ẵ','Ặ'=>'Ặ','ặ'=>'ặ','Ẹ'=>'Ẹ','ẹ'=>'ẹ','Ẻ'=>'Ẻ','ẻ'=>'ẻ','Ẽ'=>'Ẽ','ẽ'=>'ẽ','Ế'=>'Ế','ế'=>'ế','Ề'=>'Ề','ề'=>'ề','Ể'=>'Ể','ể'=>'ể','Ễ'=>'Ễ','ễ'=>'ễ','Ệ'=>'Ệ','ệ'=>'ệ','Ỉ'=>'Ỉ','ỉ'=>'ỉ','Ị'=>'Ị','ị'=>'ị','Ọ'=>'Ọ','ọ'=>'ọ','Ỏ'=>'Ỏ','ỏ'=>'ỏ','Ố'=>'Ố','ố'=>'ố','Ồ'=>'Ồ','ồ'=>'ồ','Ổ'=>'Ổ','ổ'=>'ổ','Ỗ'=>'Ỗ','ỗ'=>'ỗ','Ộ'=>'Ộ','ộ'=>'ộ','Ớ'=>'Ớ','ớ'=>'ớ','Ờ'=>'Ờ','ờ'=>'ờ','Ở'=>'Ở','ở'=>'ở','Ỡ'=>'Ỡ','ỡ'=>'ỡ','Ợ'=>'Ợ','ợ'=>'ợ','Ụ'=>'Ụ','ụ'=>'ụ','Ủ'=>'Ủ','ủ'=>'ủ','Ứ'=>'Ứ','ứ'=>'ứ','Ừ'=>'Ừ','ừ'=>'ừ','Ử'=>'Ử','ử'=>'ử','Ữ'=>'Ữ','ữ'=>'ữ','Ự'=>'Ự','ự'=>'ự','Ỳ'=>'Ỳ','ỳ'=>'ỳ','Ỵ'=>'Ỵ','ỵ'=>'ỵ','Ỷ'=>'Ỷ','ỷ'=>'ỷ','Ỹ'=>'Ỹ','ỹ'=>'ỹ','ἀ'=>'ἀ','ἁ'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἄ','ἅ'=>'ἅ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'Ἀ','Ἁ'=>'Ἁ','Ἂ'=>'Ἂ','Ἃ'=>'Ἃ','Ἄ'=>'Ἄ','Ἅ'=>'Ἅ','Ἆ'=>'Ἆ','Ἇ'=>'Ἇ','ἐ'=>'ἐ','ἑ'=>'ἑ','ἒ'=>'ἒ','ἓ'=>'ἓ','ἔ'=>'ἔ','ἕ'=>'ἕ','Ἐ'=>'Ἐ','Ἑ'=>'Ἑ','Ἒ'=>'Ἒ','Ἓ'=>'Ἓ','Ἔ'=>'Ἔ','Ἕ'=>'Ἕ','ἠ'=>'ἠ','ἡ'=>'ἡ','ἢ'=>'ἢ','ἣ'=>'ἣ','ἤ'=>'ἤ','ἥ'=>'ἥ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'Ἠ','Ἡ'=>'Ἡ','Ἢ'=>'Ἢ','Ἣ'=>'Ἣ','Ἤ'=>'Ἤ','Ἥ'=>'Ἥ','Ἦ'=>'Ἦ','Ἧ'=>'Ἧ','ἰ'=>'ἰ','ἱ'=>'ἱ','ἲ'=>'ἲ','ἳ'=>'ἳ','ἴ'=>'ἴ','ἵ'=>'ἵ','ἶ'=>'ἶ','ἷ'=>'ἷ','Ἰ'=>'Ἰ','Ἱ'=>'Ἱ','Ἲ'=>'Ἲ','Ἳ'=>'Ἳ','Ἴ'=>'Ἴ','Ἵ'=>'Ἵ','Ἶ'=>'Ἶ','Ἷ'=>'Ἷ','ὀ'=>'ὀ','ὁ'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὄ','ὅ'=>'ὅ','Ὀ'=>'Ὀ','Ὁ'=>'Ὁ','Ὂ'=>'Ὂ','Ὃ'=>'Ὃ','Ὄ'=>'Ὄ','Ὅ'=>'Ὅ','ὐ'=>'ὐ','ὑ'=>'ὑ','ὒ'=>'ὒ','ὓ'=>'ὓ','ὔ'=>'ὔ','ὕ'=>'ὕ','ὖ'=>'ὖ','ὗ'=>'ὗ','Ὑ'=>'Ὑ','Ὓ'=>'Ὓ','Ὕ'=>'Ὕ','Ὗ'=>'Ὗ','ὠ'=>'ὠ','ὡ'=>'ὡ','ὢ'=>'ὢ','ὣ'=>'ὣ','ὤ'=>'ὤ','ὥ'=>'ὥ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'Ὠ','Ὡ'=>'Ὡ','Ὢ'=>'Ὢ','Ὣ'=>'Ὣ','Ὤ'=>'Ὤ','Ὥ'=>'Ὥ','Ὦ'=>'Ὦ','Ὧ'=>'Ὧ','ὰ'=>'ὰ','ὲ'=>'ὲ','ὴ'=>'ὴ','ὶ'=>'ὶ','ὸ'=>'ὸ','ὺ'=>'ὺ','ὼ'=>'ὼ','ᾀ'=>'ᾀ','ᾁ'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ᾄ','ᾅ'=>'ᾅ','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾈ','ᾉ'=>'ᾉ','ᾊ'=>'ᾊ','ᾋ'=>'ᾋ','ᾌ'=>'ᾌ','ᾍ'=>'ᾍ','ᾎ'=>'ᾎ','ᾏ'=>'ᾏ','ᾐ'=>'ᾐ','ᾑ'=>'ᾑ','ᾒ'=>'ᾒ','ᾓ'=>'ᾓ','ᾔ'=>'ᾔ','ᾕ'=>'ᾕ','ᾖ'=>'ᾖ','ᾗ'=>'ᾗ','ᾘ'=>'ᾘ','ᾙ'=>'ᾙ','ᾚ'=>'ᾚ','ᾛ'=>'ᾛ','ᾜ'=>'ᾜ','ᾝ'=>'ᾝ','ᾞ'=>'ᾞ','ᾟ'=>'ᾟ','ᾠ'=>'ᾠ','ᾡ'=>'ᾡ','ᾢ'=>'ᾢ','ᾣ'=>'ᾣ','ᾤ'=>'ᾤ','ᾥ'=>'ᾥ','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾨ','ᾩ'=>'ᾩ','ᾪ'=>'ᾪ','ᾫ'=>'ᾫ','ᾬ'=>'ᾬ','ᾭ'=>'ᾭ','ᾮ'=>'ᾮ','ᾯ'=>'ᾯ','ᾰ'=>'ᾰ','ᾱ'=>'ᾱ','ᾲ'=>'ᾲ','ᾳ'=>'ᾳ','ᾴ'=>'ᾴ','ᾶ'=>'ᾶ','ᾷ'=>'ᾷ','Ᾰ'=>'Ᾰ','Ᾱ'=>'Ᾱ','Ὰ'=>'Ὰ','ᾼ'=>'ᾼ','῁'=>'῁','ῂ'=>'ῂ','ῃ'=>'ῃ','ῄ'=>'ῄ','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'Ὲ','Ὴ'=>'Ὴ','ῌ'=>'ῌ','῍'=>'῍','῎'=>'῎','῏'=>'῏','ῐ'=>'ῐ','ῑ'=>'ῑ','ῒ'=>'ῒ','ῖ'=>'ῖ','ῗ'=>'ῗ','Ῐ'=>'Ῐ','Ῑ'=>'Ῑ','Ὶ'=>'Ὶ','῝'=>'῝','῞'=>'῞','῟'=>'῟','ῠ'=>'ῠ','ῡ'=>'ῡ','ῢ'=>'ῢ','ῤ'=>'ῤ','ῥ'=>'ῥ','ῦ'=>'ῦ','ῧ'=>'ῧ','Ῠ'=>'Ῠ','Ῡ'=>'Ῡ','Ὺ'=>'Ὺ','Ῥ'=>'Ῥ','῭'=>'῭','ῲ'=>'ῲ','ῳ'=>'ῳ','ῴ'=>'ῴ','ῶ'=>'ῶ','ῷ'=>'ῷ','Ὸ'=>'Ὸ','Ὼ'=>'Ὼ','ῼ'=>'ῼ','↚'=>'↚','↛'=>'↛','↮'=>'↮','⇍'=>'⇍','⇎'=>'⇎','⇏'=>'⇏','∄'=>'∄','∉'=>'∉','∌'=>'∌','∤'=>'∤','∦'=>'∦','≁'=>'≁','≄'=>'≄','≇'=>'≇','≉'=>'≉','≠'=>'≠','≢'=>'≢','≭'=>'≭','≮'=>'≮','≯'=>'≯','≰'=>'≰','≱'=>'≱','≴'=>'≴','≵'=>'≵','≸'=>'≸','≹'=>'≹','⊀'=>'⊀','⊁'=>'⊁','⊄'=>'⊄','⊅'=>'⊅','⊈'=>'⊈','⊉'=>'⊉','⊬'=>'⊬','⊭'=>'⊭','⊮'=>'⊮','⊯'=>'⊯','⋠'=>'⋠','⋡'=>'⋡','⋢'=>'⋢','⋣'=>'⋣','⋪'=>'⋪','⋫'=>'⋫','⋬'=>'⋬','⋭'=>'⋭','が'=>'が','ぎ'=>'ぎ','ぐ'=>'ぐ','げ'=>'げ','ご'=>'ご','ざ'=>'ざ','じ'=>'じ','ず'=>'ず','ぜ'=>'ぜ','ぞ'=>'ぞ','だ'=>'だ','ぢ'=>'ぢ','づ'=>'づ','で'=>'で','ど'=>'ど','ば'=>'ば','ぱ'=>'ぱ','び'=>'び','ぴ'=>'ぴ','ぶ'=>'ぶ','ぷ'=>'ぷ','べ'=>'べ','ぺ'=>'ぺ','ぼ'=>'ぼ','ぽ'=>'ぽ','ゔ'=>'ゔ','ゞ'=>'ゞ','ガ'=>'ガ','ギ'=>'ギ','グ'=>'グ','ゲ'=>'ゲ','ゴ'=>'ゴ','ザ'=>'ザ','ジ'=>'ジ','ズ'=>'ズ','ゼ'=>'ゼ','ゾ'=>'ゾ','ダ'=>'ダ','ヂ'=>'ヂ','ヅ'=>'ヅ','デ'=>'デ','ド'=>'ド','バ'=>'バ','パ'=>'パ','ビ'=>'ビ','ピ'=>'ピ','ブ'=>'ブ','プ'=>'プ','ベ'=>'ベ','ペ'=>'ペ','ボ'=>'ボ','ポ'=>'ポ','ヴ'=>'ヴ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ヾ'=>'ヾ');
\ No newline at end of file +$GLOBALS['utf_canonical_comp']=array('À'=>'À','Á'=>'Á','Â'=>'Â','Ã'=>'Ã','Ä'=>'Ä','Å'=>'Å','Ç'=>'Ç','È'=>'È','É'=>'É','Ê'=>'Ê','Ë'=>'Ë','Ì'=>'Ì','Í'=>'Í','Î'=>'Î','Ï'=>'Ï','Ñ'=>'Ñ','Ò'=>'Ò','Ó'=>'Ó','Ô'=>'Ô','Õ'=>'Õ','Ö'=>'Ö','Ù'=>'Ù','Ú'=>'Ú','Û'=>'Û','Ü'=>'Ü','Ý'=>'Ý','à'=>'à','á'=>'á','â'=>'â','ã'=>'ã','ä'=>'ä','å'=>'å','ç'=>'ç','è'=>'è','é'=>'é','ê'=>'ê','ë'=>'ë','ì'=>'ì','í'=>'í','î'=>'î','ï'=>'ï','ñ'=>'ñ','ò'=>'ò','ó'=>'ó','ô'=>'ô','õ'=>'õ','ö'=>'ö','ù'=>'ù','ú'=>'ú','û'=>'û','ü'=>'ü','ý'=>'ý','ÿ'=>'ÿ','Ā'=>'Ā','ā'=>'ā','Ă'=>'Ă','ă'=>'ă','Ą'=>'Ą','ą'=>'ą','Ć'=>'Ć','ć'=>'ć','Ĉ'=>'Ĉ','ĉ'=>'ĉ','Ċ'=>'Ċ','ċ'=>'ċ','Č'=>'Č','č'=>'č','Ď'=>'Ď','ď'=>'ď','Ē'=>'Ē','ē'=>'ē','Ĕ'=>'Ĕ','ĕ'=>'ĕ','Ė'=>'Ė','ė'=>'ė','Ę'=>'Ę','ę'=>'ę','Ě'=>'Ě','ě'=>'ě','Ĝ'=>'Ĝ','ĝ'=>'ĝ','Ğ'=>'Ğ','ğ'=>'ğ','Ġ'=>'Ġ','ġ'=>'ġ','Ģ'=>'Ģ','ģ'=>'ģ','Ĥ'=>'Ĥ','ĥ'=>'ĥ','Ĩ'=>'Ĩ','ĩ'=>'ĩ','Ī'=>'Ī','ī'=>'ī','Ĭ'=>'Ĭ','ĭ'=>'ĭ','Į'=>'Į','į'=>'į','İ'=>'İ','Ĵ'=>'Ĵ','ĵ'=>'ĵ','Ķ'=>'Ķ','ķ'=>'ķ','Ĺ'=>'Ĺ','ĺ'=>'ĺ','Ļ'=>'Ļ','ļ'=>'ļ','Ľ'=>'Ľ','ľ'=>'ľ','Ń'=>'Ń','ń'=>'ń','Ņ'=>'Ņ','ņ'=>'ņ','Ň'=>'Ň','ň'=>'ň','Ō'=>'Ō','ō'=>'ō','Ŏ'=>'Ŏ','ŏ'=>'ŏ','Ő'=>'Ő','ő'=>'ő','Ŕ'=>'Ŕ','ŕ'=>'ŕ','Ŗ'=>'Ŗ','ŗ'=>'ŗ','Ř'=>'Ř','ř'=>'ř','Ś'=>'Ś','ś'=>'ś','Ŝ'=>'Ŝ','ŝ'=>'ŝ','Ş'=>'Ş','ş'=>'ş','Š'=>'Š','š'=>'š','Ţ'=>'Ţ','ţ'=>'ţ','Ť'=>'Ť','ť'=>'ť','Ũ'=>'Ũ','ũ'=>'ũ','Ū'=>'Ū','ū'=>'ū','Ŭ'=>'Ŭ','ŭ'=>'ŭ','Ů'=>'Ů','ů'=>'ů','Ű'=>'Ű','ű'=>'ű','Ų'=>'Ų','ų'=>'ų','Ŵ'=>'Ŵ','ŵ'=>'ŵ','Ŷ'=>'Ŷ','ŷ'=>'ŷ','Ÿ'=>'Ÿ','Ź'=>'Ź','ź'=>'ź','Ż'=>'Ż','ż'=>'ż','Ž'=>'Ž','ž'=>'ž','Ơ'=>'Ơ','ơ'=>'ơ','Ư'=>'Ư','ư'=>'ư','Ǎ'=>'Ǎ','ǎ'=>'ǎ','Ǐ'=>'Ǐ','ǐ'=>'ǐ','Ǒ'=>'Ǒ','ǒ'=>'ǒ','Ǔ'=>'Ǔ','ǔ'=>'ǔ','Ǖ'=>'Ǖ','ǖ'=>'ǖ','Ǘ'=>'Ǘ','ǘ'=>'ǘ','Ǚ'=>'Ǚ','ǚ'=>'ǚ','Ǜ'=>'Ǜ','ǜ'=>'ǜ','Ǟ'=>'Ǟ','ǟ'=>'ǟ','Ǡ'=>'Ǡ','ǡ'=>'ǡ','Ǣ'=>'Ǣ','ǣ'=>'ǣ','Ǧ'=>'Ǧ','ǧ'=>'ǧ','Ǩ'=>'Ǩ','ǩ'=>'ǩ','Ǫ'=>'Ǫ','ǫ'=>'ǫ','Ǭ'=>'Ǭ','ǭ'=>'ǭ','Ǯ'=>'Ǯ','ǯ'=>'ǯ','ǰ'=>'ǰ','Ǵ'=>'Ǵ','ǵ'=>'ǵ','Ǹ'=>'Ǹ','ǹ'=>'ǹ','Ǻ'=>'Ǻ','ǻ'=>'ǻ','Ǽ'=>'Ǽ','ǽ'=>'ǽ','Ǿ'=>'Ǿ','ǿ'=>'ǿ','Ȁ'=>'Ȁ','ȁ'=>'ȁ','Ȃ'=>'Ȃ','ȃ'=>'ȃ','Ȅ'=>'Ȅ','ȅ'=>'ȅ','Ȇ'=>'Ȇ','ȇ'=>'ȇ','Ȉ'=>'Ȉ','ȉ'=>'ȉ','Ȋ'=>'Ȋ','ȋ'=>'ȋ','Ȍ'=>'Ȍ','ȍ'=>'ȍ','Ȏ'=>'Ȏ','ȏ'=>'ȏ','Ȑ'=>'Ȑ','ȑ'=>'ȑ','Ȓ'=>'Ȓ','ȓ'=>'ȓ','Ȕ'=>'Ȕ','ȕ'=>'ȕ','Ȗ'=>'Ȗ','ȗ'=>'ȗ','Ș'=>'Ș','ș'=>'ș','Ț'=>'Ț','ț'=>'ț','Ȟ'=>'Ȟ','ȟ'=>'ȟ','Ȧ'=>'Ȧ','ȧ'=>'ȧ','Ȩ'=>'Ȩ','ȩ'=>'ȩ','Ȫ'=>'Ȫ','ȫ'=>'ȫ','Ȭ'=>'Ȭ','ȭ'=>'ȭ','Ȯ'=>'Ȯ','ȯ'=>'ȯ','Ȱ'=>'Ȱ','ȱ'=>'ȱ','Ȳ'=>'Ȳ','ȳ'=>'ȳ','̈́'=>'̈́','΅'=>'΅','Ά'=>'Ά','Έ'=>'Έ','Ή'=>'Ή','Ί'=>'Ί','Ό'=>'Ό','Ύ'=>'Ύ','Ώ'=>'Ώ','ΐ'=>'ΐ','Ϊ'=>'Ϊ','Ϋ'=>'Ϋ','ά'=>'ά','έ'=>'έ','ή'=>'ή','ί'=>'ί','ΰ'=>'ΰ','ϊ'=>'ϊ','ϋ'=>'ϋ','ό'=>'ό','ύ'=>'ύ','ώ'=>'ώ','ϓ'=>'ϓ','ϔ'=>'ϔ','Ѐ'=>'Ѐ','Ё'=>'Ё','Ѓ'=>'Ѓ','Ї'=>'Ї','Ќ'=>'Ќ','Ѝ'=>'Ѝ','Ў'=>'Ў','Й'=>'Й','й'=>'й','ѐ'=>'ѐ','ё'=>'ё','ѓ'=>'ѓ','ї'=>'ї','ќ'=>'ќ','ѝ'=>'ѝ','ў'=>'ў','Ѷ'=>'Ѷ','ѷ'=>'ѷ','Ӂ'=>'Ӂ','ӂ'=>'ӂ','Ӑ'=>'Ӑ','ӑ'=>'ӑ','Ӓ'=>'Ӓ','ӓ'=>'ӓ','Ӗ'=>'Ӗ','ӗ'=>'ӗ','Ӛ'=>'Ӛ','ӛ'=>'ӛ','Ӝ'=>'Ӝ','ӝ'=>'ӝ','Ӟ'=>'Ӟ','ӟ'=>'ӟ','Ӣ'=>'Ӣ','ӣ'=>'ӣ','Ӥ'=>'Ӥ','ӥ'=>'ӥ','Ӧ'=>'Ӧ','ӧ'=>'ӧ','Ӫ'=>'Ӫ','ӫ'=>'ӫ','Ӭ'=>'Ӭ','ӭ'=>'ӭ','Ӯ'=>'Ӯ','ӯ'=>'ӯ','Ӱ'=>'Ӱ','ӱ'=>'ӱ','Ӳ'=>'Ӳ','ӳ'=>'ӳ','Ӵ'=>'Ӵ','ӵ'=>'ӵ','Ӹ'=>'Ӹ','ӹ'=>'ӹ','آ'=>'آ','أ'=>'أ','ؤ'=>'ؤ','إ'=>'إ','ئ'=>'ئ','ۀ'=>'ۀ','ۂ'=>'ۂ','ۓ'=>'ۓ','ऩ'=>'ऩ','ऱ'=>'ऱ','ऴ'=>'ऴ','ো'=>'ো','ৌ'=>'ৌ','ୈ'=>'ୈ','ୋ'=>'ୋ','ୌ'=>'ୌ','ஔ'=>'ஔ','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','ై'=>'ై','ೀ'=>'ೀ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','ේ'=>'ේ','ො'=>'ො','ෝ'=>'ෝ','ෞ'=>'ෞ','ཱི'=>'ཱི','ཱུ'=>'ཱུ','ཱྀ'=>'ཱྀ','ဦ'=>'ဦ','ᬆ'=>'ᬆ','ᬈ'=>'ᬈ','ᬊ'=>'ᬊ','ᬌ'=>'ᬌ','ᬎ'=>'ᬎ','ᬒ'=>'ᬒ','ᬻ'=>'ᬻ','ᬽ'=>'ᬽ','ᭀ'=>'ᭀ','ᭁ'=>'ᭁ','ᭃ'=>'ᭃ','Ḁ'=>'Ḁ','ḁ'=>'ḁ','Ḃ'=>'Ḃ','ḃ'=>'ḃ','Ḅ'=>'Ḅ','ḅ'=>'ḅ','Ḇ'=>'Ḇ','ḇ'=>'ḇ','Ḉ'=>'Ḉ','ḉ'=>'ḉ','Ḋ'=>'Ḋ','ḋ'=>'ḋ','Ḍ'=>'Ḍ','ḍ'=>'ḍ','Ḏ'=>'Ḏ','ḏ'=>'ḏ','Ḑ'=>'Ḑ','ḑ'=>'ḑ','Ḓ'=>'Ḓ','ḓ'=>'ḓ','Ḕ'=>'Ḕ','ḕ'=>'ḕ','Ḗ'=>'Ḗ','ḗ'=>'ḗ','Ḙ'=>'Ḙ','ḙ'=>'ḙ','Ḛ'=>'Ḛ','ḛ'=>'ḛ','Ḝ'=>'Ḝ','ḝ'=>'ḝ','Ḟ'=>'Ḟ','ḟ'=>'ḟ','Ḡ'=>'Ḡ','ḡ'=>'ḡ','Ḣ'=>'Ḣ','ḣ'=>'ḣ','Ḥ'=>'Ḥ','ḥ'=>'ḥ','Ḧ'=>'Ḧ','ḧ'=>'ḧ','Ḩ'=>'Ḩ','ḩ'=>'ḩ','Ḫ'=>'Ḫ','ḫ'=>'ḫ','Ḭ'=>'Ḭ','ḭ'=>'ḭ','Ḯ'=>'Ḯ','ḯ'=>'ḯ','Ḱ'=>'Ḱ','ḱ'=>'ḱ','Ḳ'=>'Ḳ','ḳ'=>'ḳ','Ḵ'=>'Ḵ','ḵ'=>'ḵ','Ḷ'=>'Ḷ','ḷ'=>'ḷ','Ḹ'=>'Ḹ','ḹ'=>'ḹ','Ḻ'=>'Ḻ','ḻ'=>'ḻ','Ḽ'=>'Ḽ','ḽ'=>'ḽ','Ḿ'=>'Ḿ','ḿ'=>'ḿ','Ṁ'=>'Ṁ','ṁ'=>'ṁ','Ṃ'=>'Ṃ','ṃ'=>'ṃ','Ṅ'=>'Ṅ','ṅ'=>'ṅ','Ṇ'=>'Ṇ','ṇ'=>'ṇ','Ṉ'=>'Ṉ','ṉ'=>'ṉ','Ṋ'=>'Ṋ','ṋ'=>'ṋ','Ṍ'=>'Ṍ','ṍ'=>'ṍ','Ṏ'=>'Ṏ','ṏ'=>'ṏ','Ṑ'=>'Ṑ','ṑ'=>'ṑ','Ṓ'=>'Ṓ','ṓ'=>'ṓ','Ṕ'=>'Ṕ','ṕ'=>'ṕ','Ṗ'=>'Ṗ','ṗ'=>'ṗ','Ṙ'=>'Ṙ','ṙ'=>'ṙ','Ṛ'=>'Ṛ','ṛ'=>'ṛ','Ṝ'=>'Ṝ','ṝ'=>'ṝ','Ṟ'=>'Ṟ','ṟ'=>'ṟ','Ṡ'=>'Ṡ','ṡ'=>'ṡ','Ṣ'=>'Ṣ','ṣ'=>'ṣ','Ṥ'=>'Ṥ','ṥ'=>'ṥ','Ṧ'=>'Ṧ','ṧ'=>'ṧ','Ṩ'=>'Ṩ','ṩ'=>'ṩ','Ṫ'=>'Ṫ','ṫ'=>'ṫ','Ṭ'=>'Ṭ','ṭ'=>'ṭ','Ṯ'=>'Ṯ','ṯ'=>'ṯ','Ṱ'=>'Ṱ','ṱ'=>'ṱ','Ṳ'=>'Ṳ','ṳ'=>'ṳ','Ṵ'=>'Ṵ','ṵ'=>'ṵ','Ṷ'=>'Ṷ','ṷ'=>'ṷ','Ṹ'=>'Ṹ','ṹ'=>'ṹ','Ṻ'=>'Ṻ','ṻ'=>'ṻ','Ṽ'=>'Ṽ','ṽ'=>'ṽ','Ṿ'=>'Ṿ','ṿ'=>'ṿ','Ẁ'=>'Ẁ','ẁ'=>'ẁ','Ẃ'=>'Ẃ','ẃ'=>'ẃ','Ẅ'=>'Ẅ','ẅ'=>'ẅ','Ẇ'=>'Ẇ','ẇ'=>'ẇ','Ẉ'=>'Ẉ','ẉ'=>'ẉ','Ẋ'=>'Ẋ','ẋ'=>'ẋ','Ẍ'=>'Ẍ','ẍ'=>'ẍ','Ẏ'=>'Ẏ','ẏ'=>'ẏ','Ẑ'=>'Ẑ','ẑ'=>'ẑ','Ẓ'=>'Ẓ','ẓ'=>'ẓ','Ẕ'=>'Ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẛ'=>'ẛ','Ạ'=>'Ạ','ạ'=>'ạ','Ả'=>'Ả','ả'=>'ả','Ấ'=>'Ấ','ấ'=>'ấ','Ầ'=>'Ầ','ầ'=>'ầ','Ẩ'=>'Ẩ','ẩ'=>'ẩ','Ẫ'=>'Ẫ','ẫ'=>'ẫ','Ậ'=>'Ậ','ậ'=>'ậ','Ắ'=>'Ắ','ắ'=>'ắ','Ằ'=>'Ằ','ằ'=>'ằ','Ẳ'=>'Ẳ','ẳ'=>'ẳ','Ẵ'=>'Ẵ','ẵ'=>'ẵ','Ặ'=>'Ặ','ặ'=>'ặ','Ẹ'=>'Ẹ','ẹ'=>'ẹ','Ẻ'=>'Ẻ','ẻ'=>'ẻ','Ẽ'=>'Ẽ','ẽ'=>'ẽ','Ế'=>'Ế','ế'=>'ế','Ề'=>'Ề','ề'=>'ề','Ể'=>'Ể','ể'=>'ể','Ễ'=>'Ễ','ễ'=>'ễ','Ệ'=>'Ệ','ệ'=>'ệ','Ỉ'=>'Ỉ','ỉ'=>'ỉ','Ị'=>'Ị','ị'=>'ị','Ọ'=>'Ọ','ọ'=>'ọ','Ỏ'=>'Ỏ','ỏ'=>'ỏ','Ố'=>'Ố','ố'=>'ố','Ồ'=>'Ồ','ồ'=>'ồ','Ổ'=>'Ổ','ổ'=>'ổ','Ỗ'=>'Ỗ','ỗ'=>'ỗ','Ộ'=>'Ộ','ộ'=>'ộ','Ớ'=>'Ớ','ớ'=>'ớ','Ờ'=>'Ờ','ờ'=>'ờ','Ở'=>'Ở','ở'=>'ở','Ỡ'=>'Ỡ','ỡ'=>'ỡ','Ợ'=>'Ợ','ợ'=>'ợ','Ụ'=>'Ụ','ụ'=>'ụ','Ủ'=>'Ủ','ủ'=>'ủ','Ứ'=>'Ứ','ứ'=>'ứ','Ừ'=>'Ừ','ừ'=>'ừ','Ử'=>'Ử','ử'=>'ử','Ữ'=>'Ữ','ữ'=>'ữ','Ự'=>'Ự','ự'=>'ự','Ỳ'=>'Ỳ','ỳ'=>'ỳ','Ỵ'=>'Ỵ','ỵ'=>'ỵ','Ỷ'=>'Ỷ','ỷ'=>'ỷ','Ỹ'=>'Ỹ','ỹ'=>'ỹ','ἀ'=>'ἀ','ἁ'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἄ','ἅ'=>'ἅ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'Ἀ','Ἁ'=>'Ἁ','Ἂ'=>'Ἂ','Ἃ'=>'Ἃ','Ἄ'=>'Ἄ','Ἅ'=>'Ἅ','Ἆ'=>'Ἆ','Ἇ'=>'Ἇ','ἐ'=>'ἐ','ἑ'=>'ἑ','ἒ'=>'ἒ','ἓ'=>'ἓ','ἔ'=>'ἔ','ἕ'=>'ἕ','Ἐ'=>'Ἐ','Ἑ'=>'Ἑ','Ἒ'=>'Ἒ','Ἓ'=>'Ἓ','Ἔ'=>'Ἔ','Ἕ'=>'Ἕ','ἠ'=>'ἠ','ἡ'=>'ἡ','ἢ'=>'ἢ','ἣ'=>'ἣ','ἤ'=>'ἤ','ἥ'=>'ἥ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'Ἠ','Ἡ'=>'Ἡ','Ἢ'=>'Ἢ','Ἣ'=>'Ἣ','Ἤ'=>'Ἤ','Ἥ'=>'Ἥ','Ἦ'=>'Ἦ','Ἧ'=>'Ἧ','ἰ'=>'ἰ','ἱ'=>'ἱ','ἲ'=>'ἲ','ἳ'=>'ἳ','ἴ'=>'ἴ','ἵ'=>'ἵ','ἶ'=>'ἶ','ἷ'=>'ἷ','Ἰ'=>'Ἰ','Ἱ'=>'Ἱ','Ἲ'=>'Ἲ','Ἳ'=>'Ἳ','Ἴ'=>'Ἴ','Ἵ'=>'Ἵ','Ἶ'=>'Ἶ','Ἷ'=>'Ἷ','ὀ'=>'ὀ','ὁ'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὄ','ὅ'=>'ὅ','Ὀ'=>'Ὀ','Ὁ'=>'Ὁ','Ὂ'=>'Ὂ','Ὃ'=>'Ὃ','Ὄ'=>'Ὄ','Ὅ'=>'Ὅ','ὐ'=>'ὐ','ὑ'=>'ὑ','ὒ'=>'ὒ','ὓ'=>'ὓ','ὔ'=>'ὔ','ὕ'=>'ὕ','ὖ'=>'ὖ','ὗ'=>'ὗ','Ὑ'=>'Ὑ','Ὓ'=>'Ὓ','Ὕ'=>'Ὕ','Ὗ'=>'Ὗ','ὠ'=>'ὠ','ὡ'=>'ὡ','ὢ'=>'ὢ','ὣ'=>'ὣ','ὤ'=>'ὤ','ὥ'=>'ὥ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'Ὠ','Ὡ'=>'Ὡ','Ὢ'=>'Ὢ','Ὣ'=>'Ὣ','Ὤ'=>'Ὤ','Ὥ'=>'Ὥ','Ὦ'=>'Ὦ','Ὧ'=>'Ὧ','ὰ'=>'ὰ','ὲ'=>'ὲ','ὴ'=>'ὴ','ὶ'=>'ὶ','ὸ'=>'ὸ','ὺ'=>'ὺ','ὼ'=>'ὼ','ᾀ'=>'ᾀ','ᾁ'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ᾄ','ᾅ'=>'ᾅ','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾈ','ᾉ'=>'ᾉ','ᾊ'=>'ᾊ','ᾋ'=>'ᾋ','ᾌ'=>'ᾌ','ᾍ'=>'ᾍ','ᾎ'=>'ᾎ','ᾏ'=>'ᾏ','ᾐ'=>'ᾐ','ᾑ'=>'ᾑ','ᾒ'=>'ᾒ','ᾓ'=>'ᾓ','ᾔ'=>'ᾔ','ᾕ'=>'ᾕ','ᾖ'=>'ᾖ','ᾗ'=>'ᾗ','ᾘ'=>'ᾘ','ᾙ'=>'ᾙ','ᾚ'=>'ᾚ','ᾛ'=>'ᾛ','ᾜ'=>'ᾜ','ᾝ'=>'ᾝ','ᾞ'=>'ᾞ','ᾟ'=>'ᾟ','ᾠ'=>'ᾠ','ᾡ'=>'ᾡ','ᾢ'=>'ᾢ','ᾣ'=>'ᾣ','ᾤ'=>'ᾤ','ᾥ'=>'ᾥ','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾨ','ᾩ'=>'ᾩ','ᾪ'=>'ᾪ','ᾫ'=>'ᾫ','ᾬ'=>'ᾬ','ᾭ'=>'ᾭ','ᾮ'=>'ᾮ','ᾯ'=>'ᾯ','ᾰ'=>'ᾰ','ᾱ'=>'ᾱ','ᾲ'=>'ᾲ','ᾳ'=>'ᾳ','ᾴ'=>'ᾴ','ᾶ'=>'ᾶ','ᾷ'=>'ᾷ','Ᾰ'=>'Ᾰ','Ᾱ'=>'Ᾱ','Ὰ'=>'Ὰ','ᾼ'=>'ᾼ','῁'=>'῁','ῂ'=>'ῂ','ῃ'=>'ῃ','ῄ'=>'ῄ','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'Ὲ','Ὴ'=>'Ὴ','ῌ'=>'ῌ','῍'=>'῍','῎'=>'῎','῏'=>'῏','ῐ'=>'ῐ','ῑ'=>'ῑ','ῒ'=>'ῒ','ῖ'=>'ῖ','ῗ'=>'ῗ','Ῐ'=>'Ῐ','Ῑ'=>'Ῑ','Ὶ'=>'Ὶ','῝'=>'῝','῞'=>'῞','῟'=>'῟','ῠ'=>'ῠ','ῡ'=>'ῡ','ῢ'=>'ῢ','ῤ'=>'ῤ','ῥ'=>'ῥ','ῦ'=>'ῦ','ῧ'=>'ῧ','Ῠ'=>'Ῠ','Ῡ'=>'Ῡ','Ὺ'=>'Ὺ','Ῥ'=>'Ῥ','῭'=>'῭','ῲ'=>'ῲ','ῳ'=>'ῳ','ῴ'=>'ῴ','ῶ'=>'ῶ','ῷ'=>'ῷ','Ὸ'=>'Ὸ','Ὼ'=>'Ὼ','ῼ'=>'ῼ','↚'=>'↚','↛'=>'↛','↮'=>'↮','⇍'=>'⇍','⇎'=>'⇎','⇏'=>'⇏','∄'=>'∄','∉'=>'∉','∌'=>'∌','∤'=>'∤','∦'=>'∦','≁'=>'≁','≄'=>'≄','≇'=>'≇','≉'=>'≉','≠'=>'≠','≢'=>'≢','≭'=>'≭','≮'=>'≮','≯'=>'≯','≰'=>'≰','≱'=>'≱','≴'=>'≴','≵'=>'≵','≸'=>'≸','≹'=>'≹','⊀'=>'⊀','⊁'=>'⊁','⊄'=>'⊄','⊅'=>'⊅','⊈'=>'⊈','⊉'=>'⊉','⊬'=>'⊬','⊭'=>'⊭','⊮'=>'⊮','⊯'=>'⊯','⋠'=>'⋠','⋡'=>'⋡','⋢'=>'⋢','⋣'=>'⋣','⋪'=>'⋪','⋫'=>'⋫','⋬'=>'⋬','⋭'=>'⋭','が'=>'が','ぎ'=>'ぎ','ぐ'=>'ぐ','げ'=>'げ','ご'=>'ご','ざ'=>'ざ','じ'=>'じ','ず'=>'ず','ぜ'=>'ぜ','ぞ'=>'ぞ','だ'=>'だ','ぢ'=>'ぢ','づ'=>'づ','で'=>'で','ど'=>'ど','ば'=>'ば','ぱ'=>'ぱ','び'=>'び','ぴ'=>'ぴ','ぶ'=>'ぶ','ぷ'=>'ぷ','べ'=>'べ','ぺ'=>'ぺ','ぼ'=>'ぼ','ぽ'=>'ぽ','ゔ'=>'ゔ','ゞ'=>'ゞ','ガ'=>'ガ','ギ'=>'ギ','グ'=>'グ','ゲ'=>'ゲ','ゴ'=>'ゴ','ザ'=>'ザ','ジ'=>'ジ','ズ'=>'ズ','ゼ'=>'ゼ','ゾ'=>'ゾ','ダ'=>'ダ','ヂ'=>'ヂ','ヅ'=>'ヅ','デ'=>'デ','ド'=>'ド','バ'=>'バ','パ'=>'パ','ビ'=>'ビ','ピ'=>'ピ','ブ'=>'ブ','プ'=>'プ','ベ'=>'ベ','ペ'=>'ペ','ボ'=>'ボ','ポ'=>'ポ','ヴ'=>'ヴ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ヾ'=>'ヾ'); diff --git a/phpBB/includes/utf/data/utf_canonical_decomp.php b/phpBB/includes/utf/data/utf_canonical_decomp.php index 460a0cf323..9fb90803e2 100644 --- a/phpBB/includes/utf/data/utf_canonical_decomp.php +++ b/phpBB/includes/utf/data/utf_canonical_decomp.php @@ -1,2 +1,2 @@ <?php -$GLOBALS['utf_canonical_decomp']=array('À'=>'À','Á'=>'Á','Â'=>'Â','Ã'=>'Ã','Ä'=>'Ä','Å'=>'Å','Ç'=>'Ç','È'=>'È','É'=>'É','Ê'=>'Ê','Ë'=>'Ë','Ì'=>'Ì','Í'=>'Í','Î'=>'Î','Ï'=>'Ï','Ñ'=>'Ñ','Ò'=>'Ò','Ó'=>'Ó','Ô'=>'Ô','Õ'=>'Õ','Ö'=>'Ö','Ù'=>'Ù','Ú'=>'Ú','Û'=>'Û','Ü'=>'Ü','Ý'=>'Ý','à'=>'à','á'=>'á','â'=>'â','ã'=>'ã','ä'=>'ä','å'=>'å','ç'=>'ç','è'=>'è','é'=>'é','ê'=>'ê','ë'=>'ë','ì'=>'ì','í'=>'í','î'=>'î','ï'=>'ï','ñ'=>'ñ','ò'=>'ò','ó'=>'ó','ô'=>'ô','õ'=>'õ','ö'=>'ö','ù'=>'ù','ú'=>'ú','û'=>'û','ü'=>'ü','ý'=>'ý','ÿ'=>'ÿ','Ā'=>'Ā','ā'=>'ā','Ă'=>'Ă','ă'=>'ă','Ą'=>'Ą','ą'=>'ą','Ć'=>'Ć','ć'=>'ć','Ĉ'=>'Ĉ','ĉ'=>'ĉ','Ċ'=>'Ċ','ċ'=>'ċ','Č'=>'Č','č'=>'č','Ď'=>'Ď','ď'=>'ď','Ē'=>'Ē','ē'=>'ē','Ĕ'=>'Ĕ','ĕ'=>'ĕ','Ė'=>'Ė','ė'=>'ė','Ę'=>'Ę','ę'=>'ę','Ě'=>'Ě','ě'=>'ě','Ĝ'=>'Ĝ','ĝ'=>'ĝ','Ğ'=>'Ğ','ğ'=>'ğ','Ġ'=>'Ġ','ġ'=>'ġ','Ģ'=>'Ģ','ģ'=>'ģ','Ĥ'=>'Ĥ','ĥ'=>'ĥ','Ĩ'=>'Ĩ','ĩ'=>'ĩ','Ī'=>'Ī','ī'=>'ī','Ĭ'=>'Ĭ','ĭ'=>'ĭ','Į'=>'Į','į'=>'į','İ'=>'İ','Ĵ'=>'Ĵ','ĵ'=>'ĵ','Ķ'=>'Ķ','ķ'=>'ķ','Ĺ'=>'Ĺ','ĺ'=>'ĺ','Ļ'=>'Ļ','ļ'=>'ļ','Ľ'=>'Ľ','ľ'=>'ľ','Ń'=>'Ń','ń'=>'ń','Ņ'=>'Ņ','ņ'=>'ņ','Ň'=>'Ň','ň'=>'ň','Ō'=>'Ō','ō'=>'ō','Ŏ'=>'Ŏ','ŏ'=>'ŏ','Ő'=>'Ő','ő'=>'ő','Ŕ'=>'Ŕ','ŕ'=>'ŕ','Ŗ'=>'Ŗ','ŗ'=>'ŗ','Ř'=>'Ř','ř'=>'ř','Ś'=>'Ś','ś'=>'ś','Ŝ'=>'Ŝ','ŝ'=>'ŝ','Ş'=>'Ş','ş'=>'ş','Š'=>'Š','š'=>'š','Ţ'=>'Ţ','ţ'=>'ţ','Ť'=>'Ť','ť'=>'ť','Ũ'=>'Ũ','ũ'=>'ũ','Ū'=>'Ū','ū'=>'ū','Ŭ'=>'Ŭ','ŭ'=>'ŭ','Ů'=>'Ů','ů'=>'ů','Ű'=>'Ű','ű'=>'ű','Ų'=>'Ų','ų'=>'ų','Ŵ'=>'Ŵ','ŵ'=>'ŵ','Ŷ'=>'Ŷ','ŷ'=>'ŷ','Ÿ'=>'Ÿ','Ź'=>'Ź','ź'=>'ź','Ż'=>'Ż','ż'=>'ż','Ž'=>'Ž','ž'=>'ž','Ơ'=>'Ơ','ơ'=>'ơ','Ư'=>'Ư','ư'=>'ư','Ǎ'=>'Ǎ','ǎ'=>'ǎ','Ǐ'=>'Ǐ','ǐ'=>'ǐ','Ǒ'=>'Ǒ','ǒ'=>'ǒ','Ǔ'=>'Ǔ','ǔ'=>'ǔ','Ǖ'=>'Ǖ','ǖ'=>'ǖ','Ǘ'=>'Ǘ','ǘ'=>'ǘ','Ǚ'=>'Ǚ','ǚ'=>'ǚ','Ǜ'=>'Ǜ','ǜ'=>'ǜ','Ǟ'=>'Ǟ','ǟ'=>'ǟ','Ǡ'=>'Ǡ','ǡ'=>'ǡ','Ǣ'=>'Ǣ','ǣ'=>'ǣ','Ǧ'=>'Ǧ','ǧ'=>'ǧ','Ǩ'=>'Ǩ','ǩ'=>'ǩ','Ǫ'=>'Ǫ','ǫ'=>'ǫ','Ǭ'=>'Ǭ','ǭ'=>'ǭ','Ǯ'=>'Ǯ','ǯ'=>'ǯ','ǰ'=>'ǰ','Ǵ'=>'Ǵ','ǵ'=>'ǵ','Ǹ'=>'Ǹ','ǹ'=>'ǹ','Ǻ'=>'Ǻ','ǻ'=>'ǻ','Ǽ'=>'Ǽ','ǽ'=>'ǽ','Ǿ'=>'Ǿ','ǿ'=>'ǿ','Ȁ'=>'Ȁ','ȁ'=>'ȁ','Ȃ'=>'Ȃ','ȃ'=>'ȃ','Ȅ'=>'Ȅ','ȅ'=>'ȅ','Ȇ'=>'Ȇ','ȇ'=>'ȇ','Ȉ'=>'Ȉ','ȉ'=>'ȉ','Ȋ'=>'Ȋ','ȋ'=>'ȋ','Ȍ'=>'Ȍ','ȍ'=>'ȍ','Ȏ'=>'Ȏ','ȏ'=>'ȏ','Ȑ'=>'Ȑ','ȑ'=>'ȑ','Ȓ'=>'Ȓ','ȓ'=>'ȓ','Ȕ'=>'Ȕ','ȕ'=>'ȕ','Ȗ'=>'Ȗ','ȗ'=>'ȗ','Ș'=>'Ș','ș'=>'ș','Ț'=>'Ț','ț'=>'ț','Ȟ'=>'Ȟ','ȟ'=>'ȟ','Ȧ'=>'Ȧ','ȧ'=>'ȧ','Ȩ'=>'Ȩ','ȩ'=>'ȩ','Ȫ'=>'Ȫ','ȫ'=>'ȫ','Ȭ'=>'Ȭ','ȭ'=>'ȭ','Ȯ'=>'Ȯ','ȯ'=>'ȯ','Ȱ'=>'Ȱ','ȱ'=>'ȱ','Ȳ'=>'Ȳ','ȳ'=>'ȳ','̀'=>'̀','́'=>'́','̓'=>'̓','̈́'=>'̈́','ʹ'=>'ʹ',';'=>';','΅'=>'΅','Ά'=>'Ά','·'=>'·','Έ'=>'Έ','Ή'=>'Ή','Ί'=>'Ί','Ό'=>'Ό','Ύ'=>'Ύ','Ώ'=>'Ώ','ΐ'=>'ΐ','Ϊ'=>'Ϊ','Ϋ'=>'Ϋ','ά'=>'ά','έ'=>'έ','ή'=>'ή','ί'=>'ί','ΰ'=>'ΰ','ϊ'=>'ϊ','ϋ'=>'ϋ','ό'=>'ό','ύ'=>'ύ','ώ'=>'ώ','ϓ'=>'ϓ','ϔ'=>'ϔ','Ѐ'=>'Ѐ','Ё'=>'Ё','Ѓ'=>'Ѓ','Ї'=>'Ї','Ќ'=>'Ќ','Ѝ'=>'Ѝ','Ў'=>'Ў','Й'=>'Й','й'=>'й','ѐ'=>'ѐ','ё'=>'ё','ѓ'=>'ѓ','ї'=>'ї','ќ'=>'ќ','ѝ'=>'ѝ','ў'=>'ў','Ѷ'=>'Ѷ','ѷ'=>'ѷ','Ӂ'=>'Ӂ','ӂ'=>'ӂ','Ӑ'=>'Ӑ','ӑ'=>'ӑ','Ӓ'=>'Ӓ','ӓ'=>'ӓ','Ӗ'=>'Ӗ','ӗ'=>'ӗ','Ӛ'=>'Ӛ','ӛ'=>'ӛ','Ӝ'=>'Ӝ','ӝ'=>'ӝ','Ӟ'=>'Ӟ','ӟ'=>'ӟ','Ӣ'=>'Ӣ','ӣ'=>'ӣ','Ӥ'=>'Ӥ','ӥ'=>'ӥ','Ӧ'=>'Ӧ','ӧ'=>'ӧ','Ӫ'=>'Ӫ','ӫ'=>'ӫ','Ӭ'=>'Ӭ','ӭ'=>'ӭ','Ӯ'=>'Ӯ','ӯ'=>'ӯ','Ӱ'=>'Ӱ','ӱ'=>'ӱ','Ӳ'=>'Ӳ','ӳ'=>'ӳ','Ӵ'=>'Ӵ','ӵ'=>'ӵ','Ӹ'=>'Ӹ','ӹ'=>'ӹ','آ'=>'آ','أ'=>'أ','ؤ'=>'ؤ','إ'=>'إ','ئ'=>'ئ','ۀ'=>'ۀ','ۂ'=>'ۂ','ۓ'=>'ۓ','ऩ'=>'ऩ','ऱ'=>'ऱ','ऴ'=>'ऴ','क़'=>'क़','ख़'=>'ख़','ग़'=>'ग़','ज़'=>'ज़','ड़'=>'ड़','ढ़'=>'ढ़','फ़'=>'फ़','य़'=>'य़','ো'=>'ো','ৌ'=>'ৌ','ড়'=>'ড়','ঢ়'=>'ঢ়','য়'=>'য়','ਲ਼'=>'ਲ਼','ਸ਼'=>'ਸ਼','ਖ਼'=>'ਖ਼','ਗ਼'=>'ਗ਼','ਜ਼'=>'ਜ਼','ਫ਼'=>'ਫ਼','ୈ'=>'ୈ','ୋ'=>'ୋ','ୌ'=>'ୌ','ଡ଼'=>'ଡ଼','ଢ଼'=>'ଢ଼','ஔ'=>'ஔ','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','ై'=>'ై','ೀ'=>'ೀ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','ේ'=>'ේ','ො'=>'ො','ෝ'=>'ෝ','ෞ'=>'ෞ','གྷ'=>'གྷ','ཌྷ'=>'ཌྷ','དྷ'=>'དྷ','བྷ'=>'བྷ','ཛྷ'=>'ཛྷ','ཀྵ'=>'ཀྵ','ཱི'=>'ཱི','ཱུ'=>'ཱུ','ྲྀ'=>'ྲྀ','ླྀ'=>'ླྀ','ཱྀ'=>'ཱྀ','ྒྷ'=>'ྒྷ','ྜྷ'=>'ྜྷ','ྡྷ'=>'ྡྷ','ྦྷ'=>'ྦྷ','ྫྷ'=>'ྫྷ','ྐྵ'=>'ྐྵ','ဦ'=>'ဦ','ᬆ'=>'ᬆ','ᬈ'=>'ᬈ','ᬊ'=>'ᬊ','ᬌ'=>'ᬌ','ᬎ'=>'ᬎ','ᬒ'=>'ᬒ','ᬻ'=>'ᬻ','ᬽ'=>'ᬽ','ᭀ'=>'ᭀ','ᭁ'=>'ᭁ','ᭃ'=>'ᭃ','Ḁ'=>'Ḁ','ḁ'=>'ḁ','Ḃ'=>'Ḃ','ḃ'=>'ḃ','Ḅ'=>'Ḅ','ḅ'=>'ḅ','Ḇ'=>'Ḇ','ḇ'=>'ḇ','Ḉ'=>'Ḉ','ḉ'=>'ḉ','Ḋ'=>'Ḋ','ḋ'=>'ḋ','Ḍ'=>'Ḍ','ḍ'=>'ḍ','Ḏ'=>'Ḏ','ḏ'=>'ḏ','Ḑ'=>'Ḑ','ḑ'=>'ḑ','Ḓ'=>'Ḓ','ḓ'=>'ḓ','Ḕ'=>'Ḕ','ḕ'=>'ḕ','Ḗ'=>'Ḗ','ḗ'=>'ḗ','Ḙ'=>'Ḙ','ḙ'=>'ḙ','Ḛ'=>'Ḛ','ḛ'=>'ḛ','Ḝ'=>'Ḝ','ḝ'=>'ḝ','Ḟ'=>'Ḟ','ḟ'=>'ḟ','Ḡ'=>'Ḡ','ḡ'=>'ḡ','Ḣ'=>'Ḣ','ḣ'=>'ḣ','Ḥ'=>'Ḥ','ḥ'=>'ḥ','Ḧ'=>'Ḧ','ḧ'=>'ḧ','Ḩ'=>'Ḩ','ḩ'=>'ḩ','Ḫ'=>'Ḫ','ḫ'=>'ḫ','Ḭ'=>'Ḭ','ḭ'=>'ḭ','Ḯ'=>'Ḯ','ḯ'=>'ḯ','Ḱ'=>'Ḱ','ḱ'=>'ḱ','Ḳ'=>'Ḳ','ḳ'=>'ḳ','Ḵ'=>'Ḵ','ḵ'=>'ḵ','Ḷ'=>'Ḷ','ḷ'=>'ḷ','Ḹ'=>'Ḹ','ḹ'=>'ḹ','Ḻ'=>'Ḻ','ḻ'=>'ḻ','Ḽ'=>'Ḽ','ḽ'=>'ḽ','Ḿ'=>'Ḿ','ḿ'=>'ḿ','Ṁ'=>'Ṁ','ṁ'=>'ṁ','Ṃ'=>'Ṃ','ṃ'=>'ṃ','Ṅ'=>'Ṅ','ṅ'=>'ṅ','Ṇ'=>'Ṇ','ṇ'=>'ṇ','Ṉ'=>'Ṉ','ṉ'=>'ṉ','Ṋ'=>'Ṋ','ṋ'=>'ṋ','Ṍ'=>'Ṍ','ṍ'=>'ṍ','Ṏ'=>'Ṏ','ṏ'=>'ṏ','Ṑ'=>'Ṑ','ṑ'=>'ṑ','Ṓ'=>'Ṓ','ṓ'=>'ṓ','Ṕ'=>'Ṕ','ṕ'=>'ṕ','Ṗ'=>'Ṗ','ṗ'=>'ṗ','Ṙ'=>'Ṙ','ṙ'=>'ṙ','Ṛ'=>'Ṛ','ṛ'=>'ṛ','Ṝ'=>'Ṝ','ṝ'=>'ṝ','Ṟ'=>'Ṟ','ṟ'=>'ṟ','Ṡ'=>'Ṡ','ṡ'=>'ṡ','Ṣ'=>'Ṣ','ṣ'=>'ṣ','Ṥ'=>'Ṥ','ṥ'=>'ṥ','Ṧ'=>'Ṧ','ṧ'=>'ṧ','Ṩ'=>'Ṩ','ṩ'=>'ṩ','Ṫ'=>'Ṫ','ṫ'=>'ṫ','Ṭ'=>'Ṭ','ṭ'=>'ṭ','Ṯ'=>'Ṯ','ṯ'=>'ṯ','Ṱ'=>'Ṱ','ṱ'=>'ṱ','Ṳ'=>'Ṳ','ṳ'=>'ṳ','Ṵ'=>'Ṵ','ṵ'=>'ṵ','Ṷ'=>'Ṷ','ṷ'=>'ṷ','Ṹ'=>'Ṹ','ṹ'=>'ṹ','Ṻ'=>'Ṻ','ṻ'=>'ṻ','Ṽ'=>'Ṽ','ṽ'=>'ṽ','Ṿ'=>'Ṿ','ṿ'=>'ṿ','Ẁ'=>'Ẁ','ẁ'=>'ẁ','Ẃ'=>'Ẃ','ẃ'=>'ẃ','Ẅ'=>'Ẅ','ẅ'=>'ẅ','Ẇ'=>'Ẇ','ẇ'=>'ẇ','Ẉ'=>'Ẉ','ẉ'=>'ẉ','Ẋ'=>'Ẋ','ẋ'=>'ẋ','Ẍ'=>'Ẍ','ẍ'=>'ẍ','Ẏ'=>'Ẏ','ẏ'=>'ẏ','Ẑ'=>'Ẑ','ẑ'=>'ẑ','Ẓ'=>'Ẓ','ẓ'=>'ẓ','Ẕ'=>'Ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẛ'=>'ẛ','Ạ'=>'Ạ','ạ'=>'ạ','Ả'=>'Ả','ả'=>'ả','Ấ'=>'Ấ','ấ'=>'ấ','Ầ'=>'Ầ','ầ'=>'ầ','Ẩ'=>'Ẩ','ẩ'=>'ẩ','Ẫ'=>'Ẫ','ẫ'=>'ẫ','Ậ'=>'Ậ','ậ'=>'ậ','Ắ'=>'Ắ','ắ'=>'ắ','Ằ'=>'Ằ','ằ'=>'ằ','Ẳ'=>'Ẳ','ẳ'=>'ẳ','Ẵ'=>'Ẵ','ẵ'=>'ẵ','Ặ'=>'Ặ','ặ'=>'ặ','Ẹ'=>'Ẹ','ẹ'=>'ẹ','Ẻ'=>'Ẻ','ẻ'=>'ẻ','Ẽ'=>'Ẽ','ẽ'=>'ẽ','Ế'=>'Ế','ế'=>'ế','Ề'=>'Ề','ề'=>'ề','Ể'=>'Ể','ể'=>'ể','Ễ'=>'Ễ','ễ'=>'ễ','Ệ'=>'Ệ','ệ'=>'ệ','Ỉ'=>'Ỉ','ỉ'=>'ỉ','Ị'=>'Ị','ị'=>'ị','Ọ'=>'Ọ','ọ'=>'ọ','Ỏ'=>'Ỏ','ỏ'=>'ỏ','Ố'=>'Ố','ố'=>'ố','Ồ'=>'Ồ','ồ'=>'ồ','Ổ'=>'Ổ','ổ'=>'ổ','Ỗ'=>'Ỗ','ỗ'=>'ỗ','Ộ'=>'Ộ','ộ'=>'ộ','Ớ'=>'Ớ','ớ'=>'ớ','Ờ'=>'Ờ','ờ'=>'ờ','Ở'=>'Ở','ở'=>'ở','Ỡ'=>'Ỡ','ỡ'=>'ỡ','Ợ'=>'Ợ','ợ'=>'ợ','Ụ'=>'Ụ','ụ'=>'ụ','Ủ'=>'Ủ','ủ'=>'ủ','Ứ'=>'Ứ','ứ'=>'ứ','Ừ'=>'Ừ','ừ'=>'ừ','Ử'=>'Ử','ử'=>'ử','Ữ'=>'Ữ','ữ'=>'ữ','Ự'=>'Ự','ự'=>'ự','Ỳ'=>'Ỳ','ỳ'=>'ỳ','Ỵ'=>'Ỵ','ỵ'=>'ỵ','Ỷ'=>'Ỷ','ỷ'=>'ỷ','Ỹ'=>'Ỹ','ỹ'=>'ỹ','ἀ'=>'ἀ','ἁ'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἄ','ἅ'=>'ἅ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'Ἀ','Ἁ'=>'Ἁ','Ἂ'=>'Ἂ','Ἃ'=>'Ἃ','Ἄ'=>'Ἄ','Ἅ'=>'Ἅ','Ἆ'=>'Ἆ','Ἇ'=>'Ἇ','ἐ'=>'ἐ','ἑ'=>'ἑ','ἒ'=>'ἒ','ἓ'=>'ἓ','ἔ'=>'ἔ','ἕ'=>'ἕ','Ἐ'=>'Ἐ','Ἑ'=>'Ἑ','Ἒ'=>'Ἒ','Ἓ'=>'Ἓ','Ἔ'=>'Ἔ','Ἕ'=>'Ἕ','ἠ'=>'ἠ','ἡ'=>'ἡ','ἢ'=>'ἢ','ἣ'=>'ἣ','ἤ'=>'ἤ','ἥ'=>'ἥ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'Ἠ','Ἡ'=>'Ἡ','Ἢ'=>'Ἢ','Ἣ'=>'Ἣ','Ἤ'=>'Ἤ','Ἥ'=>'Ἥ','Ἦ'=>'Ἦ','Ἧ'=>'Ἧ','ἰ'=>'ἰ','ἱ'=>'ἱ','ἲ'=>'ἲ','ἳ'=>'ἳ','ἴ'=>'ἴ','ἵ'=>'ἵ','ἶ'=>'ἶ','ἷ'=>'ἷ','Ἰ'=>'Ἰ','Ἱ'=>'Ἱ','Ἲ'=>'Ἲ','Ἳ'=>'Ἳ','Ἴ'=>'Ἴ','Ἵ'=>'Ἵ','Ἶ'=>'Ἶ','Ἷ'=>'Ἷ','ὀ'=>'ὀ','ὁ'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὄ','ὅ'=>'ὅ','Ὀ'=>'Ὀ','Ὁ'=>'Ὁ','Ὂ'=>'Ὂ','Ὃ'=>'Ὃ','Ὄ'=>'Ὄ','Ὅ'=>'Ὅ','ὐ'=>'ὐ','ὑ'=>'ὑ','ὒ'=>'ὒ','ὓ'=>'ὓ','ὔ'=>'ὔ','ὕ'=>'ὕ','ὖ'=>'ὖ','ὗ'=>'ὗ','Ὑ'=>'Ὑ','Ὓ'=>'Ὓ','Ὕ'=>'Ὕ','Ὗ'=>'Ὗ','ὠ'=>'ὠ','ὡ'=>'ὡ','ὢ'=>'ὢ','ὣ'=>'ὣ','ὤ'=>'ὤ','ὥ'=>'ὥ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'Ὠ','Ὡ'=>'Ὡ','Ὢ'=>'Ὢ','Ὣ'=>'Ὣ','Ὤ'=>'Ὤ','Ὥ'=>'Ὥ','Ὦ'=>'Ὦ','Ὧ'=>'Ὧ','ὰ'=>'ὰ','ά'=>'ά','ὲ'=>'ὲ','έ'=>'έ','ὴ'=>'ὴ','ή'=>'ή','ὶ'=>'ὶ','ί'=>'ί','ὸ'=>'ὸ','ό'=>'ό','ὺ'=>'ὺ','ύ'=>'ύ','ὼ'=>'ὼ','ώ'=>'ώ','ᾀ'=>'ᾀ','ᾁ'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ᾄ','ᾅ'=>'ᾅ','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾈ','ᾉ'=>'ᾉ','ᾊ'=>'ᾊ','ᾋ'=>'ᾋ','ᾌ'=>'ᾌ','ᾍ'=>'ᾍ','ᾎ'=>'ᾎ','ᾏ'=>'ᾏ','ᾐ'=>'ᾐ','ᾑ'=>'ᾑ','ᾒ'=>'ᾒ','ᾓ'=>'ᾓ','ᾔ'=>'ᾔ','ᾕ'=>'ᾕ','ᾖ'=>'ᾖ','ᾗ'=>'ᾗ','ᾘ'=>'ᾘ','ᾙ'=>'ᾙ','ᾚ'=>'ᾚ','ᾛ'=>'ᾛ','ᾜ'=>'ᾜ','ᾝ'=>'ᾝ','ᾞ'=>'ᾞ','ᾟ'=>'ᾟ','ᾠ'=>'ᾠ','ᾡ'=>'ᾡ','ᾢ'=>'ᾢ','ᾣ'=>'ᾣ','ᾤ'=>'ᾤ','ᾥ'=>'ᾥ','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾨ','ᾩ'=>'ᾩ','ᾪ'=>'ᾪ','ᾫ'=>'ᾫ','ᾬ'=>'ᾬ','ᾭ'=>'ᾭ','ᾮ'=>'ᾮ','ᾯ'=>'ᾯ','ᾰ'=>'ᾰ','ᾱ'=>'ᾱ','ᾲ'=>'ᾲ','ᾳ'=>'ᾳ','ᾴ'=>'ᾴ','ᾶ'=>'ᾶ','ᾷ'=>'ᾷ','Ᾰ'=>'Ᾰ','Ᾱ'=>'Ᾱ','Ὰ'=>'Ὰ','Ά'=>'Ά','ᾼ'=>'ᾼ','ι'=>'ι','῁'=>'῁','ῂ'=>'ῂ','ῃ'=>'ῃ','ῄ'=>'ῄ','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'Ὲ','Έ'=>'Έ','Ὴ'=>'Ὴ','Ή'=>'Ή','ῌ'=>'ῌ','῍'=>'῍','῎'=>'῎','῏'=>'῏','ῐ'=>'ῐ','ῑ'=>'ῑ','ῒ'=>'ῒ','ΐ'=>'ΐ','ῖ'=>'ῖ','ῗ'=>'ῗ','Ῐ'=>'Ῐ','Ῑ'=>'Ῑ','Ὶ'=>'Ὶ','Ί'=>'Ί','῝'=>'῝','῞'=>'῞','῟'=>'῟','ῠ'=>'ῠ','ῡ'=>'ῡ','ῢ'=>'ῢ','ΰ'=>'ΰ','ῤ'=>'ῤ','ῥ'=>'ῥ','ῦ'=>'ῦ','ῧ'=>'ῧ','Ῠ'=>'Ῠ','Ῡ'=>'Ῡ','Ὺ'=>'Ὺ','Ύ'=>'Ύ','Ῥ'=>'Ῥ','῭'=>'῭','΅'=>'΅','`'=>'`','ῲ'=>'ῲ','ῳ'=>'ῳ','ῴ'=>'ῴ','ῶ'=>'ῶ','ῷ'=>'ῷ','Ὸ'=>'Ὸ','Ό'=>'Ό','Ὼ'=>'Ὼ','Ώ'=>'Ώ','ῼ'=>'ῼ','´'=>'´',' '=>' ',' '=>' ','Ω'=>'Ω','K'=>'K','Å'=>'Å','↚'=>'↚','↛'=>'↛','↮'=>'↮','⇍'=>'⇍','⇎'=>'⇎','⇏'=>'⇏','∄'=>'∄','∉'=>'∉','∌'=>'∌','∤'=>'∤','∦'=>'∦','≁'=>'≁','≄'=>'≄','≇'=>'≇','≉'=>'≉','≠'=>'≠','≢'=>'≢','≭'=>'≭','≮'=>'≮','≯'=>'≯','≰'=>'≰','≱'=>'≱','≴'=>'≴','≵'=>'≵','≸'=>'≸','≹'=>'≹','⊀'=>'⊀','⊁'=>'⊁','⊄'=>'⊄','⊅'=>'⊅','⊈'=>'⊈','⊉'=>'⊉','⊬'=>'⊬','⊭'=>'⊭','⊮'=>'⊮','⊯'=>'⊯','⋠'=>'⋠','⋡'=>'⋡','⋢'=>'⋢','⋣'=>'⋣','⋪'=>'⋪','⋫'=>'⋫','⋬'=>'⋬','⋭'=>'⋭','〈'=>'〈','〉'=>'〉','⫝̸'=>'⫝̸','が'=>'が','ぎ'=>'ぎ','ぐ'=>'ぐ','げ'=>'げ','ご'=>'ご','ざ'=>'ざ','じ'=>'じ','ず'=>'ず','ぜ'=>'ぜ','ぞ'=>'ぞ','だ'=>'だ','ぢ'=>'ぢ','づ'=>'づ','で'=>'で','ど'=>'ど','ば'=>'ば','ぱ'=>'ぱ','び'=>'び','ぴ'=>'ぴ','ぶ'=>'ぶ','ぷ'=>'ぷ','べ'=>'べ','ぺ'=>'ぺ','ぼ'=>'ぼ','ぽ'=>'ぽ','ゔ'=>'ゔ','ゞ'=>'ゞ','ガ'=>'ガ','ギ'=>'ギ','グ'=>'グ','ゲ'=>'ゲ','ゴ'=>'ゴ','ザ'=>'ザ','ジ'=>'ジ','ズ'=>'ズ','ゼ'=>'ゼ','ゾ'=>'ゾ','ダ'=>'ダ','ヂ'=>'ヂ','ヅ'=>'ヅ','デ'=>'デ','ド'=>'ド','バ'=>'バ','パ'=>'パ','ビ'=>'ビ','ピ'=>'ピ','ブ'=>'ブ','プ'=>'プ','ベ'=>'ベ','ペ'=>'ペ','ボ'=>'ボ','ポ'=>'ポ','ヴ'=>'ヴ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ヾ'=>'ヾ','豈'=>'豈','更'=>'更','車'=>'車','賈'=>'賈','滑'=>'滑','串'=>'串','句'=>'句','龜'=>'龜','龜'=>'龜','契'=>'契','金'=>'金','喇'=>'喇','奈'=>'奈','懶'=>'懶','癩'=>'癩','羅'=>'羅','蘿'=>'蘿','螺'=>'螺','裸'=>'裸','邏'=>'邏','樂'=>'樂','洛'=>'洛','烙'=>'烙','珞'=>'珞','落'=>'落','酪'=>'酪','駱'=>'駱','亂'=>'亂','卵'=>'卵','欄'=>'欄','爛'=>'爛','蘭'=>'蘭','鸞'=>'鸞','嵐'=>'嵐','濫'=>'濫','藍'=>'藍','襤'=>'襤','拉'=>'拉','臘'=>'臘','蠟'=>'蠟','廊'=>'廊','朗'=>'朗','浪'=>'浪','狼'=>'狼','郎'=>'郎','來'=>'來','冷'=>'冷','勞'=>'勞','擄'=>'擄','櫓'=>'櫓','爐'=>'爐','盧'=>'盧','老'=>'老','蘆'=>'蘆','虜'=>'虜','路'=>'路','露'=>'露','魯'=>'魯','鷺'=>'鷺','碌'=>'碌','祿'=>'祿','綠'=>'綠','菉'=>'菉','錄'=>'錄','鹿'=>'鹿','論'=>'論','壟'=>'壟','弄'=>'弄','籠'=>'籠','聾'=>'聾','牢'=>'牢','磊'=>'磊','賂'=>'賂','雷'=>'雷','壘'=>'壘','屢'=>'屢','樓'=>'樓','淚'=>'淚','漏'=>'漏','累'=>'累','縷'=>'縷','陋'=>'陋','勒'=>'勒','肋'=>'肋','凜'=>'凜','凌'=>'凌','稜'=>'稜','綾'=>'綾','菱'=>'菱','陵'=>'陵','讀'=>'讀','拏'=>'拏','樂'=>'樂','諾'=>'諾','丹'=>'丹','寧'=>'寧','怒'=>'怒','率'=>'率','異'=>'異','北'=>'北','磻'=>'磻','便'=>'便','復'=>'復','不'=>'不','泌'=>'泌','數'=>'數','索'=>'索','參'=>'參','塞'=>'塞','省'=>'省','葉'=>'葉','說'=>'說','殺'=>'殺','辰'=>'辰','沈'=>'沈','拾'=>'拾','若'=>'若','掠'=>'掠','略'=>'略','亮'=>'亮','兩'=>'兩','凉'=>'凉','梁'=>'梁','糧'=>'糧','良'=>'良','諒'=>'諒','量'=>'量','勵'=>'勵','呂'=>'呂','女'=>'女','廬'=>'廬','旅'=>'旅','濾'=>'濾','礪'=>'礪','閭'=>'閭','驪'=>'驪','麗'=>'麗','黎'=>'黎','力'=>'力','曆'=>'曆','歷'=>'歷','轢'=>'轢','年'=>'年','憐'=>'憐','戀'=>'戀','撚'=>'撚','漣'=>'漣','煉'=>'煉','璉'=>'璉','秊'=>'秊','練'=>'練','聯'=>'聯','輦'=>'輦','蓮'=>'蓮','連'=>'連','鍊'=>'鍊','列'=>'列','劣'=>'劣','咽'=>'咽','烈'=>'烈','裂'=>'裂','說'=>'說','廉'=>'廉','念'=>'念','捻'=>'捻','殮'=>'殮','簾'=>'簾','獵'=>'獵','令'=>'令','囹'=>'囹','寧'=>'寧','嶺'=>'嶺','怜'=>'怜','玲'=>'玲','瑩'=>'瑩','羚'=>'羚','聆'=>'聆','鈴'=>'鈴','零'=>'零','靈'=>'靈','領'=>'領','例'=>'例','禮'=>'禮','醴'=>'醴','隸'=>'隸','惡'=>'惡','了'=>'了','僚'=>'僚','寮'=>'寮','尿'=>'尿','料'=>'料','樂'=>'樂','燎'=>'燎','療'=>'療','蓼'=>'蓼','遼'=>'遼','龍'=>'龍','暈'=>'暈','阮'=>'阮','劉'=>'劉','杻'=>'杻','柳'=>'柳','流'=>'流','溜'=>'溜','琉'=>'琉','留'=>'留','硫'=>'硫','紐'=>'紐','類'=>'類','六'=>'六','戮'=>'戮','陸'=>'陸','倫'=>'倫','崙'=>'崙','淪'=>'淪','輪'=>'輪','律'=>'律','慄'=>'慄','栗'=>'栗','率'=>'率','隆'=>'隆','利'=>'利','吏'=>'吏','履'=>'履','易'=>'易','李'=>'李','梨'=>'梨','泥'=>'泥','理'=>'理','痢'=>'痢','罹'=>'罹','裏'=>'裏','裡'=>'裡','里'=>'里','離'=>'離','匿'=>'匿','溺'=>'溺','吝'=>'吝','燐'=>'燐','璘'=>'璘','藺'=>'藺','隣'=>'隣','鱗'=>'鱗','麟'=>'麟','林'=>'林','淋'=>'淋','臨'=>'臨','立'=>'立','笠'=>'笠','粒'=>'粒','狀'=>'狀','炙'=>'炙','識'=>'識','什'=>'什','茶'=>'茶','刺'=>'刺','切'=>'切','度'=>'度','拓'=>'拓','糖'=>'糖','宅'=>'宅','洞'=>'洞','暴'=>'暴','輻'=>'輻','行'=>'行','降'=>'降','見'=>'見','廓'=>'廓','兀'=>'兀','嗀'=>'嗀','塚'=>'塚','晴'=>'晴','凞'=>'凞','猪'=>'猪','益'=>'益','礼'=>'礼','神'=>'神','祥'=>'祥','福'=>'福','靖'=>'靖','精'=>'精','羽'=>'羽','蘒'=>'蘒','諸'=>'諸','逸'=>'逸','都'=>'都','飯'=>'飯','飼'=>'飼','館'=>'館','鶴'=>'鶴','侮'=>'侮','僧'=>'僧','免'=>'免','勉'=>'勉','勤'=>'勤','卑'=>'卑','喝'=>'喝','嘆'=>'嘆','器'=>'器','塀'=>'塀','墨'=>'墨','層'=>'層','屮'=>'屮','悔'=>'悔','慨'=>'慨','憎'=>'憎','懲'=>'懲','敏'=>'敏','既'=>'既','暑'=>'暑','梅'=>'梅','海'=>'海','渚'=>'渚','漢'=>'漢','煮'=>'煮','爫'=>'爫','琢'=>'琢','碑'=>'碑','社'=>'社','祉'=>'祉','祈'=>'祈','祐'=>'祐','祖'=>'祖','祝'=>'祝','禍'=>'禍','禎'=>'禎','穀'=>'穀','突'=>'突','節'=>'節','練'=>'練','縉'=>'縉','繁'=>'繁','署'=>'署','者'=>'者','臭'=>'臭','艹'=>'艹','艹'=>'艹','著'=>'著','褐'=>'褐','視'=>'視','謁'=>'謁','謹'=>'謹','賓'=>'賓','贈'=>'贈','辶'=>'辶','逸'=>'逸','難'=>'難','響'=>'響','頻'=>'頻','並'=>'並','况'=>'况','全'=>'全','侀'=>'侀','充'=>'充','冀'=>'冀','勇'=>'勇','勺'=>'勺','喝'=>'喝','啕'=>'啕','喙'=>'喙','嗢'=>'嗢','塚'=>'塚','墳'=>'墳','奄'=>'奄','奔'=>'奔','婢'=>'婢','嬨'=>'嬨','廒'=>'廒','廙'=>'廙','彩'=>'彩','徭'=>'徭','惘'=>'惘','慎'=>'慎','愈'=>'愈','憎'=>'憎','慠'=>'慠','懲'=>'懲','戴'=>'戴','揄'=>'揄','搜'=>'搜','摒'=>'摒','敖'=>'敖','晴'=>'晴','朗'=>'朗','望'=>'望','杖'=>'杖','歹'=>'歹','殺'=>'殺','流'=>'流','滛'=>'滛','滋'=>'滋','漢'=>'漢','瀞'=>'瀞','煮'=>'煮','瞧'=>'瞧','爵'=>'爵','犯'=>'犯','猪'=>'猪','瑱'=>'瑱','甆'=>'甆','画'=>'画','瘝'=>'瘝','瘟'=>'瘟','益'=>'益','盛'=>'盛','直'=>'直','睊'=>'睊','着'=>'着','磌'=>'磌','窱'=>'窱','節'=>'節','类'=>'类','絛'=>'絛','練'=>'練','缾'=>'缾','者'=>'者','荒'=>'荒','華'=>'華','蝹'=>'蝹','襁'=>'襁','覆'=>'覆','視'=>'視','調'=>'調','諸'=>'諸','請'=>'請','謁'=>'謁','諾'=>'諾','諭'=>'諭','謹'=>'謹','變'=>'變','贈'=>'贈','輸'=>'輸','遲'=>'遲','醙'=>'醙','鉶'=>'鉶','陼'=>'陼','難'=>'難','靖'=>'靖','韛'=>'韛','響'=>'響','頋'=>'頋','頻'=>'頻','鬒'=>'鬒','龜'=>'龜','𢡊'=>'𢡊','𢡄'=>'𢡄','𣏕'=>'𣏕','㮝'=>'㮝','䀘'=>'䀘','䀹'=>'䀹','𥉉'=>'𥉉','𥳐'=>'𥳐','𧻓'=>'𧻓','齃'=>'齃','龎'=>'龎','יִ'=>'יִ','ײַ'=>'ײַ','שׁ'=>'שׁ','שׂ'=>'שׂ','שּׁ'=>'שּׁ','שּׂ'=>'שּׂ','אַ'=>'אַ','אָ'=>'אָ','אּ'=>'אּ','בּ'=>'בּ','גּ'=>'גּ','דּ'=>'דּ','הּ'=>'הּ','וּ'=>'וּ','זּ'=>'זּ','טּ'=>'טּ','יּ'=>'יּ','ךּ'=>'ךּ','כּ'=>'כּ','לּ'=>'לּ','מּ'=>'מּ','נּ'=>'נּ','סּ'=>'סּ','ףּ'=>'ףּ','פּ'=>'פּ','צּ'=>'צּ','קּ'=>'קּ','רּ'=>'רּ','שּ'=>'שּ','תּ'=>'תּ','וֹ'=>'וֹ','בֿ'=>'בֿ','כֿ'=>'כֿ','פֿ'=>'פֿ','𝅗𝅥'=>'𝅗𝅥','𝅘𝅥'=>'𝅘𝅥','𝅘𝅥𝅮'=>'𝅘𝅥𝅮','𝅘𝅥𝅯'=>'𝅘𝅥𝅯','𝅘𝅥𝅰'=>'𝅘𝅥𝅰','𝅘𝅥𝅱'=>'𝅘𝅥𝅱','𝅘𝅥𝅲'=>'𝅘𝅥𝅲','𝆹𝅥'=>'𝆹𝅥','𝆺𝅥'=>'𝆺𝅥','𝆹𝅥𝅮'=>'𝆹𝅥𝅮','𝆺𝅥𝅮'=>'𝆺𝅥𝅮','𝆹𝅥𝅯'=>'𝆹𝅥𝅯','𝆺𝅥𝅯'=>'𝆺𝅥𝅯','丽'=>'丽','丸'=>'丸','乁'=>'乁','𠄢'=>'𠄢','你'=>'你','侮'=>'侮','侻'=>'侻','倂'=>'倂','偺'=>'偺','備'=>'備','僧'=>'僧','像'=>'像','㒞'=>'㒞','𠘺'=>'𠘺','免'=>'免','兔'=>'兔','兤'=>'兤','具'=>'具','𠔜'=>'𠔜','㒹'=>'㒹','內'=>'內','再'=>'再','𠕋'=>'𠕋','冗'=>'冗','冤'=>'冤','仌'=>'仌','冬'=>'冬','况'=>'况','𩇟'=>'𩇟','凵'=>'凵','刃'=>'刃','㓟'=>'㓟','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','㔕'=>'㔕','勇'=>'勇','勉'=>'勉','勤'=>'勤','勺'=>'勺','包'=>'包','匆'=>'匆','北'=>'北','卉'=>'卉','卑'=>'卑','博'=>'博','即'=>'即','卽'=>'卽','卿'=>'卿','卿'=>'卿','卿'=>'卿','𠨬'=>'𠨬','灰'=>'灰','及'=>'及','叟'=>'叟','𠭣'=>'𠭣','叫'=>'叫','叱'=>'叱','吆'=>'吆','咞'=>'咞','吸'=>'吸','呈'=>'呈','周'=>'周','咢'=>'咢','哶'=>'哶','唐'=>'唐','啓'=>'啓','啣'=>'啣','善'=>'善','善'=>'善','喙'=>'喙','喫'=>'喫','喳'=>'喳','嗂'=>'嗂','圖'=>'圖','嘆'=>'嘆','圗'=>'圗','噑'=>'噑','噴'=>'噴','切'=>'切','壮'=>'壮','城'=>'城','埴'=>'埴','堍'=>'堍','型'=>'型','堲'=>'堲','報'=>'報','墬'=>'墬','𡓤'=>'𡓤','売'=>'売','壷'=>'壷','夆'=>'夆','多'=>'多','夢'=>'夢','奢'=>'奢','𡚨'=>'𡚨','𡛪'=>'𡛪','姬'=>'姬','娛'=>'娛','娧'=>'娧','姘'=>'姘','婦'=>'婦','㛮'=>'㛮','㛼'=>'㛼','嬈'=>'嬈','嬾'=>'嬾','嬾'=>'嬾','𡧈'=>'𡧈','寃'=>'寃','寘'=>'寘','寧'=>'寧','寳'=>'寳','𡬘'=>'𡬘','寿'=>'寿','将'=>'将','当'=>'当','尢'=>'尢','㞁'=>'㞁','屠'=>'屠','屮'=>'屮','峀'=>'峀','岍'=>'岍','𡷤'=>'𡷤','嵃'=>'嵃','𡷦'=>'𡷦','嵮'=>'嵮','嵫'=>'嵫','嵼'=>'嵼','巡'=>'巡','巢'=>'巢','㠯'=>'㠯','巽'=>'巽','帨'=>'帨','帽'=>'帽','幩'=>'幩','㡢'=>'㡢','𢆃'=>'𢆃','㡼'=>'㡼','庰'=>'庰','庳'=>'庳','庶'=>'庶','廊'=>'廊','𪎒'=>'𪎒','廾'=>'廾','𢌱'=>'𢌱','𢌱'=>'𢌱','舁'=>'舁','弢'=>'弢','弢'=>'弢','㣇'=>'㣇','𣊸'=>'𣊸','𦇚'=>'𦇚','形'=>'形','彫'=>'彫','㣣'=>'㣣','徚'=>'徚','忍'=>'忍','志'=>'志','忹'=>'忹','悁'=>'悁','㤺'=>'㤺','㤜'=>'㤜','悔'=>'悔','𢛔'=>'𢛔','惇'=>'惇','慈'=>'慈','慌'=>'慌','慎'=>'慎','慌'=>'慌','慺'=>'慺','憎'=>'憎','憲'=>'憲','憤'=>'憤','憯'=>'憯','懞'=>'懞','懲'=>'懲','懶'=>'懶','成'=>'成','戛'=>'戛','扝'=>'扝','抱'=>'抱','拔'=>'拔','捐'=>'捐','𢬌'=>'𢬌','挽'=>'挽','拼'=>'拼','捨'=>'捨','掃'=>'掃','揤'=>'揤','𢯱'=>'𢯱','搢'=>'搢','揅'=>'揅','掩'=>'掩','㨮'=>'㨮','摩'=>'摩','摾'=>'摾','撝'=>'撝','摷'=>'摷','㩬'=>'㩬','敏'=>'敏','敬'=>'敬','𣀊'=>'𣀊','旣'=>'旣','書'=>'書','晉'=>'晉','㬙'=>'㬙','暑'=>'暑','㬈'=>'㬈','㫤'=>'㫤','冒'=>'冒','冕'=>'冕','最'=>'最','暜'=>'暜','肭'=>'肭','䏙'=>'䏙','朗'=>'朗','望'=>'望','朡'=>'朡','杞'=>'杞','杓'=>'杓','𣏃'=>'𣏃','㭉'=>'㭉','柺'=>'柺','枅'=>'枅','桒'=>'桒','梅'=>'梅','𣑭'=>'𣑭','梎'=>'梎','栟'=>'栟','椔'=>'椔','㮝'=>'㮝','楂'=>'楂','榣'=>'榣','槪'=>'槪','檨'=>'檨','𣚣'=>'𣚣','櫛'=>'櫛','㰘'=>'㰘','次'=>'次','𣢧'=>'𣢧','歔'=>'歔','㱎'=>'㱎','歲'=>'歲','殟'=>'殟','殺'=>'殺','殻'=>'殻','𣪍'=>'𣪍','𡴋'=>'𡴋','𣫺'=>'𣫺','汎'=>'汎','𣲼'=>'𣲼','沿'=>'沿','泍'=>'泍','汧'=>'汧','洖'=>'洖','派'=>'派','海'=>'海','流'=>'流','浩'=>'浩','浸'=>'浸','涅'=>'涅','𣴞'=>'𣴞','洴'=>'洴','港'=>'港','湮'=>'湮','㴳'=>'㴳','滋'=>'滋','滇'=>'滇','𣻑'=>'𣻑','淹'=>'淹','潮'=>'潮','𣽞'=>'𣽞','𣾎'=>'𣾎','濆'=>'濆','瀹'=>'瀹','瀞'=>'瀞','瀛'=>'瀛','㶖'=>'㶖','灊'=>'灊','災'=>'災','灷'=>'灷','炭'=>'炭','𠔥'=>'𠔥','煅'=>'煅','𤉣'=>'𤉣','熜'=>'熜','𤎫'=>'𤎫','爨'=>'爨','爵'=>'爵','牐'=>'牐','𤘈'=>'𤘈','犀'=>'犀','犕'=>'犕','𤜵'=>'𤜵','𤠔'=>'𤠔','獺'=>'獺','王'=>'王','㺬'=>'㺬','玥'=>'玥','㺸'=>'㺸','㺸'=>'㺸','瑇'=>'瑇','瑜'=>'瑜','瑱'=>'瑱','璅'=>'璅','瓊'=>'瓊','㼛'=>'㼛','甤'=>'甤','𤰶'=>'𤰶','甾'=>'甾','𤲒'=>'𤲒','異'=>'異','𢆟'=>'𢆟','瘐'=>'瘐','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'𥁄','㿼'=>'㿼','䀈'=>'䀈','直'=>'直','𥃳'=>'𥃳','𥃲'=>'𥃲','𥄙'=>'𥄙','𥄳'=>'𥄳','眞'=>'眞','真'=>'真','真'=>'真','睊'=>'睊','䀹'=>'䀹','瞋'=>'瞋','䁆'=>'䁆','䂖'=>'䂖','𥐝'=>'𥐝','硎'=>'硎','碌'=>'碌','磌'=>'磌','䃣'=>'䃣','𥘦'=>'𥘦','祖'=>'祖','𥚚'=>'𥚚','𥛅'=>'𥛅','福'=>'福','秫'=>'秫','䄯'=>'䄯','穀'=>'穀','穊'=>'穊','穏'=>'穏','𥥼'=>'𥥼','𥪧'=>'𥪧','𥪧'=>'𥪧','竮'=>'竮','䈂'=>'䈂','𥮫'=>'𥮫','篆'=>'篆','築'=>'築','䈧'=>'䈧','𥲀'=>'𥲀','糒'=>'糒','䊠'=>'䊠','糨'=>'糨','糣'=>'糣','紀'=>'紀','𥾆'=>'𥾆','絣'=>'絣','䌁'=>'䌁','緇'=>'緇','縂'=>'縂','繅'=>'繅','䌴'=>'䌴','𦈨'=>'𦈨','𦉇'=>'𦉇','䍙'=>'䍙','𦋙'=>'𦋙','罺'=>'罺','𦌾'=>'𦌾','羕'=>'羕','翺'=>'翺','者'=>'者','𦓚'=>'𦓚','𦔣'=>'𦔣','聠'=>'聠','𦖨'=>'𦖨','聰'=>'聰','𣍟'=>'𣍟','䏕'=>'䏕','育'=>'育','脃'=>'脃','䐋'=>'䐋','脾'=>'脾','媵'=>'媵','𦞧'=>'𦞧','𦞵'=>'𦞵','𣎓'=>'𣎓','𣎜'=>'𣎜','舁'=>'舁','舄'=>'舄','辞'=>'辞','䑫'=>'䑫','芑'=>'芑','芋'=>'芋','芝'=>'芝','劳'=>'劳','花'=>'花','芳'=>'芳','芽'=>'芽','苦'=>'苦','𦬼'=>'𦬼','若'=>'若','茝'=>'茝','荣'=>'荣','莭'=>'莭','茣'=>'茣','莽'=>'莽','菧'=>'菧','著'=>'著','荓'=>'荓','菊'=>'菊','菌'=>'菌','菜'=>'菜','𦰶'=>'𦰶','𦵫'=>'𦵫','𦳕'=>'𦳕','䔫'=>'䔫','蓱'=>'蓱','蓳'=>'蓳','蔖'=>'蔖','𧏊'=>'𧏊','蕤'=>'蕤','𦼬'=>'𦼬','䕝'=>'䕝','䕡'=>'䕡','𦾱'=>'𦾱','𧃒'=>'𧃒','䕫'=>'䕫','虐'=>'虐','虜'=>'虜','虧'=>'虧','虩'=>'虩','蚩'=>'蚩','蚈'=>'蚈','蜎'=>'蜎','蛢'=>'蛢','蝹'=>'蝹','蜨'=>'蜨','蝫'=>'蝫','螆'=>'螆','䗗'=>'䗗','蟡'=>'蟡','蠁'=>'蠁','䗹'=>'䗹','衠'=>'衠','衣'=>'衣','𧙧'=>'𧙧','裗'=>'裗','裞'=>'裞','䘵'=>'䘵','裺'=>'裺','㒻'=>'㒻','𧢮'=>'𧢮','𧥦'=>'𧥦','䚾'=>'䚾','䛇'=>'䛇','誠'=>'誠','諭'=>'諭','變'=>'變','豕'=>'豕','𧲨'=>'𧲨','貫'=>'貫','賁'=>'賁','贛'=>'贛','起'=>'起','𧼯'=>'𧼯','𠠄'=>'𠠄','跋'=>'跋','趼'=>'趼','跰'=>'跰','𠣞'=>'𠣞','軔'=>'軔','輸'=>'輸','𨗒'=>'𨗒','𨗭'=>'𨗭','邔'=>'邔','郱'=>'郱','鄑'=>'鄑','𨜮'=>'𨜮','鄛'=>'鄛','鈸'=>'鈸','鋗'=>'鋗','鋘'=>'鋘','鉼'=>'鉼','鏹'=>'鏹','鐕'=>'鐕','𨯺'=>'𨯺','開'=>'開','䦕'=>'䦕','閷'=>'閷','𨵷'=>'𨵷','䧦'=>'䧦','雃'=>'雃','嶲'=>'嶲','霣'=>'霣','𩅅'=>'𩅅','𩈚'=>'𩈚','䩮'=>'䩮','䩶'=>'䩶','韠'=>'韠','𩐊'=>'𩐊','䪲'=>'䪲','𩒖'=>'𩒖','頋'=>'頋','頋'=>'頋','頩'=>'頩','𩖶'=>'𩖶','飢'=>'飢','䬳'=>'䬳','餩'=>'餩','馧'=>'馧','駂'=>'駂','駾'=>'駾','䯎'=>'䯎','𩬰'=>'𩬰','鬒'=>'鬒','鱀'=>'鱀','鳽'=>'鳽','䳎'=>'䳎','䳭'=>'䳭','鵧'=>'鵧','𪃎'=>'𪃎','䳸'=>'䳸','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','麻'=>'麻','䵖'=>'䵖','黹'=>'黹','黾'=>'黾','鼅'=>'鼅','鼏'=>'鼏','鼖'=>'鼖','鼻'=>'鼻','𪘀'=>'𪘀');
\ No newline at end of file +$GLOBALS['utf_canonical_decomp']=array('À'=>'À','Á'=>'Á','Â'=>'Â','Ã'=>'Ã','Ä'=>'Ä','Å'=>'Å','Ç'=>'Ç','È'=>'È','É'=>'É','Ê'=>'Ê','Ë'=>'Ë','Ì'=>'Ì','Í'=>'Í','Î'=>'Î','Ï'=>'Ï','Ñ'=>'Ñ','Ò'=>'Ò','Ó'=>'Ó','Ô'=>'Ô','Õ'=>'Õ','Ö'=>'Ö','Ù'=>'Ù','Ú'=>'Ú','Û'=>'Û','Ü'=>'Ü','Ý'=>'Ý','à'=>'à','á'=>'á','â'=>'â','ã'=>'ã','ä'=>'ä','å'=>'å','ç'=>'ç','è'=>'è','é'=>'é','ê'=>'ê','ë'=>'ë','ì'=>'ì','í'=>'í','î'=>'î','ï'=>'ï','ñ'=>'ñ','ò'=>'ò','ó'=>'ó','ô'=>'ô','õ'=>'õ','ö'=>'ö','ù'=>'ù','ú'=>'ú','û'=>'û','ü'=>'ü','ý'=>'ý','ÿ'=>'ÿ','Ā'=>'Ā','ā'=>'ā','Ă'=>'Ă','ă'=>'ă','Ą'=>'Ą','ą'=>'ą','Ć'=>'Ć','ć'=>'ć','Ĉ'=>'Ĉ','ĉ'=>'ĉ','Ċ'=>'Ċ','ċ'=>'ċ','Č'=>'Č','č'=>'č','Ď'=>'Ď','ď'=>'ď','Ē'=>'Ē','ē'=>'ē','Ĕ'=>'Ĕ','ĕ'=>'ĕ','Ė'=>'Ė','ė'=>'ė','Ę'=>'Ę','ę'=>'ę','Ě'=>'Ě','ě'=>'ě','Ĝ'=>'Ĝ','ĝ'=>'ĝ','Ğ'=>'Ğ','ğ'=>'ğ','Ġ'=>'Ġ','ġ'=>'ġ','Ģ'=>'Ģ','ģ'=>'ģ','Ĥ'=>'Ĥ','ĥ'=>'ĥ','Ĩ'=>'Ĩ','ĩ'=>'ĩ','Ī'=>'Ī','ī'=>'ī','Ĭ'=>'Ĭ','ĭ'=>'ĭ','Į'=>'Į','į'=>'į','İ'=>'İ','Ĵ'=>'Ĵ','ĵ'=>'ĵ','Ķ'=>'Ķ','ķ'=>'ķ','Ĺ'=>'Ĺ','ĺ'=>'ĺ','Ļ'=>'Ļ','ļ'=>'ļ','Ľ'=>'Ľ','ľ'=>'ľ','Ń'=>'Ń','ń'=>'ń','Ņ'=>'Ņ','ņ'=>'ņ','Ň'=>'Ň','ň'=>'ň','Ō'=>'Ō','ō'=>'ō','Ŏ'=>'Ŏ','ŏ'=>'ŏ','Ő'=>'Ő','ő'=>'ő','Ŕ'=>'Ŕ','ŕ'=>'ŕ','Ŗ'=>'Ŗ','ŗ'=>'ŗ','Ř'=>'Ř','ř'=>'ř','Ś'=>'Ś','ś'=>'ś','Ŝ'=>'Ŝ','ŝ'=>'ŝ','Ş'=>'Ş','ş'=>'ş','Š'=>'Š','š'=>'š','Ţ'=>'Ţ','ţ'=>'ţ','Ť'=>'Ť','ť'=>'ť','Ũ'=>'Ũ','ũ'=>'ũ','Ū'=>'Ū','ū'=>'ū','Ŭ'=>'Ŭ','ŭ'=>'ŭ','Ů'=>'Ů','ů'=>'ů','Ű'=>'Ű','ű'=>'ű','Ų'=>'Ų','ų'=>'ų','Ŵ'=>'Ŵ','ŵ'=>'ŵ','Ŷ'=>'Ŷ','ŷ'=>'ŷ','Ÿ'=>'Ÿ','Ź'=>'Ź','ź'=>'ź','Ż'=>'Ż','ż'=>'ż','Ž'=>'Ž','ž'=>'ž','Ơ'=>'Ơ','ơ'=>'ơ','Ư'=>'Ư','ư'=>'ư','Ǎ'=>'Ǎ','ǎ'=>'ǎ','Ǐ'=>'Ǐ','ǐ'=>'ǐ','Ǒ'=>'Ǒ','ǒ'=>'ǒ','Ǔ'=>'Ǔ','ǔ'=>'ǔ','Ǖ'=>'Ǖ','ǖ'=>'ǖ','Ǘ'=>'Ǘ','ǘ'=>'ǘ','Ǚ'=>'Ǚ','ǚ'=>'ǚ','Ǜ'=>'Ǜ','ǜ'=>'ǜ','Ǟ'=>'Ǟ','ǟ'=>'ǟ','Ǡ'=>'Ǡ','ǡ'=>'ǡ','Ǣ'=>'Ǣ','ǣ'=>'ǣ','Ǧ'=>'Ǧ','ǧ'=>'ǧ','Ǩ'=>'Ǩ','ǩ'=>'ǩ','Ǫ'=>'Ǫ','ǫ'=>'ǫ','Ǭ'=>'Ǭ','ǭ'=>'ǭ','Ǯ'=>'Ǯ','ǯ'=>'ǯ','ǰ'=>'ǰ','Ǵ'=>'Ǵ','ǵ'=>'ǵ','Ǹ'=>'Ǹ','ǹ'=>'ǹ','Ǻ'=>'Ǻ','ǻ'=>'ǻ','Ǽ'=>'Ǽ','ǽ'=>'ǽ','Ǿ'=>'Ǿ','ǿ'=>'ǿ','Ȁ'=>'Ȁ','ȁ'=>'ȁ','Ȃ'=>'Ȃ','ȃ'=>'ȃ','Ȅ'=>'Ȅ','ȅ'=>'ȅ','Ȇ'=>'Ȇ','ȇ'=>'ȇ','Ȉ'=>'Ȉ','ȉ'=>'ȉ','Ȋ'=>'Ȋ','ȋ'=>'ȋ','Ȍ'=>'Ȍ','ȍ'=>'ȍ','Ȏ'=>'Ȏ','ȏ'=>'ȏ','Ȑ'=>'Ȑ','ȑ'=>'ȑ','Ȓ'=>'Ȓ','ȓ'=>'ȓ','Ȕ'=>'Ȕ','ȕ'=>'ȕ','Ȗ'=>'Ȗ','ȗ'=>'ȗ','Ș'=>'Ș','ș'=>'ș','Ț'=>'Ț','ț'=>'ț','Ȟ'=>'Ȟ','ȟ'=>'ȟ','Ȧ'=>'Ȧ','ȧ'=>'ȧ','Ȩ'=>'Ȩ','ȩ'=>'ȩ','Ȫ'=>'Ȫ','ȫ'=>'ȫ','Ȭ'=>'Ȭ','ȭ'=>'ȭ','Ȯ'=>'Ȯ','ȯ'=>'ȯ','Ȱ'=>'Ȱ','ȱ'=>'ȱ','Ȳ'=>'Ȳ','ȳ'=>'ȳ','̀'=>'̀','́'=>'́','̓'=>'̓','̈́'=>'̈́','ʹ'=>'ʹ',';'=>';','΅'=>'΅','Ά'=>'Ά','·'=>'·','Έ'=>'Έ','Ή'=>'Ή','Ί'=>'Ί','Ό'=>'Ό','Ύ'=>'Ύ','Ώ'=>'Ώ','ΐ'=>'ΐ','Ϊ'=>'Ϊ','Ϋ'=>'Ϋ','ά'=>'ά','έ'=>'έ','ή'=>'ή','ί'=>'ί','ΰ'=>'ΰ','ϊ'=>'ϊ','ϋ'=>'ϋ','ό'=>'ό','ύ'=>'ύ','ώ'=>'ώ','ϓ'=>'ϓ','ϔ'=>'ϔ','Ѐ'=>'Ѐ','Ё'=>'Ё','Ѓ'=>'Ѓ','Ї'=>'Ї','Ќ'=>'Ќ','Ѝ'=>'Ѝ','Ў'=>'Ў','Й'=>'Й','й'=>'й','ѐ'=>'ѐ','ё'=>'ё','ѓ'=>'ѓ','ї'=>'ї','ќ'=>'ќ','ѝ'=>'ѝ','ў'=>'ў','Ѷ'=>'Ѷ','ѷ'=>'ѷ','Ӂ'=>'Ӂ','ӂ'=>'ӂ','Ӑ'=>'Ӑ','ӑ'=>'ӑ','Ӓ'=>'Ӓ','ӓ'=>'ӓ','Ӗ'=>'Ӗ','ӗ'=>'ӗ','Ӛ'=>'Ӛ','ӛ'=>'ӛ','Ӝ'=>'Ӝ','ӝ'=>'ӝ','Ӟ'=>'Ӟ','ӟ'=>'ӟ','Ӣ'=>'Ӣ','ӣ'=>'ӣ','Ӥ'=>'Ӥ','ӥ'=>'ӥ','Ӧ'=>'Ӧ','ӧ'=>'ӧ','Ӫ'=>'Ӫ','ӫ'=>'ӫ','Ӭ'=>'Ӭ','ӭ'=>'ӭ','Ӯ'=>'Ӯ','ӯ'=>'ӯ','Ӱ'=>'Ӱ','ӱ'=>'ӱ','Ӳ'=>'Ӳ','ӳ'=>'ӳ','Ӵ'=>'Ӵ','ӵ'=>'ӵ','Ӹ'=>'Ӹ','ӹ'=>'ӹ','آ'=>'آ','أ'=>'أ','ؤ'=>'ؤ','إ'=>'إ','ئ'=>'ئ','ۀ'=>'ۀ','ۂ'=>'ۂ','ۓ'=>'ۓ','ऩ'=>'ऩ','ऱ'=>'ऱ','ऴ'=>'ऴ','क़'=>'क़','ख़'=>'ख़','ग़'=>'ग़','ज़'=>'ज़','ड़'=>'ड़','ढ़'=>'ढ़','फ़'=>'फ़','य़'=>'य़','ো'=>'ো','ৌ'=>'ৌ','ড়'=>'ড়','ঢ়'=>'ঢ়','য়'=>'য়','ਲ਼'=>'ਲ਼','ਸ਼'=>'ਸ਼','ਖ਼'=>'ਖ਼','ਗ਼'=>'ਗ਼','ਜ਼'=>'ਜ਼','ਫ਼'=>'ਫ਼','ୈ'=>'ୈ','ୋ'=>'ୋ','ୌ'=>'ୌ','ଡ଼'=>'ଡ଼','ଢ଼'=>'ଢ଼','ஔ'=>'ஔ','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','ై'=>'ై','ೀ'=>'ೀ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','ේ'=>'ේ','ො'=>'ො','ෝ'=>'ෝ','ෞ'=>'ෞ','གྷ'=>'གྷ','ཌྷ'=>'ཌྷ','དྷ'=>'དྷ','བྷ'=>'བྷ','ཛྷ'=>'ཛྷ','ཀྵ'=>'ཀྵ','ཱི'=>'ཱི','ཱུ'=>'ཱུ','ྲྀ'=>'ྲྀ','ླྀ'=>'ླྀ','ཱྀ'=>'ཱྀ','ྒྷ'=>'ྒྷ','ྜྷ'=>'ྜྷ','ྡྷ'=>'ྡྷ','ྦྷ'=>'ྦྷ','ྫྷ'=>'ྫྷ','ྐྵ'=>'ྐྵ','ဦ'=>'ဦ','ᬆ'=>'ᬆ','ᬈ'=>'ᬈ','ᬊ'=>'ᬊ','ᬌ'=>'ᬌ','ᬎ'=>'ᬎ','ᬒ'=>'ᬒ','ᬻ'=>'ᬻ','ᬽ'=>'ᬽ','ᭀ'=>'ᭀ','ᭁ'=>'ᭁ','ᭃ'=>'ᭃ','Ḁ'=>'Ḁ','ḁ'=>'ḁ','Ḃ'=>'Ḃ','ḃ'=>'ḃ','Ḅ'=>'Ḅ','ḅ'=>'ḅ','Ḇ'=>'Ḇ','ḇ'=>'ḇ','Ḉ'=>'Ḉ','ḉ'=>'ḉ','Ḋ'=>'Ḋ','ḋ'=>'ḋ','Ḍ'=>'Ḍ','ḍ'=>'ḍ','Ḏ'=>'Ḏ','ḏ'=>'ḏ','Ḑ'=>'Ḑ','ḑ'=>'ḑ','Ḓ'=>'Ḓ','ḓ'=>'ḓ','Ḕ'=>'Ḕ','ḕ'=>'ḕ','Ḗ'=>'Ḗ','ḗ'=>'ḗ','Ḙ'=>'Ḙ','ḙ'=>'ḙ','Ḛ'=>'Ḛ','ḛ'=>'ḛ','Ḝ'=>'Ḝ','ḝ'=>'ḝ','Ḟ'=>'Ḟ','ḟ'=>'ḟ','Ḡ'=>'Ḡ','ḡ'=>'ḡ','Ḣ'=>'Ḣ','ḣ'=>'ḣ','Ḥ'=>'Ḥ','ḥ'=>'ḥ','Ḧ'=>'Ḧ','ḧ'=>'ḧ','Ḩ'=>'Ḩ','ḩ'=>'ḩ','Ḫ'=>'Ḫ','ḫ'=>'ḫ','Ḭ'=>'Ḭ','ḭ'=>'ḭ','Ḯ'=>'Ḯ','ḯ'=>'ḯ','Ḱ'=>'Ḱ','ḱ'=>'ḱ','Ḳ'=>'Ḳ','ḳ'=>'ḳ','Ḵ'=>'Ḵ','ḵ'=>'ḵ','Ḷ'=>'Ḷ','ḷ'=>'ḷ','Ḹ'=>'Ḹ','ḹ'=>'ḹ','Ḻ'=>'Ḻ','ḻ'=>'ḻ','Ḽ'=>'Ḽ','ḽ'=>'ḽ','Ḿ'=>'Ḿ','ḿ'=>'ḿ','Ṁ'=>'Ṁ','ṁ'=>'ṁ','Ṃ'=>'Ṃ','ṃ'=>'ṃ','Ṅ'=>'Ṅ','ṅ'=>'ṅ','Ṇ'=>'Ṇ','ṇ'=>'ṇ','Ṉ'=>'Ṉ','ṉ'=>'ṉ','Ṋ'=>'Ṋ','ṋ'=>'ṋ','Ṍ'=>'Ṍ','ṍ'=>'ṍ','Ṏ'=>'Ṏ','ṏ'=>'ṏ','Ṑ'=>'Ṑ','ṑ'=>'ṑ','Ṓ'=>'Ṓ','ṓ'=>'ṓ','Ṕ'=>'Ṕ','ṕ'=>'ṕ','Ṗ'=>'Ṗ','ṗ'=>'ṗ','Ṙ'=>'Ṙ','ṙ'=>'ṙ','Ṛ'=>'Ṛ','ṛ'=>'ṛ','Ṝ'=>'Ṝ','ṝ'=>'ṝ','Ṟ'=>'Ṟ','ṟ'=>'ṟ','Ṡ'=>'Ṡ','ṡ'=>'ṡ','Ṣ'=>'Ṣ','ṣ'=>'ṣ','Ṥ'=>'Ṥ','ṥ'=>'ṥ','Ṧ'=>'Ṧ','ṧ'=>'ṧ','Ṩ'=>'Ṩ','ṩ'=>'ṩ','Ṫ'=>'Ṫ','ṫ'=>'ṫ','Ṭ'=>'Ṭ','ṭ'=>'ṭ','Ṯ'=>'Ṯ','ṯ'=>'ṯ','Ṱ'=>'Ṱ','ṱ'=>'ṱ','Ṳ'=>'Ṳ','ṳ'=>'ṳ','Ṵ'=>'Ṵ','ṵ'=>'ṵ','Ṷ'=>'Ṷ','ṷ'=>'ṷ','Ṹ'=>'Ṹ','ṹ'=>'ṹ','Ṻ'=>'Ṻ','ṻ'=>'ṻ','Ṽ'=>'Ṽ','ṽ'=>'ṽ','Ṿ'=>'Ṿ','ṿ'=>'ṿ','Ẁ'=>'Ẁ','ẁ'=>'ẁ','Ẃ'=>'Ẃ','ẃ'=>'ẃ','Ẅ'=>'Ẅ','ẅ'=>'ẅ','Ẇ'=>'Ẇ','ẇ'=>'ẇ','Ẉ'=>'Ẉ','ẉ'=>'ẉ','Ẋ'=>'Ẋ','ẋ'=>'ẋ','Ẍ'=>'Ẍ','ẍ'=>'ẍ','Ẏ'=>'Ẏ','ẏ'=>'ẏ','Ẑ'=>'Ẑ','ẑ'=>'ẑ','Ẓ'=>'Ẓ','ẓ'=>'ẓ','Ẕ'=>'Ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẛ'=>'ẛ','Ạ'=>'Ạ','ạ'=>'ạ','Ả'=>'Ả','ả'=>'ả','Ấ'=>'Ấ','ấ'=>'ấ','Ầ'=>'Ầ','ầ'=>'ầ','Ẩ'=>'Ẩ','ẩ'=>'ẩ','Ẫ'=>'Ẫ','ẫ'=>'ẫ','Ậ'=>'Ậ','ậ'=>'ậ','Ắ'=>'Ắ','ắ'=>'ắ','Ằ'=>'Ằ','ằ'=>'ằ','Ẳ'=>'Ẳ','ẳ'=>'ẳ','Ẵ'=>'Ẵ','ẵ'=>'ẵ','Ặ'=>'Ặ','ặ'=>'ặ','Ẹ'=>'Ẹ','ẹ'=>'ẹ','Ẻ'=>'Ẻ','ẻ'=>'ẻ','Ẽ'=>'Ẽ','ẽ'=>'ẽ','Ế'=>'Ế','ế'=>'ế','Ề'=>'Ề','ề'=>'ề','Ể'=>'Ể','ể'=>'ể','Ễ'=>'Ễ','ễ'=>'ễ','Ệ'=>'Ệ','ệ'=>'ệ','Ỉ'=>'Ỉ','ỉ'=>'ỉ','Ị'=>'Ị','ị'=>'ị','Ọ'=>'Ọ','ọ'=>'ọ','Ỏ'=>'Ỏ','ỏ'=>'ỏ','Ố'=>'Ố','ố'=>'ố','Ồ'=>'Ồ','ồ'=>'ồ','Ổ'=>'Ổ','ổ'=>'ổ','Ỗ'=>'Ỗ','ỗ'=>'ỗ','Ộ'=>'Ộ','ộ'=>'ộ','Ớ'=>'Ớ','ớ'=>'ớ','Ờ'=>'Ờ','ờ'=>'ờ','Ở'=>'Ở','ở'=>'ở','Ỡ'=>'Ỡ','ỡ'=>'ỡ','Ợ'=>'Ợ','ợ'=>'ợ','Ụ'=>'Ụ','ụ'=>'ụ','Ủ'=>'Ủ','ủ'=>'ủ','Ứ'=>'Ứ','ứ'=>'ứ','Ừ'=>'Ừ','ừ'=>'ừ','Ử'=>'Ử','ử'=>'ử','Ữ'=>'Ữ','ữ'=>'ữ','Ự'=>'Ự','ự'=>'ự','Ỳ'=>'Ỳ','ỳ'=>'ỳ','Ỵ'=>'Ỵ','ỵ'=>'ỵ','Ỷ'=>'Ỷ','ỷ'=>'ỷ','Ỹ'=>'Ỹ','ỹ'=>'ỹ','ἀ'=>'ἀ','ἁ'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἄ','ἅ'=>'ἅ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'Ἀ','Ἁ'=>'Ἁ','Ἂ'=>'Ἂ','Ἃ'=>'Ἃ','Ἄ'=>'Ἄ','Ἅ'=>'Ἅ','Ἆ'=>'Ἆ','Ἇ'=>'Ἇ','ἐ'=>'ἐ','ἑ'=>'ἑ','ἒ'=>'ἒ','ἓ'=>'ἓ','ἔ'=>'ἔ','ἕ'=>'ἕ','Ἐ'=>'Ἐ','Ἑ'=>'Ἑ','Ἒ'=>'Ἒ','Ἓ'=>'Ἓ','Ἔ'=>'Ἔ','Ἕ'=>'Ἕ','ἠ'=>'ἠ','ἡ'=>'ἡ','ἢ'=>'ἢ','ἣ'=>'ἣ','ἤ'=>'ἤ','ἥ'=>'ἥ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'Ἠ','Ἡ'=>'Ἡ','Ἢ'=>'Ἢ','Ἣ'=>'Ἣ','Ἤ'=>'Ἤ','Ἥ'=>'Ἥ','Ἦ'=>'Ἦ','Ἧ'=>'Ἧ','ἰ'=>'ἰ','ἱ'=>'ἱ','ἲ'=>'ἲ','ἳ'=>'ἳ','ἴ'=>'ἴ','ἵ'=>'ἵ','ἶ'=>'ἶ','ἷ'=>'ἷ','Ἰ'=>'Ἰ','Ἱ'=>'Ἱ','Ἲ'=>'Ἲ','Ἳ'=>'Ἳ','Ἴ'=>'Ἴ','Ἵ'=>'Ἵ','Ἶ'=>'Ἶ','Ἷ'=>'Ἷ','ὀ'=>'ὀ','ὁ'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὄ','ὅ'=>'ὅ','Ὀ'=>'Ὀ','Ὁ'=>'Ὁ','Ὂ'=>'Ὂ','Ὃ'=>'Ὃ','Ὄ'=>'Ὄ','Ὅ'=>'Ὅ','ὐ'=>'ὐ','ὑ'=>'ὑ','ὒ'=>'ὒ','ὓ'=>'ὓ','ὔ'=>'ὔ','ὕ'=>'ὕ','ὖ'=>'ὖ','ὗ'=>'ὗ','Ὑ'=>'Ὑ','Ὓ'=>'Ὓ','Ὕ'=>'Ὕ','Ὗ'=>'Ὗ','ὠ'=>'ὠ','ὡ'=>'ὡ','ὢ'=>'ὢ','ὣ'=>'ὣ','ὤ'=>'ὤ','ὥ'=>'ὥ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'Ὠ','Ὡ'=>'Ὡ','Ὢ'=>'Ὢ','Ὣ'=>'Ὣ','Ὤ'=>'Ὤ','Ὥ'=>'Ὥ','Ὦ'=>'Ὦ','Ὧ'=>'Ὧ','ὰ'=>'ὰ','ά'=>'ά','ὲ'=>'ὲ','έ'=>'έ','ὴ'=>'ὴ','ή'=>'ή','ὶ'=>'ὶ','ί'=>'ί','ὸ'=>'ὸ','ό'=>'ό','ὺ'=>'ὺ','ύ'=>'ύ','ὼ'=>'ὼ','ώ'=>'ώ','ᾀ'=>'ᾀ','ᾁ'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ᾄ','ᾅ'=>'ᾅ','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾈ','ᾉ'=>'ᾉ','ᾊ'=>'ᾊ','ᾋ'=>'ᾋ','ᾌ'=>'ᾌ','ᾍ'=>'ᾍ','ᾎ'=>'ᾎ','ᾏ'=>'ᾏ','ᾐ'=>'ᾐ','ᾑ'=>'ᾑ','ᾒ'=>'ᾒ','ᾓ'=>'ᾓ','ᾔ'=>'ᾔ','ᾕ'=>'ᾕ','ᾖ'=>'ᾖ','ᾗ'=>'ᾗ','ᾘ'=>'ᾘ','ᾙ'=>'ᾙ','ᾚ'=>'ᾚ','ᾛ'=>'ᾛ','ᾜ'=>'ᾜ','ᾝ'=>'ᾝ','ᾞ'=>'ᾞ','ᾟ'=>'ᾟ','ᾠ'=>'ᾠ','ᾡ'=>'ᾡ','ᾢ'=>'ᾢ','ᾣ'=>'ᾣ','ᾤ'=>'ᾤ','ᾥ'=>'ᾥ','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾨ','ᾩ'=>'ᾩ','ᾪ'=>'ᾪ','ᾫ'=>'ᾫ','ᾬ'=>'ᾬ','ᾭ'=>'ᾭ','ᾮ'=>'ᾮ','ᾯ'=>'ᾯ','ᾰ'=>'ᾰ','ᾱ'=>'ᾱ','ᾲ'=>'ᾲ','ᾳ'=>'ᾳ','ᾴ'=>'ᾴ','ᾶ'=>'ᾶ','ᾷ'=>'ᾷ','Ᾰ'=>'Ᾰ','Ᾱ'=>'Ᾱ','Ὰ'=>'Ὰ','Ά'=>'Ά','ᾼ'=>'ᾼ','ι'=>'ι','῁'=>'῁','ῂ'=>'ῂ','ῃ'=>'ῃ','ῄ'=>'ῄ','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'Ὲ','Έ'=>'Έ','Ὴ'=>'Ὴ','Ή'=>'Ή','ῌ'=>'ῌ','῍'=>'῍','῎'=>'῎','῏'=>'῏','ῐ'=>'ῐ','ῑ'=>'ῑ','ῒ'=>'ῒ','ΐ'=>'ΐ','ῖ'=>'ῖ','ῗ'=>'ῗ','Ῐ'=>'Ῐ','Ῑ'=>'Ῑ','Ὶ'=>'Ὶ','Ί'=>'Ί','῝'=>'῝','῞'=>'῞','῟'=>'῟','ῠ'=>'ῠ','ῡ'=>'ῡ','ῢ'=>'ῢ','ΰ'=>'ΰ','ῤ'=>'ῤ','ῥ'=>'ῥ','ῦ'=>'ῦ','ῧ'=>'ῧ','Ῠ'=>'Ῠ','Ῡ'=>'Ῡ','Ὺ'=>'Ὺ','Ύ'=>'Ύ','Ῥ'=>'Ῥ','῭'=>'῭','΅'=>'΅','`'=>'`','ῲ'=>'ῲ','ῳ'=>'ῳ','ῴ'=>'ῴ','ῶ'=>'ῶ','ῷ'=>'ῷ','Ὸ'=>'Ὸ','Ό'=>'Ό','Ὼ'=>'Ὼ','Ώ'=>'Ώ','ῼ'=>'ῼ','´'=>'´',' '=>' ',' '=>' ','Ω'=>'Ω','K'=>'K','Å'=>'Å','↚'=>'↚','↛'=>'↛','↮'=>'↮','⇍'=>'⇍','⇎'=>'⇎','⇏'=>'⇏','∄'=>'∄','∉'=>'∉','∌'=>'∌','∤'=>'∤','∦'=>'∦','≁'=>'≁','≄'=>'≄','≇'=>'≇','≉'=>'≉','≠'=>'≠','≢'=>'≢','≭'=>'≭','≮'=>'≮','≯'=>'≯','≰'=>'≰','≱'=>'≱','≴'=>'≴','≵'=>'≵','≸'=>'≸','≹'=>'≹','⊀'=>'⊀','⊁'=>'⊁','⊄'=>'⊄','⊅'=>'⊅','⊈'=>'⊈','⊉'=>'⊉','⊬'=>'⊬','⊭'=>'⊭','⊮'=>'⊮','⊯'=>'⊯','⋠'=>'⋠','⋡'=>'⋡','⋢'=>'⋢','⋣'=>'⋣','⋪'=>'⋪','⋫'=>'⋫','⋬'=>'⋬','⋭'=>'⋭','〈'=>'〈','〉'=>'〉','⫝̸'=>'⫝̸','が'=>'が','ぎ'=>'ぎ','ぐ'=>'ぐ','げ'=>'げ','ご'=>'ご','ざ'=>'ざ','じ'=>'じ','ず'=>'ず','ぜ'=>'ぜ','ぞ'=>'ぞ','だ'=>'だ','ぢ'=>'ぢ','づ'=>'づ','で'=>'で','ど'=>'ど','ば'=>'ば','ぱ'=>'ぱ','び'=>'び','ぴ'=>'ぴ','ぶ'=>'ぶ','ぷ'=>'ぷ','べ'=>'べ','ぺ'=>'ぺ','ぼ'=>'ぼ','ぽ'=>'ぽ','ゔ'=>'ゔ','ゞ'=>'ゞ','ガ'=>'ガ','ギ'=>'ギ','グ'=>'グ','ゲ'=>'ゲ','ゴ'=>'ゴ','ザ'=>'ザ','ジ'=>'ジ','ズ'=>'ズ','ゼ'=>'ゼ','ゾ'=>'ゾ','ダ'=>'ダ','ヂ'=>'ヂ','ヅ'=>'ヅ','デ'=>'デ','ド'=>'ド','バ'=>'バ','パ'=>'パ','ビ'=>'ビ','ピ'=>'ピ','ブ'=>'ブ','プ'=>'プ','ベ'=>'ベ','ペ'=>'ペ','ボ'=>'ボ','ポ'=>'ポ','ヴ'=>'ヴ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ヾ'=>'ヾ','豈'=>'豈','更'=>'更','車'=>'車','賈'=>'賈','滑'=>'滑','串'=>'串','句'=>'句','龜'=>'龜','龜'=>'龜','契'=>'契','金'=>'金','喇'=>'喇','奈'=>'奈','懶'=>'懶','癩'=>'癩','羅'=>'羅','蘿'=>'蘿','螺'=>'螺','裸'=>'裸','邏'=>'邏','樂'=>'樂','洛'=>'洛','烙'=>'烙','珞'=>'珞','落'=>'落','酪'=>'酪','駱'=>'駱','亂'=>'亂','卵'=>'卵','欄'=>'欄','爛'=>'爛','蘭'=>'蘭','鸞'=>'鸞','嵐'=>'嵐','濫'=>'濫','藍'=>'藍','襤'=>'襤','拉'=>'拉','臘'=>'臘','蠟'=>'蠟','廊'=>'廊','朗'=>'朗','浪'=>'浪','狼'=>'狼','郎'=>'郎','來'=>'來','冷'=>'冷','勞'=>'勞','擄'=>'擄','櫓'=>'櫓','爐'=>'爐','盧'=>'盧','老'=>'老','蘆'=>'蘆','虜'=>'虜','路'=>'路','露'=>'露','魯'=>'魯','鷺'=>'鷺','碌'=>'碌','祿'=>'祿','綠'=>'綠','菉'=>'菉','錄'=>'錄','鹿'=>'鹿','論'=>'論','壟'=>'壟','弄'=>'弄','籠'=>'籠','聾'=>'聾','牢'=>'牢','磊'=>'磊','賂'=>'賂','雷'=>'雷','壘'=>'壘','屢'=>'屢','樓'=>'樓','淚'=>'淚','漏'=>'漏','累'=>'累','縷'=>'縷','陋'=>'陋','勒'=>'勒','肋'=>'肋','凜'=>'凜','凌'=>'凌','稜'=>'稜','綾'=>'綾','菱'=>'菱','陵'=>'陵','讀'=>'讀','拏'=>'拏','樂'=>'樂','諾'=>'諾','丹'=>'丹','寧'=>'寧','怒'=>'怒','率'=>'率','異'=>'異','北'=>'北','磻'=>'磻','便'=>'便','復'=>'復','不'=>'不','泌'=>'泌','數'=>'數','索'=>'索','參'=>'參','塞'=>'塞','省'=>'省','葉'=>'葉','說'=>'說','殺'=>'殺','辰'=>'辰','沈'=>'沈','拾'=>'拾','若'=>'若','掠'=>'掠','略'=>'略','亮'=>'亮','兩'=>'兩','凉'=>'凉','梁'=>'梁','糧'=>'糧','良'=>'良','諒'=>'諒','量'=>'量','勵'=>'勵','呂'=>'呂','女'=>'女','廬'=>'廬','旅'=>'旅','濾'=>'濾','礪'=>'礪','閭'=>'閭','驪'=>'驪','麗'=>'麗','黎'=>'黎','力'=>'力','曆'=>'曆','歷'=>'歷','轢'=>'轢','年'=>'年','憐'=>'憐','戀'=>'戀','撚'=>'撚','漣'=>'漣','煉'=>'煉','璉'=>'璉','秊'=>'秊','練'=>'練','聯'=>'聯','輦'=>'輦','蓮'=>'蓮','連'=>'連','鍊'=>'鍊','列'=>'列','劣'=>'劣','咽'=>'咽','烈'=>'烈','裂'=>'裂','說'=>'說','廉'=>'廉','念'=>'念','捻'=>'捻','殮'=>'殮','簾'=>'簾','獵'=>'獵','令'=>'令','囹'=>'囹','寧'=>'寧','嶺'=>'嶺','怜'=>'怜','玲'=>'玲','瑩'=>'瑩','羚'=>'羚','聆'=>'聆','鈴'=>'鈴','零'=>'零','靈'=>'靈','領'=>'領','例'=>'例','禮'=>'禮','醴'=>'醴','隸'=>'隸','惡'=>'惡','了'=>'了','僚'=>'僚','寮'=>'寮','尿'=>'尿','料'=>'料','樂'=>'樂','燎'=>'燎','療'=>'療','蓼'=>'蓼','遼'=>'遼','龍'=>'龍','暈'=>'暈','阮'=>'阮','劉'=>'劉','杻'=>'杻','柳'=>'柳','流'=>'流','溜'=>'溜','琉'=>'琉','留'=>'留','硫'=>'硫','紐'=>'紐','類'=>'類','六'=>'六','戮'=>'戮','陸'=>'陸','倫'=>'倫','崙'=>'崙','淪'=>'淪','輪'=>'輪','律'=>'律','慄'=>'慄','栗'=>'栗','率'=>'率','隆'=>'隆','利'=>'利','吏'=>'吏','履'=>'履','易'=>'易','李'=>'李','梨'=>'梨','泥'=>'泥','理'=>'理','痢'=>'痢','罹'=>'罹','裏'=>'裏','裡'=>'裡','里'=>'里','離'=>'離','匿'=>'匿','溺'=>'溺','吝'=>'吝','燐'=>'燐','璘'=>'璘','藺'=>'藺','隣'=>'隣','鱗'=>'鱗','麟'=>'麟','林'=>'林','淋'=>'淋','臨'=>'臨','立'=>'立','笠'=>'笠','粒'=>'粒','狀'=>'狀','炙'=>'炙','識'=>'識','什'=>'什','茶'=>'茶','刺'=>'刺','切'=>'切','度'=>'度','拓'=>'拓','糖'=>'糖','宅'=>'宅','洞'=>'洞','暴'=>'暴','輻'=>'輻','行'=>'行','降'=>'降','見'=>'見','廓'=>'廓','兀'=>'兀','嗀'=>'嗀','塚'=>'塚','晴'=>'晴','凞'=>'凞','猪'=>'猪','益'=>'益','礼'=>'礼','神'=>'神','祥'=>'祥','福'=>'福','靖'=>'靖','精'=>'精','羽'=>'羽','蘒'=>'蘒','諸'=>'諸','逸'=>'逸','都'=>'都','飯'=>'飯','飼'=>'飼','館'=>'館','鶴'=>'鶴','侮'=>'侮','僧'=>'僧','免'=>'免','勉'=>'勉','勤'=>'勤','卑'=>'卑','喝'=>'喝','嘆'=>'嘆','器'=>'器','塀'=>'塀','墨'=>'墨','層'=>'層','屮'=>'屮','悔'=>'悔','慨'=>'慨','憎'=>'憎','懲'=>'懲','敏'=>'敏','既'=>'既','暑'=>'暑','梅'=>'梅','海'=>'海','渚'=>'渚','漢'=>'漢','煮'=>'煮','爫'=>'爫','琢'=>'琢','碑'=>'碑','社'=>'社','祉'=>'祉','祈'=>'祈','祐'=>'祐','祖'=>'祖','祝'=>'祝','禍'=>'禍','禎'=>'禎','穀'=>'穀','突'=>'突','節'=>'節','練'=>'練','縉'=>'縉','繁'=>'繁','署'=>'署','者'=>'者','臭'=>'臭','艹'=>'艹','艹'=>'艹','著'=>'著','褐'=>'褐','視'=>'視','謁'=>'謁','謹'=>'謹','賓'=>'賓','贈'=>'贈','辶'=>'辶','逸'=>'逸','難'=>'難','響'=>'響','頻'=>'頻','並'=>'並','况'=>'况','全'=>'全','侀'=>'侀','充'=>'充','冀'=>'冀','勇'=>'勇','勺'=>'勺','喝'=>'喝','啕'=>'啕','喙'=>'喙','嗢'=>'嗢','塚'=>'塚','墳'=>'墳','奄'=>'奄','奔'=>'奔','婢'=>'婢','嬨'=>'嬨','廒'=>'廒','廙'=>'廙','彩'=>'彩','徭'=>'徭','惘'=>'惘','慎'=>'慎','愈'=>'愈','憎'=>'憎','慠'=>'慠','懲'=>'懲','戴'=>'戴','揄'=>'揄','搜'=>'搜','摒'=>'摒','敖'=>'敖','晴'=>'晴','朗'=>'朗','望'=>'望','杖'=>'杖','歹'=>'歹','殺'=>'殺','流'=>'流','滛'=>'滛','滋'=>'滋','漢'=>'漢','瀞'=>'瀞','煮'=>'煮','瞧'=>'瞧','爵'=>'爵','犯'=>'犯','猪'=>'猪','瑱'=>'瑱','甆'=>'甆','画'=>'画','瘝'=>'瘝','瘟'=>'瘟','益'=>'益','盛'=>'盛','直'=>'直','睊'=>'睊','着'=>'着','磌'=>'磌','窱'=>'窱','節'=>'節','类'=>'类','絛'=>'絛','練'=>'練','缾'=>'缾','者'=>'者','荒'=>'荒','華'=>'華','蝹'=>'蝹','襁'=>'襁','覆'=>'覆','視'=>'視','調'=>'調','諸'=>'諸','請'=>'請','謁'=>'謁','諾'=>'諾','諭'=>'諭','謹'=>'謹','變'=>'變','贈'=>'贈','輸'=>'輸','遲'=>'遲','醙'=>'醙','鉶'=>'鉶','陼'=>'陼','難'=>'難','靖'=>'靖','韛'=>'韛','響'=>'響','頋'=>'頋','頻'=>'頻','鬒'=>'鬒','龜'=>'龜','𢡊'=>'𢡊','𢡄'=>'𢡄','𣏕'=>'𣏕','㮝'=>'㮝','䀘'=>'䀘','䀹'=>'䀹','𥉉'=>'𥉉','𥳐'=>'𥳐','𧻓'=>'𧻓','齃'=>'齃','龎'=>'龎','יִ'=>'יִ','ײַ'=>'ײַ','שׁ'=>'שׁ','שׂ'=>'שׂ','שּׁ'=>'שּׁ','שּׂ'=>'שּׂ','אַ'=>'אַ','אָ'=>'אָ','אּ'=>'אּ','בּ'=>'בּ','גּ'=>'גּ','דּ'=>'דּ','הּ'=>'הּ','וּ'=>'וּ','זּ'=>'זּ','טּ'=>'טּ','יּ'=>'יּ','ךּ'=>'ךּ','כּ'=>'כּ','לּ'=>'לּ','מּ'=>'מּ','נּ'=>'נּ','סּ'=>'סּ','ףּ'=>'ףּ','פּ'=>'פּ','צּ'=>'צּ','קּ'=>'קּ','רּ'=>'רּ','שּ'=>'שּ','תּ'=>'תּ','וֹ'=>'וֹ','בֿ'=>'בֿ','כֿ'=>'כֿ','פֿ'=>'פֿ','𝅗𝅥'=>'𝅗𝅥','𝅘𝅥'=>'𝅘𝅥','𝅘𝅥𝅮'=>'𝅘𝅥𝅮','𝅘𝅥𝅯'=>'𝅘𝅥𝅯','𝅘𝅥𝅰'=>'𝅘𝅥𝅰','𝅘𝅥𝅱'=>'𝅘𝅥𝅱','𝅘𝅥𝅲'=>'𝅘𝅥𝅲','𝆹𝅥'=>'𝆹𝅥','𝆺𝅥'=>'𝆺𝅥','𝆹𝅥𝅮'=>'𝆹𝅥𝅮','𝆺𝅥𝅮'=>'𝆺𝅥𝅮','𝆹𝅥𝅯'=>'𝆹𝅥𝅯','𝆺𝅥𝅯'=>'𝆺𝅥𝅯','丽'=>'丽','丸'=>'丸','乁'=>'乁','𠄢'=>'𠄢','你'=>'你','侮'=>'侮','侻'=>'侻','倂'=>'倂','偺'=>'偺','備'=>'備','僧'=>'僧','像'=>'像','㒞'=>'㒞','𠘺'=>'𠘺','免'=>'免','兔'=>'兔','兤'=>'兤','具'=>'具','𠔜'=>'𠔜','㒹'=>'㒹','內'=>'內','再'=>'再','𠕋'=>'𠕋','冗'=>'冗','冤'=>'冤','仌'=>'仌','冬'=>'冬','况'=>'况','𩇟'=>'𩇟','凵'=>'凵','刃'=>'刃','㓟'=>'㓟','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','㔕'=>'㔕','勇'=>'勇','勉'=>'勉','勤'=>'勤','勺'=>'勺','包'=>'包','匆'=>'匆','北'=>'北','卉'=>'卉','卑'=>'卑','博'=>'博','即'=>'即','卽'=>'卽','卿'=>'卿','卿'=>'卿','卿'=>'卿','𠨬'=>'𠨬','灰'=>'灰','及'=>'及','叟'=>'叟','𠭣'=>'𠭣','叫'=>'叫','叱'=>'叱','吆'=>'吆','咞'=>'咞','吸'=>'吸','呈'=>'呈','周'=>'周','咢'=>'咢','哶'=>'哶','唐'=>'唐','啓'=>'啓','啣'=>'啣','善'=>'善','善'=>'善','喙'=>'喙','喫'=>'喫','喳'=>'喳','嗂'=>'嗂','圖'=>'圖','嘆'=>'嘆','圗'=>'圗','噑'=>'噑','噴'=>'噴','切'=>'切','壮'=>'壮','城'=>'城','埴'=>'埴','堍'=>'堍','型'=>'型','堲'=>'堲','報'=>'報','墬'=>'墬','𡓤'=>'𡓤','売'=>'売','壷'=>'壷','夆'=>'夆','多'=>'多','夢'=>'夢','奢'=>'奢','𡚨'=>'𡚨','𡛪'=>'𡛪','姬'=>'姬','娛'=>'娛','娧'=>'娧','姘'=>'姘','婦'=>'婦','㛮'=>'㛮','㛼'=>'㛼','嬈'=>'嬈','嬾'=>'嬾','嬾'=>'嬾','𡧈'=>'𡧈','寃'=>'寃','寘'=>'寘','寧'=>'寧','寳'=>'寳','𡬘'=>'𡬘','寿'=>'寿','将'=>'将','当'=>'当','尢'=>'尢','㞁'=>'㞁','屠'=>'屠','屮'=>'屮','峀'=>'峀','岍'=>'岍','𡷤'=>'𡷤','嵃'=>'嵃','𡷦'=>'𡷦','嵮'=>'嵮','嵫'=>'嵫','嵼'=>'嵼','巡'=>'巡','巢'=>'巢','㠯'=>'㠯','巽'=>'巽','帨'=>'帨','帽'=>'帽','幩'=>'幩','㡢'=>'㡢','𢆃'=>'𢆃','㡼'=>'㡼','庰'=>'庰','庳'=>'庳','庶'=>'庶','廊'=>'廊','𪎒'=>'𪎒','廾'=>'廾','𢌱'=>'𢌱','𢌱'=>'𢌱','舁'=>'舁','弢'=>'弢','弢'=>'弢','㣇'=>'㣇','𣊸'=>'𣊸','𦇚'=>'𦇚','形'=>'形','彫'=>'彫','㣣'=>'㣣','徚'=>'徚','忍'=>'忍','志'=>'志','忹'=>'忹','悁'=>'悁','㤺'=>'㤺','㤜'=>'㤜','悔'=>'悔','𢛔'=>'𢛔','惇'=>'惇','慈'=>'慈','慌'=>'慌','慎'=>'慎','慌'=>'慌','慺'=>'慺','憎'=>'憎','憲'=>'憲','憤'=>'憤','憯'=>'憯','懞'=>'懞','懲'=>'懲','懶'=>'懶','成'=>'成','戛'=>'戛','扝'=>'扝','抱'=>'抱','拔'=>'拔','捐'=>'捐','𢬌'=>'𢬌','挽'=>'挽','拼'=>'拼','捨'=>'捨','掃'=>'掃','揤'=>'揤','𢯱'=>'𢯱','搢'=>'搢','揅'=>'揅','掩'=>'掩','㨮'=>'㨮','摩'=>'摩','摾'=>'摾','撝'=>'撝','摷'=>'摷','㩬'=>'㩬','敏'=>'敏','敬'=>'敬','𣀊'=>'𣀊','旣'=>'旣','書'=>'書','晉'=>'晉','㬙'=>'㬙','暑'=>'暑','㬈'=>'㬈','㫤'=>'㫤','冒'=>'冒','冕'=>'冕','最'=>'最','暜'=>'暜','肭'=>'肭','䏙'=>'䏙','朗'=>'朗','望'=>'望','朡'=>'朡','杞'=>'杞','杓'=>'杓','𣏃'=>'𣏃','㭉'=>'㭉','柺'=>'柺','枅'=>'枅','桒'=>'桒','梅'=>'梅','𣑭'=>'𣑭','梎'=>'梎','栟'=>'栟','椔'=>'椔','㮝'=>'㮝','楂'=>'楂','榣'=>'榣','槪'=>'槪','檨'=>'檨','𣚣'=>'𣚣','櫛'=>'櫛','㰘'=>'㰘','次'=>'次','𣢧'=>'𣢧','歔'=>'歔','㱎'=>'㱎','歲'=>'歲','殟'=>'殟','殺'=>'殺','殻'=>'殻','𣪍'=>'𣪍','𡴋'=>'𡴋','𣫺'=>'𣫺','汎'=>'汎','𣲼'=>'𣲼','沿'=>'沿','泍'=>'泍','汧'=>'汧','洖'=>'洖','派'=>'派','海'=>'海','流'=>'流','浩'=>'浩','浸'=>'浸','涅'=>'涅','𣴞'=>'𣴞','洴'=>'洴','港'=>'港','湮'=>'湮','㴳'=>'㴳','滋'=>'滋','滇'=>'滇','𣻑'=>'𣻑','淹'=>'淹','潮'=>'潮','𣽞'=>'𣽞','𣾎'=>'𣾎','濆'=>'濆','瀹'=>'瀹','瀞'=>'瀞','瀛'=>'瀛','㶖'=>'㶖','灊'=>'灊','災'=>'災','灷'=>'灷','炭'=>'炭','𠔥'=>'𠔥','煅'=>'煅','𤉣'=>'𤉣','熜'=>'熜','𤎫'=>'𤎫','爨'=>'爨','爵'=>'爵','牐'=>'牐','𤘈'=>'𤘈','犀'=>'犀','犕'=>'犕','𤜵'=>'𤜵','𤠔'=>'𤠔','獺'=>'獺','王'=>'王','㺬'=>'㺬','玥'=>'玥','㺸'=>'㺸','㺸'=>'㺸','瑇'=>'瑇','瑜'=>'瑜','瑱'=>'瑱','璅'=>'璅','瓊'=>'瓊','㼛'=>'㼛','甤'=>'甤','𤰶'=>'𤰶','甾'=>'甾','𤲒'=>'𤲒','異'=>'異','𢆟'=>'𢆟','瘐'=>'瘐','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'𥁄','㿼'=>'㿼','䀈'=>'䀈','直'=>'直','𥃳'=>'𥃳','𥃲'=>'𥃲','𥄙'=>'𥄙','𥄳'=>'𥄳','眞'=>'眞','真'=>'真','真'=>'真','睊'=>'睊','䀹'=>'䀹','瞋'=>'瞋','䁆'=>'䁆','䂖'=>'䂖','𥐝'=>'𥐝','硎'=>'硎','碌'=>'碌','磌'=>'磌','䃣'=>'䃣','𥘦'=>'𥘦','祖'=>'祖','𥚚'=>'𥚚','𥛅'=>'𥛅','福'=>'福','秫'=>'秫','䄯'=>'䄯','穀'=>'穀','穊'=>'穊','穏'=>'穏','𥥼'=>'𥥼','𥪧'=>'𥪧','𥪧'=>'𥪧','竮'=>'竮','䈂'=>'䈂','𥮫'=>'𥮫','篆'=>'篆','築'=>'築','䈧'=>'䈧','𥲀'=>'𥲀','糒'=>'糒','䊠'=>'䊠','糨'=>'糨','糣'=>'糣','紀'=>'紀','𥾆'=>'𥾆','絣'=>'絣','䌁'=>'䌁','緇'=>'緇','縂'=>'縂','繅'=>'繅','䌴'=>'䌴','𦈨'=>'𦈨','𦉇'=>'𦉇','䍙'=>'䍙','𦋙'=>'𦋙','罺'=>'罺','𦌾'=>'𦌾','羕'=>'羕','翺'=>'翺','者'=>'者','𦓚'=>'𦓚','𦔣'=>'𦔣','聠'=>'聠','𦖨'=>'𦖨','聰'=>'聰','𣍟'=>'𣍟','䏕'=>'䏕','育'=>'育','脃'=>'脃','䐋'=>'䐋','脾'=>'脾','媵'=>'媵','𦞧'=>'𦞧','𦞵'=>'𦞵','𣎓'=>'𣎓','𣎜'=>'𣎜','舁'=>'舁','舄'=>'舄','辞'=>'辞','䑫'=>'䑫','芑'=>'芑','芋'=>'芋','芝'=>'芝','劳'=>'劳','花'=>'花','芳'=>'芳','芽'=>'芽','苦'=>'苦','𦬼'=>'𦬼','若'=>'若','茝'=>'茝','荣'=>'荣','莭'=>'莭','茣'=>'茣','莽'=>'莽','菧'=>'菧','著'=>'著','荓'=>'荓','菊'=>'菊','菌'=>'菌','菜'=>'菜','𦰶'=>'𦰶','𦵫'=>'𦵫','𦳕'=>'𦳕','䔫'=>'䔫','蓱'=>'蓱','蓳'=>'蓳','蔖'=>'蔖','𧏊'=>'𧏊','蕤'=>'蕤','𦼬'=>'𦼬','䕝'=>'䕝','䕡'=>'䕡','𦾱'=>'𦾱','𧃒'=>'𧃒','䕫'=>'䕫','虐'=>'虐','虜'=>'虜','虧'=>'虧','虩'=>'虩','蚩'=>'蚩','蚈'=>'蚈','蜎'=>'蜎','蛢'=>'蛢','蝹'=>'蝹','蜨'=>'蜨','蝫'=>'蝫','螆'=>'螆','䗗'=>'䗗','蟡'=>'蟡','蠁'=>'蠁','䗹'=>'䗹','衠'=>'衠','衣'=>'衣','𧙧'=>'𧙧','裗'=>'裗','裞'=>'裞','䘵'=>'䘵','裺'=>'裺','㒻'=>'㒻','𧢮'=>'𧢮','𧥦'=>'𧥦','䚾'=>'䚾','䛇'=>'䛇','誠'=>'誠','諭'=>'諭','變'=>'變','豕'=>'豕','𧲨'=>'𧲨','貫'=>'貫','賁'=>'賁','贛'=>'贛','起'=>'起','𧼯'=>'𧼯','𠠄'=>'𠠄','跋'=>'跋','趼'=>'趼','跰'=>'跰','𠣞'=>'𠣞','軔'=>'軔','輸'=>'輸','𨗒'=>'𨗒','𨗭'=>'𨗭','邔'=>'邔','郱'=>'郱','鄑'=>'鄑','𨜮'=>'𨜮','鄛'=>'鄛','鈸'=>'鈸','鋗'=>'鋗','鋘'=>'鋘','鉼'=>'鉼','鏹'=>'鏹','鐕'=>'鐕','𨯺'=>'𨯺','開'=>'開','䦕'=>'䦕','閷'=>'閷','𨵷'=>'𨵷','䧦'=>'䧦','雃'=>'雃','嶲'=>'嶲','霣'=>'霣','𩅅'=>'𩅅','𩈚'=>'𩈚','䩮'=>'䩮','䩶'=>'䩶','韠'=>'韠','𩐊'=>'𩐊','䪲'=>'䪲','𩒖'=>'𩒖','頋'=>'頋','頋'=>'頋','頩'=>'頩','𩖶'=>'𩖶','飢'=>'飢','䬳'=>'䬳','餩'=>'餩','馧'=>'馧','駂'=>'駂','駾'=>'駾','䯎'=>'䯎','𩬰'=>'𩬰','鬒'=>'鬒','鱀'=>'鱀','鳽'=>'鳽','䳎'=>'䳎','䳭'=>'䳭','鵧'=>'鵧','𪃎'=>'𪃎','䳸'=>'䳸','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','麻'=>'麻','䵖'=>'䵖','黹'=>'黹','黾'=>'黾','鼅'=>'鼅','鼏'=>'鼏','鼖'=>'鼖','鼻'=>'鼻','𪘀'=>'𪘀'); diff --git a/phpBB/includes/utf/data/utf_compatibility_decomp.php b/phpBB/includes/utf/data/utf_compatibility_decomp.php index 08a7a047a4..c62948e81a 100644 --- a/phpBB/includes/utf/data/utf_compatibility_decomp.php +++ b/phpBB/includes/utf/data/utf_compatibility_decomp.php @@ -1,2 +1,2 @@ <?php -$GLOBALS['utf_compatibility_decomp']=array(' '=>' ','¨'=>' ̈','ª'=>'a','¯'=>' ̄','²'=>'2','³'=>'3','´'=>' ́','µ'=>'μ','¸'=>' ̧','¹'=>'1','º'=>'o','¼'=>'1⁄4','½'=>'1⁄2','¾'=>'3⁄4','À'=>'À','Á'=>'Á','Â'=>'Â','Ã'=>'Ã','Ä'=>'Ä','Å'=>'Å','Ç'=>'Ç','È'=>'È','É'=>'É','Ê'=>'Ê','Ë'=>'Ë','Ì'=>'Ì','Í'=>'Í','Î'=>'Î','Ï'=>'Ï','Ñ'=>'Ñ','Ò'=>'Ò','Ó'=>'Ó','Ô'=>'Ô','Õ'=>'Õ','Ö'=>'Ö','Ù'=>'Ù','Ú'=>'Ú','Û'=>'Û','Ü'=>'Ü','Ý'=>'Ý','à'=>'à','á'=>'á','â'=>'â','ã'=>'ã','ä'=>'ä','å'=>'å','ç'=>'ç','è'=>'è','é'=>'é','ê'=>'ê','ë'=>'ë','ì'=>'ì','í'=>'í','î'=>'î','ï'=>'ï','ñ'=>'ñ','ò'=>'ò','ó'=>'ó','ô'=>'ô','õ'=>'õ','ö'=>'ö','ù'=>'ù','ú'=>'ú','û'=>'û','ü'=>'ü','ý'=>'ý','ÿ'=>'ÿ','Ā'=>'Ā','ā'=>'ā','Ă'=>'Ă','ă'=>'ă','Ą'=>'Ą','ą'=>'ą','Ć'=>'Ć','ć'=>'ć','Ĉ'=>'Ĉ','ĉ'=>'ĉ','Ċ'=>'Ċ','ċ'=>'ċ','Č'=>'Č','č'=>'č','Ď'=>'Ď','ď'=>'ď','Ē'=>'Ē','ē'=>'ē','Ĕ'=>'Ĕ','ĕ'=>'ĕ','Ė'=>'Ė','ė'=>'ė','Ę'=>'Ę','ę'=>'ę','Ě'=>'Ě','ě'=>'ě','Ĝ'=>'Ĝ','ĝ'=>'ĝ','Ğ'=>'Ğ','ğ'=>'ğ','Ġ'=>'Ġ','ġ'=>'ġ','Ģ'=>'Ģ','ģ'=>'ģ','Ĥ'=>'Ĥ','ĥ'=>'ĥ','Ĩ'=>'Ĩ','ĩ'=>'ĩ','Ī'=>'Ī','ī'=>'ī','Ĭ'=>'Ĭ','ĭ'=>'ĭ','Į'=>'Į','į'=>'į','İ'=>'İ','IJ'=>'IJ','ij'=>'ij','Ĵ'=>'Ĵ','ĵ'=>'ĵ','Ķ'=>'Ķ','ķ'=>'ķ','Ĺ'=>'Ĺ','ĺ'=>'ĺ','Ļ'=>'Ļ','ļ'=>'ļ','Ľ'=>'Ľ','ľ'=>'ľ','Ŀ'=>'L·','ŀ'=>'l·','Ń'=>'Ń','ń'=>'ń','Ņ'=>'Ņ','ņ'=>'ņ','Ň'=>'Ň','ň'=>'ň','ʼn'=>'ʼn','Ō'=>'Ō','ō'=>'ō','Ŏ'=>'Ŏ','ŏ'=>'ŏ','Ő'=>'Ő','ő'=>'ő','Ŕ'=>'Ŕ','ŕ'=>'ŕ','Ŗ'=>'Ŗ','ŗ'=>'ŗ','Ř'=>'Ř','ř'=>'ř','Ś'=>'Ś','ś'=>'ś','Ŝ'=>'Ŝ','ŝ'=>'ŝ','Ş'=>'Ş','ş'=>'ş','Š'=>'Š','š'=>'š','Ţ'=>'Ţ','ţ'=>'ţ','Ť'=>'Ť','ť'=>'ť','Ũ'=>'Ũ','ũ'=>'ũ','Ū'=>'Ū','ū'=>'ū','Ŭ'=>'Ŭ','ŭ'=>'ŭ','Ů'=>'Ů','ů'=>'ů','Ű'=>'Ű','ű'=>'ű','Ų'=>'Ų','ų'=>'ų','Ŵ'=>'Ŵ','ŵ'=>'ŵ','Ŷ'=>'Ŷ','ŷ'=>'ŷ','Ÿ'=>'Ÿ','Ź'=>'Ź','ź'=>'ź','Ż'=>'Ż','ż'=>'ż','Ž'=>'Ž','ž'=>'ž','ſ'=>'s','Ơ'=>'Ơ','ơ'=>'ơ','Ư'=>'Ư','ư'=>'ư','DŽ'=>'DŽ','Dž'=>'Dž','dž'=>'dž','LJ'=>'LJ','Lj'=>'Lj','lj'=>'lj','NJ'=>'NJ','Nj'=>'Nj','nj'=>'nj','Ǎ'=>'Ǎ','ǎ'=>'ǎ','Ǐ'=>'Ǐ','ǐ'=>'ǐ','Ǒ'=>'Ǒ','ǒ'=>'ǒ','Ǔ'=>'Ǔ','ǔ'=>'ǔ','Ǖ'=>'Ǖ','ǖ'=>'ǖ','Ǘ'=>'Ǘ','ǘ'=>'ǘ','Ǚ'=>'Ǚ','ǚ'=>'ǚ','Ǜ'=>'Ǜ','ǜ'=>'ǜ','Ǟ'=>'Ǟ','ǟ'=>'ǟ','Ǡ'=>'Ǡ','ǡ'=>'ǡ','Ǣ'=>'Ǣ','ǣ'=>'ǣ','Ǧ'=>'Ǧ','ǧ'=>'ǧ','Ǩ'=>'Ǩ','ǩ'=>'ǩ','Ǫ'=>'Ǫ','ǫ'=>'ǫ','Ǭ'=>'Ǭ','ǭ'=>'ǭ','Ǯ'=>'Ǯ','ǯ'=>'ǯ','ǰ'=>'ǰ','DZ'=>'DZ','Dz'=>'Dz','dz'=>'dz','Ǵ'=>'Ǵ','ǵ'=>'ǵ','Ǹ'=>'Ǹ','ǹ'=>'ǹ','Ǻ'=>'Ǻ','ǻ'=>'ǻ','Ǽ'=>'Ǽ','ǽ'=>'ǽ','Ǿ'=>'Ǿ','ǿ'=>'ǿ','Ȁ'=>'Ȁ','ȁ'=>'ȁ','Ȃ'=>'Ȃ','ȃ'=>'ȃ','Ȅ'=>'Ȅ','ȅ'=>'ȅ','Ȇ'=>'Ȇ','ȇ'=>'ȇ','Ȉ'=>'Ȉ','ȉ'=>'ȉ','Ȋ'=>'Ȋ','ȋ'=>'ȋ','Ȍ'=>'Ȍ','ȍ'=>'ȍ','Ȏ'=>'Ȏ','ȏ'=>'ȏ','Ȑ'=>'Ȑ','ȑ'=>'ȑ','Ȓ'=>'Ȓ','ȓ'=>'ȓ','Ȕ'=>'Ȕ','ȕ'=>'ȕ','Ȗ'=>'Ȗ','ȗ'=>'ȗ','Ș'=>'Ș','ș'=>'ș','Ț'=>'Ț','ț'=>'ț','Ȟ'=>'Ȟ','ȟ'=>'ȟ','Ȧ'=>'Ȧ','ȧ'=>'ȧ','Ȩ'=>'Ȩ','ȩ'=>'ȩ','Ȫ'=>'Ȫ','ȫ'=>'ȫ','Ȭ'=>'Ȭ','ȭ'=>'ȭ','Ȯ'=>'Ȯ','ȯ'=>'ȯ','Ȱ'=>'Ȱ','ȱ'=>'ȱ','Ȳ'=>'Ȳ','ȳ'=>'ȳ','ʰ'=>'h','ʱ'=>'ɦ','ʲ'=>'j','ʳ'=>'r','ʴ'=>'ɹ','ʵ'=>'ɻ','ʶ'=>'ʁ','ʷ'=>'w','ʸ'=>'y','˘'=>' ̆','˙'=>' ̇','˚'=>' ̊','˛'=>' ̨','˜'=>' ̃','˝'=>' ̋','ˠ'=>'ɣ','ˡ'=>'l','ˢ'=>'s','ˣ'=>'x','ˤ'=>'ʕ','̀'=>'̀','́'=>'́','̓'=>'̓','̈́'=>'̈́','ʹ'=>'ʹ','ͺ'=>' ͅ',';'=>';','΄'=>' ́','΅'=>' ̈́','Ά'=>'Ά','·'=>'·','Έ'=>'Έ','Ή'=>'Ή','Ί'=>'Ί','Ό'=>'Ό','Ύ'=>'Ύ','Ώ'=>'Ώ','ΐ'=>'ΐ','Ϊ'=>'Ϊ','Ϋ'=>'Ϋ','ά'=>'ά','έ'=>'έ','ή'=>'ή','ί'=>'ί','ΰ'=>'ΰ','ϊ'=>'ϊ','ϋ'=>'ϋ','ό'=>'ό','ύ'=>'ύ','ώ'=>'ώ','ϐ'=>'β','ϑ'=>'θ','ϒ'=>'Υ','ϓ'=>'Ύ','ϔ'=>'Ϋ','ϕ'=>'φ','ϖ'=>'π','ϰ'=>'κ','ϱ'=>'ρ','ϲ'=>'ς','ϴ'=>'Θ','ϵ'=>'ε','Ϲ'=>'Σ','Ѐ'=>'Ѐ','Ё'=>'Ё','Ѓ'=>'Ѓ','Ї'=>'Ї','Ќ'=>'Ќ','Ѝ'=>'Ѝ','Ў'=>'Ў','Й'=>'Й','й'=>'й','ѐ'=>'ѐ','ё'=>'ё','ѓ'=>'ѓ','ї'=>'ї','ќ'=>'ќ','ѝ'=>'ѝ','ў'=>'ў','Ѷ'=>'Ѷ','ѷ'=>'ѷ','Ӂ'=>'Ӂ','ӂ'=>'ӂ','Ӑ'=>'Ӑ','ӑ'=>'ӑ','Ӓ'=>'Ӓ','ӓ'=>'ӓ','Ӗ'=>'Ӗ','ӗ'=>'ӗ','Ӛ'=>'Ӛ','ӛ'=>'ӛ','Ӝ'=>'Ӝ','ӝ'=>'ӝ','Ӟ'=>'Ӟ','ӟ'=>'ӟ','Ӣ'=>'Ӣ','ӣ'=>'ӣ','Ӥ'=>'Ӥ','ӥ'=>'ӥ','Ӧ'=>'Ӧ','ӧ'=>'ӧ','Ӫ'=>'Ӫ','ӫ'=>'ӫ','Ӭ'=>'Ӭ','ӭ'=>'ӭ','Ӯ'=>'Ӯ','ӯ'=>'ӯ','Ӱ'=>'Ӱ','ӱ'=>'ӱ','Ӳ'=>'Ӳ','ӳ'=>'ӳ','Ӵ'=>'Ӵ','ӵ'=>'ӵ','Ӹ'=>'Ӹ','ӹ'=>'ӹ','և'=>'եւ','آ'=>'آ','أ'=>'أ','ؤ'=>'ؤ','إ'=>'إ','ئ'=>'ئ','ٵ'=>'اٴ','ٶ'=>'وٴ','ٷ'=>'ۇٴ','ٸ'=>'يٴ','ۀ'=>'ۀ','ۂ'=>'ۂ','ۓ'=>'ۓ','ऩ'=>'ऩ','ऱ'=>'ऱ','ऴ'=>'ऴ','क़'=>'क़','ख़'=>'ख़','ग़'=>'ग़','ज़'=>'ज़','ड़'=>'ड़','ढ़'=>'ढ़','फ़'=>'फ़','य़'=>'य़','ো'=>'ো','ৌ'=>'ৌ','ড়'=>'ড়','ঢ়'=>'ঢ়','য়'=>'য়','ਲ਼'=>'ਲ਼','ਸ਼'=>'ਸ਼','ਖ਼'=>'ਖ਼','ਗ਼'=>'ਗ਼','ਜ਼'=>'ਜ਼','ਫ਼'=>'ਫ਼','ୈ'=>'ୈ','ୋ'=>'ୋ','ୌ'=>'ୌ','ଡ଼'=>'ଡ଼','ଢ଼'=>'ଢ଼','ஔ'=>'ஔ','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','ై'=>'ై','ೀ'=>'ೀ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','ේ'=>'ේ','ො'=>'ො','ෝ'=>'ෝ','ෞ'=>'ෞ','ำ'=>'ํา','ຳ'=>'ໍາ','ໜ'=>'ຫນ','ໝ'=>'ຫມ','༌'=>'་','གྷ'=>'གྷ','ཌྷ'=>'ཌྷ','དྷ'=>'དྷ','བྷ'=>'བྷ','ཛྷ'=>'ཛྷ','ཀྵ'=>'ཀྵ','ཱི'=>'ཱི','ཱུ'=>'ཱུ','ྲྀ'=>'ྲྀ','ཷ'=>'ྲཱྀ','ླྀ'=>'ླྀ','ཹ'=>'ླཱྀ','ཱྀ'=>'ཱྀ','ྒྷ'=>'ྒྷ','ྜྷ'=>'ྜྷ','ྡྷ'=>'ྡྷ','ྦྷ'=>'ྦྷ','ྫྷ'=>'ྫྷ','ྐྵ'=>'ྐྵ','ဦ'=>'ဦ','ჼ'=>'ნ','ᬆ'=>'ᬆ','ᬈ'=>'ᬈ','ᬊ'=>'ᬊ','ᬌ'=>'ᬌ','ᬎ'=>'ᬎ','ᬒ'=>'ᬒ','ᬻ'=>'ᬻ','ᬽ'=>'ᬽ','ᭀ'=>'ᭀ','ᭁ'=>'ᭁ','ᭃ'=>'ᭃ','ᴬ'=>'A','ᴭ'=>'Æ','ᴮ'=>'B','ᴰ'=>'D','ᴱ'=>'E','ᴲ'=>'Ǝ','ᴳ'=>'G','ᴴ'=>'H','ᴵ'=>'I','ᴶ'=>'J','ᴷ'=>'K','ᴸ'=>'L','ᴹ'=>'M','ᴺ'=>'N','ᴼ'=>'O','ᴽ'=>'Ȣ','ᴾ'=>'P','ᴿ'=>'R','ᵀ'=>'T','ᵁ'=>'U','ᵂ'=>'W','ᵃ'=>'a','ᵄ'=>'ɐ','ᵅ'=>'ɑ','ᵆ'=>'ᴂ','ᵇ'=>'b','ᵈ'=>'d','ᵉ'=>'e','ᵊ'=>'ə','ᵋ'=>'ɛ','ᵌ'=>'ɜ','ᵍ'=>'g','ᵏ'=>'k','ᵐ'=>'m','ᵑ'=>'ŋ','ᵒ'=>'o','ᵓ'=>'ɔ','ᵔ'=>'ᴖ','ᵕ'=>'ᴗ','ᵖ'=>'p','ᵗ'=>'t','ᵘ'=>'u','ᵙ'=>'ᴝ','ᵚ'=>'ɯ','ᵛ'=>'v','ᵜ'=>'ᴥ','ᵝ'=>'β','ᵞ'=>'γ','ᵟ'=>'δ','ᵠ'=>'φ','ᵡ'=>'χ','ᵢ'=>'i','ᵣ'=>'r','ᵤ'=>'u','ᵥ'=>'v','ᵦ'=>'β','ᵧ'=>'γ','ᵨ'=>'ρ','ᵩ'=>'φ','ᵪ'=>'χ','ᵸ'=>'н','ᶛ'=>'ɒ','ᶜ'=>'c','ᶝ'=>'ɕ','ᶞ'=>'ð','ᶟ'=>'ɜ','ᶠ'=>'f','ᶡ'=>'ɟ','ᶢ'=>'ɡ','ᶣ'=>'ɥ','ᶤ'=>'ɨ','ᶥ'=>'ɩ','ᶦ'=>'ɪ','ᶧ'=>'ᵻ','ᶨ'=>'ʝ','ᶩ'=>'ɭ','ᶪ'=>'ᶅ','ᶫ'=>'ʟ','ᶬ'=>'ɱ','ᶭ'=>'ɰ','ᶮ'=>'ɲ','ᶯ'=>'ɳ','ᶰ'=>'ɴ','ᶱ'=>'ɵ','ᶲ'=>'ɸ','ᶳ'=>'ʂ','ᶴ'=>'ʃ','ᶵ'=>'ƫ','ᶶ'=>'ʉ','ᶷ'=>'ʊ','ᶸ'=>'ᴜ','ᶹ'=>'ʋ','ᶺ'=>'ʌ','ᶻ'=>'z','ᶼ'=>'ʐ','ᶽ'=>'ʑ','ᶾ'=>'ʒ','ᶿ'=>'θ','Ḁ'=>'Ḁ','ḁ'=>'ḁ','Ḃ'=>'Ḃ','ḃ'=>'ḃ','Ḅ'=>'Ḅ','ḅ'=>'ḅ','Ḇ'=>'Ḇ','ḇ'=>'ḇ','Ḉ'=>'Ḉ','ḉ'=>'ḉ','Ḋ'=>'Ḋ','ḋ'=>'ḋ','Ḍ'=>'Ḍ','ḍ'=>'ḍ','Ḏ'=>'Ḏ','ḏ'=>'ḏ','Ḑ'=>'Ḑ','ḑ'=>'ḑ','Ḓ'=>'Ḓ','ḓ'=>'ḓ','Ḕ'=>'Ḕ','ḕ'=>'ḕ','Ḗ'=>'Ḗ','ḗ'=>'ḗ','Ḙ'=>'Ḙ','ḙ'=>'ḙ','Ḛ'=>'Ḛ','ḛ'=>'ḛ','Ḝ'=>'Ḝ','ḝ'=>'ḝ','Ḟ'=>'Ḟ','ḟ'=>'ḟ','Ḡ'=>'Ḡ','ḡ'=>'ḡ','Ḣ'=>'Ḣ','ḣ'=>'ḣ','Ḥ'=>'Ḥ','ḥ'=>'ḥ','Ḧ'=>'Ḧ','ḧ'=>'ḧ','Ḩ'=>'Ḩ','ḩ'=>'ḩ','Ḫ'=>'Ḫ','ḫ'=>'ḫ','Ḭ'=>'Ḭ','ḭ'=>'ḭ','Ḯ'=>'Ḯ','ḯ'=>'ḯ','Ḱ'=>'Ḱ','ḱ'=>'ḱ','Ḳ'=>'Ḳ','ḳ'=>'ḳ','Ḵ'=>'Ḵ','ḵ'=>'ḵ','Ḷ'=>'Ḷ','ḷ'=>'ḷ','Ḹ'=>'Ḹ','ḹ'=>'ḹ','Ḻ'=>'Ḻ','ḻ'=>'ḻ','Ḽ'=>'Ḽ','ḽ'=>'ḽ','Ḿ'=>'Ḿ','ḿ'=>'ḿ','Ṁ'=>'Ṁ','ṁ'=>'ṁ','Ṃ'=>'Ṃ','ṃ'=>'ṃ','Ṅ'=>'Ṅ','ṅ'=>'ṅ','Ṇ'=>'Ṇ','ṇ'=>'ṇ','Ṉ'=>'Ṉ','ṉ'=>'ṉ','Ṋ'=>'Ṋ','ṋ'=>'ṋ','Ṍ'=>'Ṍ','ṍ'=>'ṍ','Ṏ'=>'Ṏ','ṏ'=>'ṏ','Ṑ'=>'Ṑ','ṑ'=>'ṑ','Ṓ'=>'Ṓ','ṓ'=>'ṓ','Ṕ'=>'Ṕ','ṕ'=>'ṕ','Ṗ'=>'Ṗ','ṗ'=>'ṗ','Ṙ'=>'Ṙ','ṙ'=>'ṙ','Ṛ'=>'Ṛ','ṛ'=>'ṛ','Ṝ'=>'Ṝ','ṝ'=>'ṝ','Ṟ'=>'Ṟ','ṟ'=>'ṟ','Ṡ'=>'Ṡ','ṡ'=>'ṡ','Ṣ'=>'Ṣ','ṣ'=>'ṣ','Ṥ'=>'Ṥ','ṥ'=>'ṥ','Ṧ'=>'Ṧ','ṧ'=>'ṧ','Ṩ'=>'Ṩ','ṩ'=>'ṩ','Ṫ'=>'Ṫ','ṫ'=>'ṫ','Ṭ'=>'Ṭ','ṭ'=>'ṭ','Ṯ'=>'Ṯ','ṯ'=>'ṯ','Ṱ'=>'Ṱ','ṱ'=>'ṱ','Ṳ'=>'Ṳ','ṳ'=>'ṳ','Ṵ'=>'Ṵ','ṵ'=>'ṵ','Ṷ'=>'Ṷ','ṷ'=>'ṷ','Ṹ'=>'Ṹ','ṹ'=>'ṹ','Ṻ'=>'Ṻ','ṻ'=>'ṻ','Ṽ'=>'Ṽ','ṽ'=>'ṽ','Ṿ'=>'Ṿ','ṿ'=>'ṿ','Ẁ'=>'Ẁ','ẁ'=>'ẁ','Ẃ'=>'Ẃ','ẃ'=>'ẃ','Ẅ'=>'Ẅ','ẅ'=>'ẅ','Ẇ'=>'Ẇ','ẇ'=>'ẇ','Ẉ'=>'Ẉ','ẉ'=>'ẉ','Ẋ'=>'Ẋ','ẋ'=>'ẋ','Ẍ'=>'Ẍ','ẍ'=>'ẍ','Ẏ'=>'Ẏ','ẏ'=>'ẏ','Ẑ'=>'Ẑ','ẑ'=>'ẑ','Ẓ'=>'Ẓ','ẓ'=>'ẓ','Ẕ'=>'Ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẚ'=>'aʾ','ẛ'=>'ṡ','Ạ'=>'Ạ','ạ'=>'ạ','Ả'=>'Ả','ả'=>'ả','Ấ'=>'Ấ','ấ'=>'ấ','Ầ'=>'Ầ','ầ'=>'ầ','Ẩ'=>'Ẩ','ẩ'=>'ẩ','Ẫ'=>'Ẫ','ẫ'=>'ẫ','Ậ'=>'Ậ','ậ'=>'ậ','Ắ'=>'Ắ','ắ'=>'ắ','Ằ'=>'Ằ','ằ'=>'ằ','Ẳ'=>'Ẳ','ẳ'=>'ẳ','Ẵ'=>'Ẵ','ẵ'=>'ẵ','Ặ'=>'Ặ','ặ'=>'ặ','Ẹ'=>'Ẹ','ẹ'=>'ẹ','Ẻ'=>'Ẻ','ẻ'=>'ẻ','Ẽ'=>'Ẽ','ẽ'=>'ẽ','Ế'=>'Ế','ế'=>'ế','Ề'=>'Ề','ề'=>'ề','Ể'=>'Ể','ể'=>'ể','Ễ'=>'Ễ','ễ'=>'ễ','Ệ'=>'Ệ','ệ'=>'ệ','Ỉ'=>'Ỉ','ỉ'=>'ỉ','Ị'=>'Ị','ị'=>'ị','Ọ'=>'Ọ','ọ'=>'ọ','Ỏ'=>'Ỏ','ỏ'=>'ỏ','Ố'=>'Ố','ố'=>'ố','Ồ'=>'Ồ','ồ'=>'ồ','Ổ'=>'Ổ','ổ'=>'ổ','Ỗ'=>'Ỗ','ỗ'=>'ỗ','Ộ'=>'Ộ','ộ'=>'ộ','Ớ'=>'Ớ','ớ'=>'ớ','Ờ'=>'Ờ','ờ'=>'ờ','Ở'=>'Ở','ở'=>'ở','Ỡ'=>'Ỡ','ỡ'=>'ỡ','Ợ'=>'Ợ','ợ'=>'ợ','Ụ'=>'Ụ','ụ'=>'ụ','Ủ'=>'Ủ','ủ'=>'ủ','Ứ'=>'Ứ','ứ'=>'ứ','Ừ'=>'Ừ','ừ'=>'ừ','Ử'=>'Ử','ử'=>'ử','Ữ'=>'Ữ','ữ'=>'ữ','Ự'=>'Ự','ự'=>'ự','Ỳ'=>'Ỳ','ỳ'=>'ỳ','Ỵ'=>'Ỵ','ỵ'=>'ỵ','Ỷ'=>'Ỷ','ỷ'=>'ỷ','Ỹ'=>'Ỹ','ỹ'=>'ỹ','ἀ'=>'ἀ','ἁ'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἄ','ἅ'=>'ἅ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'Ἀ','Ἁ'=>'Ἁ','Ἂ'=>'Ἂ','Ἃ'=>'Ἃ','Ἄ'=>'Ἄ','Ἅ'=>'Ἅ','Ἆ'=>'Ἆ','Ἇ'=>'Ἇ','ἐ'=>'ἐ','ἑ'=>'ἑ','ἒ'=>'ἒ','ἓ'=>'ἓ','ἔ'=>'ἔ','ἕ'=>'ἕ','Ἐ'=>'Ἐ','Ἑ'=>'Ἑ','Ἒ'=>'Ἒ','Ἓ'=>'Ἓ','Ἔ'=>'Ἔ','Ἕ'=>'Ἕ','ἠ'=>'ἠ','ἡ'=>'ἡ','ἢ'=>'ἢ','ἣ'=>'ἣ','ἤ'=>'ἤ','ἥ'=>'ἥ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'Ἠ','Ἡ'=>'Ἡ','Ἢ'=>'Ἢ','Ἣ'=>'Ἣ','Ἤ'=>'Ἤ','Ἥ'=>'Ἥ','Ἦ'=>'Ἦ','Ἧ'=>'Ἧ','ἰ'=>'ἰ','ἱ'=>'ἱ','ἲ'=>'ἲ','ἳ'=>'ἳ','ἴ'=>'ἴ','ἵ'=>'ἵ','ἶ'=>'ἶ','ἷ'=>'ἷ','Ἰ'=>'Ἰ','Ἱ'=>'Ἱ','Ἲ'=>'Ἲ','Ἳ'=>'Ἳ','Ἴ'=>'Ἴ','Ἵ'=>'Ἵ','Ἶ'=>'Ἶ','Ἷ'=>'Ἷ','ὀ'=>'ὀ','ὁ'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὄ','ὅ'=>'ὅ','Ὀ'=>'Ὀ','Ὁ'=>'Ὁ','Ὂ'=>'Ὂ','Ὃ'=>'Ὃ','Ὄ'=>'Ὄ','Ὅ'=>'Ὅ','ὐ'=>'ὐ','ὑ'=>'ὑ','ὒ'=>'ὒ','ὓ'=>'ὓ','ὔ'=>'ὔ','ὕ'=>'ὕ','ὖ'=>'ὖ','ὗ'=>'ὗ','Ὑ'=>'Ὑ','Ὓ'=>'Ὓ','Ὕ'=>'Ὕ','Ὗ'=>'Ὗ','ὠ'=>'ὠ','ὡ'=>'ὡ','ὢ'=>'ὢ','ὣ'=>'ὣ','ὤ'=>'ὤ','ὥ'=>'ὥ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'Ὠ','Ὡ'=>'Ὡ','Ὢ'=>'Ὢ','Ὣ'=>'Ὣ','Ὤ'=>'Ὤ','Ὥ'=>'Ὥ','Ὦ'=>'Ὦ','Ὧ'=>'Ὧ','ὰ'=>'ὰ','ά'=>'ά','ὲ'=>'ὲ','έ'=>'έ','ὴ'=>'ὴ','ή'=>'ή','ὶ'=>'ὶ','ί'=>'ί','ὸ'=>'ὸ','ό'=>'ό','ὺ'=>'ὺ','ύ'=>'ύ','ὼ'=>'ὼ','ώ'=>'ώ','ᾀ'=>'ᾀ','ᾁ'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ᾄ','ᾅ'=>'ᾅ','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾈ','ᾉ'=>'ᾉ','ᾊ'=>'ᾊ','ᾋ'=>'ᾋ','ᾌ'=>'ᾌ','ᾍ'=>'ᾍ','ᾎ'=>'ᾎ','ᾏ'=>'ᾏ','ᾐ'=>'ᾐ','ᾑ'=>'ᾑ','ᾒ'=>'ᾒ','ᾓ'=>'ᾓ','ᾔ'=>'ᾔ','ᾕ'=>'ᾕ','ᾖ'=>'ᾖ','ᾗ'=>'ᾗ','ᾘ'=>'ᾘ','ᾙ'=>'ᾙ','ᾚ'=>'ᾚ','ᾛ'=>'ᾛ','ᾜ'=>'ᾜ','ᾝ'=>'ᾝ','ᾞ'=>'ᾞ','ᾟ'=>'ᾟ','ᾠ'=>'ᾠ','ᾡ'=>'ᾡ','ᾢ'=>'ᾢ','ᾣ'=>'ᾣ','ᾤ'=>'ᾤ','ᾥ'=>'ᾥ','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾨ','ᾩ'=>'ᾩ','ᾪ'=>'ᾪ','ᾫ'=>'ᾫ','ᾬ'=>'ᾬ','ᾭ'=>'ᾭ','ᾮ'=>'ᾮ','ᾯ'=>'ᾯ','ᾰ'=>'ᾰ','ᾱ'=>'ᾱ','ᾲ'=>'ᾲ','ᾳ'=>'ᾳ','ᾴ'=>'ᾴ','ᾶ'=>'ᾶ','ᾷ'=>'ᾷ','Ᾰ'=>'Ᾰ','Ᾱ'=>'Ᾱ','Ὰ'=>'Ὰ','Ά'=>'Ά','ᾼ'=>'ᾼ','᾽'=>' ̓','ι'=>'ι','᾿'=>' ̓','῀'=>' ͂','῁'=>' ̈͂','ῂ'=>'ῂ','ῃ'=>'ῃ','ῄ'=>'ῄ','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'Ὲ','Έ'=>'Έ','Ὴ'=>'Ὴ','Ή'=>'Ή','ῌ'=>'ῌ','῍'=>' ̓̀','῎'=>' ̓́','῏'=>' ̓͂','ῐ'=>'ῐ','ῑ'=>'ῑ','ῒ'=>'ῒ','ΐ'=>'ΐ','ῖ'=>'ῖ','ῗ'=>'ῗ','Ῐ'=>'Ῐ','Ῑ'=>'Ῑ','Ὶ'=>'Ὶ','Ί'=>'Ί','῝'=>' ̔̀','῞'=>' ̔́','῟'=>' ̔͂','ῠ'=>'ῠ','ῡ'=>'ῡ','ῢ'=>'ῢ','ΰ'=>'ΰ','ῤ'=>'ῤ','ῥ'=>'ῥ','ῦ'=>'ῦ','ῧ'=>'ῧ','Ῠ'=>'Ῠ','Ῡ'=>'Ῡ','Ὺ'=>'Ὺ','Ύ'=>'Ύ','Ῥ'=>'Ῥ','῭'=>' ̈̀','΅'=>' ̈́','`'=>'`','ῲ'=>'ῲ','ῳ'=>'ῳ','ῴ'=>'ῴ','ῶ'=>'ῶ','ῷ'=>'ῷ','Ὸ'=>'Ὸ','Ό'=>'Ό','Ὼ'=>'Ὼ','Ώ'=>'Ώ','ῼ'=>'ῼ','´'=>' ́','῾'=>' ̔',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ','‑'=>'‐','‗'=>' ̳','․'=>'.','‥'=>'..','…'=>'...',' '=>' ','″'=>'′′','‴'=>'′′′','‶'=>'‵‵','‷'=>'‵‵‵','‼'=>'!!','‾'=>' ̅','⁇'=>'??','⁈'=>'?!','⁉'=>'!?','⁗'=>'′′′′',' '=>' ','⁰'=>'0','ⁱ'=>'i','⁴'=>'4','⁵'=>'5','⁶'=>'6','⁷'=>'7','⁸'=>'8','⁹'=>'9','⁺'=>'+','⁻'=>'−','⁼'=>'=','⁽'=>'(','⁾'=>')','ⁿ'=>'n','₀'=>'0','₁'=>'1','₂'=>'2','₃'=>'3','₄'=>'4','₅'=>'5','₆'=>'6','₇'=>'7','₈'=>'8','₉'=>'9','₊'=>'+','₋'=>'−','₌'=>'=','₍'=>'(','₎'=>')','ₐ'=>'a','ₑ'=>'e','ₒ'=>'o','ₓ'=>'x','ₔ'=>'ə','₨'=>'Rs','℀'=>'a/c','℁'=>'a/s','ℂ'=>'C','℃'=>'°C','℅'=>'c/o','℆'=>'c/u','ℇ'=>'Ɛ','℉'=>'°F','ℊ'=>'g','ℋ'=>'H','ℌ'=>'H','ℍ'=>'H','ℎ'=>'h','ℏ'=>'ħ','ℐ'=>'I','ℑ'=>'I','ℒ'=>'L','ℓ'=>'l','ℕ'=>'N','№'=>'No','ℙ'=>'P','ℚ'=>'Q','ℛ'=>'R','ℜ'=>'R','ℝ'=>'R','℠'=>'SM','℡'=>'TEL','™'=>'TM','ℤ'=>'Z','Ω'=>'Ω','ℨ'=>'Z','K'=>'K','Å'=>'Å','ℬ'=>'B','ℭ'=>'C','ℯ'=>'e','ℰ'=>'E','ℱ'=>'F','ℳ'=>'M','ℴ'=>'o','ℵ'=>'א','ℶ'=>'ב','ℷ'=>'ג','ℸ'=>'ד','ℹ'=>'i','℻'=>'FAX','ℼ'=>'π','ℽ'=>'γ','ℾ'=>'Γ','ℿ'=>'Π','⅀'=>'∑','ⅅ'=>'D','ⅆ'=>'d','ⅇ'=>'e','ⅈ'=>'i','ⅉ'=>'j','⅓'=>'1⁄3','⅔'=>'2⁄3','⅕'=>'1⁄5','⅖'=>'2⁄5','⅗'=>'3⁄5','⅘'=>'4⁄5','⅙'=>'1⁄6','⅚'=>'5⁄6','⅛'=>'1⁄8','⅜'=>'3⁄8','⅝'=>'5⁄8','⅞'=>'7⁄8','⅟'=>'1⁄','Ⅰ'=>'I','Ⅱ'=>'II','Ⅲ'=>'III','Ⅳ'=>'IV','Ⅴ'=>'V','Ⅵ'=>'VI','Ⅶ'=>'VII','Ⅷ'=>'VIII','Ⅸ'=>'IX','Ⅹ'=>'X','Ⅺ'=>'XI','Ⅻ'=>'XII','Ⅼ'=>'L','Ⅽ'=>'C','Ⅾ'=>'D','Ⅿ'=>'M','ⅰ'=>'i','ⅱ'=>'ii','ⅲ'=>'iii','ⅳ'=>'iv','ⅴ'=>'v','ⅵ'=>'vi','ⅶ'=>'vii','ⅷ'=>'viii','ⅸ'=>'ix','ⅹ'=>'x','ⅺ'=>'xi','ⅻ'=>'xii','ⅼ'=>'l','ⅽ'=>'c','ⅾ'=>'d','ⅿ'=>'m','↚'=>'↚','↛'=>'↛','↮'=>'↮','⇍'=>'⇍','⇎'=>'⇎','⇏'=>'⇏','∄'=>'∄','∉'=>'∉','∌'=>'∌','∤'=>'∤','∦'=>'∦','∬'=>'∫∫','∭'=>'∫∫∫','∯'=>'∮∮','∰'=>'∮∮∮','≁'=>'≁','≄'=>'≄','≇'=>'≇','≉'=>'≉','≠'=>'≠','≢'=>'≢','≭'=>'≭','≮'=>'≮','≯'=>'≯','≰'=>'≰','≱'=>'≱','≴'=>'≴','≵'=>'≵','≸'=>'≸','≹'=>'≹','⊀'=>'⊀','⊁'=>'⊁','⊄'=>'⊄','⊅'=>'⊅','⊈'=>'⊈','⊉'=>'⊉','⊬'=>'⊬','⊭'=>'⊭','⊮'=>'⊮','⊯'=>'⊯','⋠'=>'⋠','⋡'=>'⋡','⋢'=>'⋢','⋣'=>'⋣','⋪'=>'⋪','⋫'=>'⋫','⋬'=>'⋬','⋭'=>'⋭','〈'=>'〈','〉'=>'〉','①'=>'1','②'=>'2','③'=>'3','④'=>'4','⑤'=>'5','⑥'=>'6','⑦'=>'7','⑧'=>'8','⑨'=>'9','⑩'=>'10','⑪'=>'11','⑫'=>'12','⑬'=>'13','⑭'=>'14','⑮'=>'15','⑯'=>'16','⑰'=>'17','⑱'=>'18','⑲'=>'19','⑳'=>'20','⑴'=>'(1)','⑵'=>'(2)','⑶'=>'(3)','⑷'=>'(4)','⑸'=>'(5)','⑹'=>'(6)','⑺'=>'(7)','⑻'=>'(8)','⑼'=>'(9)','⑽'=>'(10)','⑾'=>'(11)','⑿'=>'(12)','⒀'=>'(13)','⒁'=>'(14)','⒂'=>'(15)','⒃'=>'(16)','⒄'=>'(17)','⒅'=>'(18)','⒆'=>'(19)','⒇'=>'(20)','⒈'=>'1.','⒉'=>'2.','⒊'=>'3.','⒋'=>'4.','⒌'=>'5.','⒍'=>'6.','⒎'=>'7.','⒏'=>'8.','⒐'=>'9.','⒑'=>'10.','⒒'=>'11.','⒓'=>'12.','⒔'=>'13.','⒕'=>'14.','⒖'=>'15.','⒗'=>'16.','⒘'=>'17.','⒙'=>'18.','⒚'=>'19.','⒛'=>'20.','⒜'=>'(a)','⒝'=>'(b)','⒞'=>'(c)','⒟'=>'(d)','⒠'=>'(e)','⒡'=>'(f)','⒢'=>'(g)','⒣'=>'(h)','⒤'=>'(i)','⒥'=>'(j)','⒦'=>'(k)','⒧'=>'(l)','⒨'=>'(m)','⒩'=>'(n)','⒪'=>'(o)','⒫'=>'(p)','⒬'=>'(q)','⒭'=>'(r)','⒮'=>'(s)','⒯'=>'(t)','⒰'=>'(u)','⒱'=>'(v)','⒲'=>'(w)','⒳'=>'(x)','⒴'=>'(y)','⒵'=>'(z)','Ⓐ'=>'A','Ⓑ'=>'B','Ⓒ'=>'C','Ⓓ'=>'D','Ⓔ'=>'E','Ⓕ'=>'F','Ⓖ'=>'G','Ⓗ'=>'H','Ⓘ'=>'I','Ⓙ'=>'J','Ⓚ'=>'K','Ⓛ'=>'L','Ⓜ'=>'M','Ⓝ'=>'N','Ⓞ'=>'O','Ⓟ'=>'P','Ⓠ'=>'Q','Ⓡ'=>'R','Ⓢ'=>'S','Ⓣ'=>'T','Ⓤ'=>'U','Ⓥ'=>'V','Ⓦ'=>'W','Ⓧ'=>'X','Ⓨ'=>'Y','Ⓩ'=>'Z','ⓐ'=>'a','ⓑ'=>'b','ⓒ'=>'c','ⓓ'=>'d','ⓔ'=>'e','ⓕ'=>'f','ⓖ'=>'g','ⓗ'=>'h','ⓘ'=>'i','ⓙ'=>'j','ⓚ'=>'k','ⓛ'=>'l','ⓜ'=>'m','ⓝ'=>'n','ⓞ'=>'o','ⓟ'=>'p','ⓠ'=>'q','ⓡ'=>'r','ⓢ'=>'s','ⓣ'=>'t','ⓤ'=>'u','ⓥ'=>'v','ⓦ'=>'w','ⓧ'=>'x','ⓨ'=>'y','ⓩ'=>'z','⓪'=>'0','⨌'=>'∫∫∫∫','⩴'=>'::=','⩵'=>'==','⩶'=>'===','⫝̸'=>'⫝̸','ⵯ'=>'ⵡ','⺟'=>'母','⻳'=>'龟','⼀'=>'一','⼁'=>'丨','⼂'=>'丶','⼃'=>'丿','⼄'=>'乙','⼅'=>'亅','⼆'=>'二','⼇'=>'亠','⼈'=>'人','⼉'=>'儿','⼊'=>'入','⼋'=>'八','⼌'=>'冂','⼍'=>'冖','⼎'=>'冫','⼏'=>'几','⼐'=>'凵','⼑'=>'刀','⼒'=>'力','⼓'=>'勹','⼔'=>'匕','⼕'=>'匚','⼖'=>'匸','⼗'=>'十','⼘'=>'卜','⼙'=>'卩','⼚'=>'厂','⼛'=>'厶','⼜'=>'又','⼝'=>'口','⼞'=>'囗','⼟'=>'土','⼠'=>'士','⼡'=>'夂','⼢'=>'夊','⼣'=>'夕','⼤'=>'大','⼥'=>'女','⼦'=>'子','⼧'=>'宀','⼨'=>'寸','⼩'=>'小','⼪'=>'尢','⼫'=>'尸','⼬'=>'屮','⼭'=>'山','⼮'=>'巛','⼯'=>'工','⼰'=>'己','⼱'=>'巾','⼲'=>'干','⼳'=>'幺','⼴'=>'广','⼵'=>'廴','⼶'=>'廾','⼷'=>'弋','⼸'=>'弓','⼹'=>'彐','⼺'=>'彡','⼻'=>'彳','⼼'=>'心','⼽'=>'戈','⼾'=>'戶','⼿'=>'手','⽀'=>'支','⽁'=>'攴','⽂'=>'文','⽃'=>'斗','⽄'=>'斤','⽅'=>'方','⽆'=>'无','⽇'=>'日','⽈'=>'曰','⽉'=>'月','⽊'=>'木','⽋'=>'欠','⽌'=>'止','⽍'=>'歹','⽎'=>'殳','⽏'=>'毋','⽐'=>'比','⽑'=>'毛','⽒'=>'氏','⽓'=>'气','⽔'=>'水','⽕'=>'火','⽖'=>'爪','⽗'=>'父','⽘'=>'爻','⽙'=>'爿','⽚'=>'片','⽛'=>'牙','⽜'=>'牛','⽝'=>'犬','⽞'=>'玄','⽟'=>'玉','⽠'=>'瓜','⽡'=>'瓦','⽢'=>'甘','⽣'=>'生','⽤'=>'用','⽥'=>'田','⽦'=>'疋','⽧'=>'疒','⽨'=>'癶','⽩'=>'白','⽪'=>'皮','⽫'=>'皿','⽬'=>'目','⽭'=>'矛','⽮'=>'矢','⽯'=>'石','⽰'=>'示','⽱'=>'禸','⽲'=>'禾','⽳'=>'穴','⽴'=>'立','⽵'=>'竹','⽶'=>'米','⽷'=>'糸','⽸'=>'缶','⽹'=>'网','⽺'=>'羊','⽻'=>'羽','⽼'=>'老','⽽'=>'而','⽾'=>'耒','⽿'=>'耳','⾀'=>'聿','⾁'=>'肉','⾂'=>'臣','⾃'=>'自','⾄'=>'至','⾅'=>'臼','⾆'=>'舌','⾇'=>'舛','⾈'=>'舟','⾉'=>'艮','⾊'=>'色','⾋'=>'艸','⾌'=>'虍','⾍'=>'虫','⾎'=>'血','⾏'=>'行','⾐'=>'衣','⾑'=>'襾','⾒'=>'見','⾓'=>'角','⾔'=>'言','⾕'=>'谷','⾖'=>'豆','⾗'=>'豕','⾘'=>'豸','⾙'=>'貝','⾚'=>'赤','⾛'=>'走','⾜'=>'足','⾝'=>'身','⾞'=>'車','⾟'=>'辛','⾠'=>'辰','⾡'=>'辵','⾢'=>'邑','⾣'=>'酉','⾤'=>'釆','⾥'=>'里','⾦'=>'金','⾧'=>'長','⾨'=>'門','⾩'=>'阜','⾪'=>'隶','⾫'=>'隹','⾬'=>'雨','⾭'=>'靑','⾮'=>'非','⾯'=>'面','⾰'=>'革','⾱'=>'韋','⾲'=>'韭','⾳'=>'音','⾴'=>'頁','⾵'=>'風','⾶'=>'飛','⾷'=>'食','⾸'=>'首','⾹'=>'香','⾺'=>'馬','⾻'=>'骨','⾼'=>'高','⾽'=>'髟','⾾'=>'鬥','⾿'=>'鬯','⿀'=>'鬲','⿁'=>'鬼','⿂'=>'魚','⿃'=>'鳥','⿄'=>'鹵','⿅'=>'鹿','⿆'=>'麥','⿇'=>'麻','⿈'=>'黃','⿉'=>'黍','⿊'=>'黑','⿋'=>'黹','⿌'=>'黽','⿍'=>'鼎','⿎'=>'鼓','⿏'=>'鼠','⿐'=>'鼻','⿑'=>'齊','⿒'=>'齒','⿓'=>'龍','⿔'=>'龜','⿕'=>'龠',' '=>' ','〶'=>'〒','〸'=>'十','〹'=>'卄','〺'=>'卅','が'=>'が','ぎ'=>'ぎ','ぐ'=>'ぐ','げ'=>'げ','ご'=>'ご','ざ'=>'ざ','じ'=>'じ','ず'=>'ず','ぜ'=>'ぜ','ぞ'=>'ぞ','だ'=>'だ','ぢ'=>'ぢ','づ'=>'づ','で'=>'で','ど'=>'ど','ば'=>'ば','ぱ'=>'ぱ','び'=>'び','ぴ'=>'ぴ','ぶ'=>'ぶ','ぷ'=>'ぷ','べ'=>'べ','ぺ'=>'ぺ','ぼ'=>'ぼ','ぽ'=>'ぽ','ゔ'=>'ゔ','゛'=>' ゙','゜'=>' ゚','ゞ'=>'ゞ','ゟ'=>'より','ガ'=>'ガ','ギ'=>'ギ','グ'=>'グ','ゲ'=>'ゲ','ゴ'=>'ゴ','ザ'=>'ザ','ジ'=>'ジ','ズ'=>'ズ','ゼ'=>'ゼ','ゾ'=>'ゾ','ダ'=>'ダ','ヂ'=>'ヂ','ヅ'=>'ヅ','デ'=>'デ','ド'=>'ド','バ'=>'バ','パ'=>'パ','ビ'=>'ビ','ピ'=>'ピ','ブ'=>'ブ','プ'=>'プ','ベ'=>'ベ','ペ'=>'ペ','ボ'=>'ボ','ポ'=>'ポ','ヴ'=>'ヴ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ヾ'=>'ヾ','ヿ'=>'コト','ㄱ'=>'ᄀ','ㄲ'=>'ᄁ','ㄳ'=>'ᆪ','ㄴ'=>'ᄂ','ㄵ'=>'ᆬ','ㄶ'=>'ᆭ','ㄷ'=>'ᄃ','ㄸ'=>'ᄄ','ㄹ'=>'ᄅ','ㄺ'=>'ᆰ','ㄻ'=>'ᆱ','ㄼ'=>'ᆲ','ㄽ'=>'ᆳ','ㄾ'=>'ᆴ','ㄿ'=>'ᆵ','ㅀ'=>'ᄚ','ㅁ'=>'ᄆ','ㅂ'=>'ᄇ','ㅃ'=>'ᄈ','ㅄ'=>'ᄡ','ㅅ'=>'ᄉ','ㅆ'=>'ᄊ','ㅇ'=>'ᄋ','ㅈ'=>'ᄌ','ㅉ'=>'ᄍ','ㅊ'=>'ᄎ','ㅋ'=>'ᄏ','ㅌ'=>'ᄐ','ㅍ'=>'ᄑ','ㅎ'=>'ᄒ','ㅏ'=>'ᅡ','ㅐ'=>'ᅢ','ㅑ'=>'ᅣ','ㅒ'=>'ᅤ','ㅓ'=>'ᅥ','ㅔ'=>'ᅦ','ㅕ'=>'ᅧ','ㅖ'=>'ᅨ','ㅗ'=>'ᅩ','ㅘ'=>'ᅪ','ㅙ'=>'ᅫ','ㅚ'=>'ᅬ','ㅛ'=>'ᅭ','ㅜ'=>'ᅮ','ㅝ'=>'ᅯ','ㅞ'=>'ᅰ','ㅟ'=>'ᅱ','ㅠ'=>'ᅲ','ㅡ'=>'ᅳ','ㅢ'=>'ᅴ','ㅣ'=>'ᅵ','ㅤ'=>'ᅠ','ㅥ'=>'ᄔ','ㅦ'=>'ᄕ','ㅧ'=>'ᇇ','ㅨ'=>'ᇈ','ㅩ'=>'ᇌ','ㅪ'=>'ᇎ','ㅫ'=>'ᇓ','ㅬ'=>'ᇗ','ㅭ'=>'ᇙ','ㅮ'=>'ᄜ','ㅯ'=>'ᇝ','ㅰ'=>'ᇟ','ㅱ'=>'ᄝ','ㅲ'=>'ᄞ','ㅳ'=>'ᄠ','ㅴ'=>'ᄢ','ㅵ'=>'ᄣ','ㅶ'=>'ᄧ','ㅷ'=>'ᄩ','ㅸ'=>'ᄫ','ㅹ'=>'ᄬ','ㅺ'=>'ᄭ','ㅻ'=>'ᄮ','ㅼ'=>'ᄯ','ㅽ'=>'ᄲ','ㅾ'=>'ᄶ','ㅿ'=>'ᅀ','ㆀ'=>'ᅇ','ㆁ'=>'ᅌ','ㆂ'=>'ᇱ','ㆃ'=>'ᇲ','ㆄ'=>'ᅗ','ㆅ'=>'ᅘ','ㆆ'=>'ᅙ','ㆇ'=>'ᆄ','ㆈ'=>'ᆅ','ㆉ'=>'ᆈ','ㆊ'=>'ᆑ','ㆋ'=>'ᆒ','ㆌ'=>'ᆔ','ㆍ'=>'ᆞ','ㆎ'=>'ᆡ','㆒'=>'一','㆓'=>'二','㆔'=>'三','㆕'=>'四','㆖'=>'上','㆗'=>'中','㆘'=>'下','㆙'=>'甲','㆚'=>'乙','㆛'=>'丙','㆜'=>'丁','㆝'=>'天','㆞'=>'地','㆟'=>'人','㈀'=>'(ᄀ)','㈁'=>'(ᄂ)','㈂'=>'(ᄃ)','㈃'=>'(ᄅ)','㈄'=>'(ᄆ)','㈅'=>'(ᄇ)','㈆'=>'(ᄉ)','㈇'=>'(ᄋ)','㈈'=>'(ᄌ)','㈉'=>'(ᄎ)','㈊'=>'(ᄏ)','㈋'=>'(ᄐ)','㈌'=>'(ᄑ)','㈍'=>'(ᄒ)','㈎'=>'(가)','㈏'=>'(나)','㈐'=>'(다)','㈑'=>'(라)','㈒'=>'(마)','㈓'=>'(바)','㈔'=>'(사)','㈕'=>'(아)','㈖'=>'(자)','㈗'=>'(차)','㈘'=>'(카)','㈙'=>'(타)','㈚'=>'(파)','㈛'=>'(하)','㈜'=>'(주)','㈝'=>'(오전)','㈞'=>'(오후)','㈠'=>'(一)','㈡'=>'(二)','㈢'=>'(三)','㈣'=>'(四)','㈤'=>'(五)','㈥'=>'(六)','㈦'=>'(七)','㈧'=>'(八)','㈨'=>'(九)','㈩'=>'(十)','㈪'=>'(月)','㈫'=>'(火)','㈬'=>'(水)','㈭'=>'(木)','㈮'=>'(金)','㈯'=>'(土)','㈰'=>'(日)','㈱'=>'(株)','㈲'=>'(有)','㈳'=>'(社)','㈴'=>'(名)','㈵'=>'(特)','㈶'=>'(財)','㈷'=>'(祝)','㈸'=>'(労)','㈹'=>'(代)','㈺'=>'(呼)','㈻'=>'(学)','㈼'=>'(監)','㈽'=>'(企)','㈾'=>'(資)','㈿'=>'(協)','㉀'=>'(祭)','㉁'=>'(休)','㉂'=>'(自)','㉃'=>'(至)','㉐'=>'PTE','㉑'=>'21','㉒'=>'22','㉓'=>'23','㉔'=>'24','㉕'=>'25','㉖'=>'26','㉗'=>'27','㉘'=>'28','㉙'=>'29','㉚'=>'30','㉛'=>'31','㉜'=>'32','㉝'=>'33','㉞'=>'34','㉟'=>'35','㉠'=>'ᄀ','㉡'=>'ᄂ','㉢'=>'ᄃ','㉣'=>'ᄅ','㉤'=>'ᄆ','㉥'=>'ᄇ','㉦'=>'ᄉ','㉧'=>'ᄋ','㉨'=>'ᄌ','㉩'=>'ᄎ','㉪'=>'ᄏ','㉫'=>'ᄐ','㉬'=>'ᄑ','㉭'=>'ᄒ','㉮'=>'가','㉯'=>'나','㉰'=>'다','㉱'=>'라','㉲'=>'마','㉳'=>'바','㉴'=>'사','㉵'=>'아','㉶'=>'자','㉷'=>'차','㉸'=>'카','㉹'=>'타','㉺'=>'파','㉻'=>'하','㉼'=>'참고','㉽'=>'주의','㉾'=>'우','㊀'=>'一','㊁'=>'二','㊂'=>'三','㊃'=>'四','㊄'=>'五','㊅'=>'六','㊆'=>'七','㊇'=>'八','㊈'=>'九','㊉'=>'十','㊊'=>'月','㊋'=>'火','㊌'=>'水','㊍'=>'木','㊎'=>'金','㊏'=>'土','㊐'=>'日','㊑'=>'株','㊒'=>'有','㊓'=>'社','㊔'=>'名','㊕'=>'特','㊖'=>'財','㊗'=>'祝','㊘'=>'労','㊙'=>'秘','㊚'=>'男','㊛'=>'女','㊜'=>'適','㊝'=>'優','㊞'=>'印','㊟'=>'注','㊠'=>'項','㊡'=>'休','㊢'=>'写','㊣'=>'正','㊤'=>'上','㊥'=>'中','㊦'=>'下','㊧'=>'左','㊨'=>'右','㊩'=>'医','㊪'=>'宗','㊫'=>'学','㊬'=>'監','㊭'=>'企','㊮'=>'資','㊯'=>'協','㊰'=>'夜','㊱'=>'36','㊲'=>'37','㊳'=>'38','㊴'=>'39','㊵'=>'40','㊶'=>'41','㊷'=>'42','㊸'=>'43','㊹'=>'44','㊺'=>'45','㊻'=>'46','㊼'=>'47','㊽'=>'48','㊾'=>'49','㊿'=>'50','㋀'=>'1月','㋁'=>'2月','㋂'=>'3月','㋃'=>'4月','㋄'=>'5月','㋅'=>'6月','㋆'=>'7月','㋇'=>'8月','㋈'=>'9月','㋉'=>'10月','㋊'=>'11月','㋋'=>'12月','㋌'=>'Hg','㋍'=>'erg','㋎'=>'eV','㋏'=>'LTD','㋐'=>'ア','㋑'=>'イ','㋒'=>'ウ','㋓'=>'エ','㋔'=>'オ','㋕'=>'カ','㋖'=>'キ','㋗'=>'ク','㋘'=>'ケ','㋙'=>'コ','㋚'=>'サ','㋛'=>'シ','㋜'=>'ス','㋝'=>'セ','㋞'=>'ソ','㋟'=>'タ','㋠'=>'チ','㋡'=>'ツ','㋢'=>'テ','㋣'=>'ト','㋤'=>'ナ','㋥'=>'ニ','㋦'=>'ヌ','㋧'=>'ネ','㋨'=>'ノ','㋩'=>'ハ','㋪'=>'ヒ','㋫'=>'フ','㋬'=>'ヘ','㋭'=>'ホ','㋮'=>'マ','㋯'=>'ミ','㋰'=>'ム','㋱'=>'メ','㋲'=>'モ','㋳'=>'ヤ','㋴'=>'ユ','㋵'=>'ヨ','㋶'=>'ラ','㋷'=>'リ','㋸'=>'ル','㋹'=>'レ','㋺'=>'ロ','㋻'=>'ワ','㋼'=>'ヰ','㋽'=>'ヱ','㋾'=>'ヲ','㌀'=>'アパート','㌁'=>'アルファ','㌂'=>'アンペア','㌃'=>'アール','㌄'=>'イニング','㌅'=>'インチ','㌆'=>'ウォン','㌇'=>'エスクード','㌈'=>'エーカー','㌉'=>'オンス','㌊'=>'オーム','㌋'=>'カイリ','㌌'=>'カラット','㌍'=>'カロリー','㌎'=>'ガロン','㌏'=>'ガンマ','㌐'=>'ギガ','㌑'=>'ギニー','㌒'=>'キュリー','㌓'=>'ギルダー','㌔'=>'キロ','㌕'=>'キログラム','㌖'=>'キロメートル','㌗'=>'キロワット','㌘'=>'グラム','㌙'=>'グラムトン','㌚'=>'クルゼイロ','㌛'=>'クローネ','㌜'=>'ケース','㌝'=>'コルナ','㌞'=>'コーポ','㌟'=>'サイクル','㌠'=>'サンチーム','㌡'=>'シリング','㌢'=>'センチ','㌣'=>'セント','㌤'=>'ダース','㌥'=>'デシ','㌦'=>'ドル','㌧'=>'トン','㌨'=>'ナノ','㌩'=>'ノット','㌪'=>'ハイツ','㌫'=>'パーセント','㌬'=>'パーツ','㌭'=>'バーレル','㌮'=>'ピアストル','㌯'=>'ピクル','㌰'=>'ピコ','㌱'=>'ビル','㌲'=>'ファラッド','㌳'=>'フィート','㌴'=>'ブッシェル','㌵'=>'フラン','㌶'=>'ヘクタール','㌷'=>'ペソ','㌸'=>'ペニヒ','㌹'=>'ヘルツ','㌺'=>'ペンス','㌻'=>'ページ','㌼'=>'ベータ','㌽'=>'ポイント','㌾'=>'ボルト','㌿'=>'ホン','㍀'=>'ポンド','㍁'=>'ホール','㍂'=>'ホーン','㍃'=>'マイクロ','㍄'=>'マイル','㍅'=>'マッハ','㍆'=>'マルク','㍇'=>'マンション','㍈'=>'ミクロン','㍉'=>'ミリ','㍊'=>'ミリバール','㍋'=>'メガ','㍌'=>'メガトン','㍍'=>'メートル','㍎'=>'ヤード','㍏'=>'ヤール','㍐'=>'ユアン','㍑'=>'リットル','㍒'=>'リラ','㍓'=>'ルピー','㍔'=>'ルーブル','㍕'=>'レム','㍖'=>'レントゲン','㍗'=>'ワット','㍘'=>'0点','㍙'=>'1点','㍚'=>'2点','㍛'=>'3点','㍜'=>'4点','㍝'=>'5点','㍞'=>'6点','㍟'=>'7点','㍠'=>'8点','㍡'=>'9点','㍢'=>'10点','㍣'=>'11点','㍤'=>'12点','㍥'=>'13点','㍦'=>'14点','㍧'=>'15点','㍨'=>'16点','㍩'=>'17点','㍪'=>'18点','㍫'=>'19点','㍬'=>'20点','㍭'=>'21点','㍮'=>'22点','㍯'=>'23点','㍰'=>'24点','㍱'=>'hPa','㍲'=>'da','㍳'=>'AU','㍴'=>'bar','㍵'=>'oV','㍶'=>'pc','㍷'=>'dm','㍸'=>'dm2','㍹'=>'dm3','㍺'=>'IU','㍻'=>'平成','㍼'=>'昭和','㍽'=>'大正','㍾'=>'明治','㍿'=>'株式会社','㎀'=>'pA','㎁'=>'nA','㎂'=>'μA','㎃'=>'mA','㎄'=>'kA','㎅'=>'KB','㎆'=>'MB','㎇'=>'GB','㎈'=>'cal','㎉'=>'kcal','㎊'=>'pF','㎋'=>'nF','㎌'=>'μF','㎍'=>'μg','㎎'=>'mg','㎏'=>'kg','㎐'=>'Hz','㎑'=>'kHz','㎒'=>'MHz','㎓'=>'GHz','㎔'=>'THz','㎕'=>'μl','㎖'=>'ml','㎗'=>'dl','㎘'=>'kl','㎙'=>'fm','㎚'=>'nm','㎛'=>'μm','㎜'=>'mm','㎝'=>'cm','㎞'=>'km','㎟'=>'mm2','㎠'=>'cm2','㎡'=>'m2','㎢'=>'km2','㎣'=>'mm3','㎤'=>'cm3','㎥'=>'m3','㎦'=>'km3','㎧'=>'m∕s','㎨'=>'m∕s2','㎩'=>'Pa','㎪'=>'kPa','㎫'=>'MPa','㎬'=>'GPa','㎭'=>'rad','㎮'=>'rad∕s','㎯'=>'rad∕s2','㎰'=>'ps','㎱'=>'ns','㎲'=>'μs','㎳'=>'ms','㎴'=>'pV','㎵'=>'nV','㎶'=>'μV','㎷'=>'mV','㎸'=>'kV','㎹'=>'MV','㎺'=>'pW','㎻'=>'nW','㎼'=>'μW','㎽'=>'mW','㎾'=>'kW','㎿'=>'MW','㏀'=>'kΩ','㏁'=>'MΩ','㏂'=>'a.m.','㏃'=>'Bq','㏄'=>'cc','㏅'=>'cd','㏆'=>'C∕kg','㏇'=>'Co.','㏈'=>'dB','㏉'=>'Gy','㏊'=>'ha','㏋'=>'HP','㏌'=>'in','㏍'=>'KK','㏎'=>'KM','㏏'=>'kt','㏐'=>'lm','㏑'=>'ln','㏒'=>'log','㏓'=>'lx','㏔'=>'mb','㏕'=>'mil','㏖'=>'mol','㏗'=>'PH','㏘'=>'p.m.','㏙'=>'PPM','㏚'=>'PR','㏛'=>'sr','㏜'=>'Sv','㏝'=>'Wb','㏞'=>'V∕m','㏟'=>'A∕m','㏠'=>'1日','㏡'=>'2日','㏢'=>'3日','㏣'=>'4日','㏤'=>'5日','㏥'=>'6日','㏦'=>'7日','㏧'=>'8日','㏨'=>'9日','㏩'=>'10日','㏪'=>'11日','㏫'=>'12日','㏬'=>'13日','㏭'=>'14日','㏮'=>'15日','㏯'=>'16日','㏰'=>'17日','㏱'=>'18日','㏲'=>'19日','㏳'=>'20日','㏴'=>'21日','㏵'=>'22日','㏶'=>'23日','㏷'=>'24日','㏸'=>'25日','㏹'=>'26日','㏺'=>'27日','㏻'=>'28日','㏼'=>'29日','㏽'=>'30日','㏾'=>'31日','㏿'=>'gal','豈'=>'豈','更'=>'更','車'=>'車','賈'=>'賈','滑'=>'滑','串'=>'串','句'=>'句','龜'=>'龜','龜'=>'龜','契'=>'契','金'=>'金','喇'=>'喇','奈'=>'奈','懶'=>'懶','癩'=>'癩','羅'=>'羅','蘿'=>'蘿','螺'=>'螺','裸'=>'裸','邏'=>'邏','樂'=>'樂','洛'=>'洛','烙'=>'烙','珞'=>'珞','落'=>'落','酪'=>'酪','駱'=>'駱','亂'=>'亂','卵'=>'卵','欄'=>'欄','爛'=>'爛','蘭'=>'蘭','鸞'=>'鸞','嵐'=>'嵐','濫'=>'濫','藍'=>'藍','襤'=>'襤','拉'=>'拉','臘'=>'臘','蠟'=>'蠟','廊'=>'廊','朗'=>'朗','浪'=>'浪','狼'=>'狼','郎'=>'郎','來'=>'來','冷'=>'冷','勞'=>'勞','擄'=>'擄','櫓'=>'櫓','爐'=>'爐','盧'=>'盧','老'=>'老','蘆'=>'蘆','虜'=>'虜','路'=>'路','露'=>'露','魯'=>'魯','鷺'=>'鷺','碌'=>'碌','祿'=>'祿','綠'=>'綠','菉'=>'菉','錄'=>'錄','鹿'=>'鹿','論'=>'論','壟'=>'壟','弄'=>'弄','籠'=>'籠','聾'=>'聾','牢'=>'牢','磊'=>'磊','賂'=>'賂','雷'=>'雷','壘'=>'壘','屢'=>'屢','樓'=>'樓','淚'=>'淚','漏'=>'漏','累'=>'累','縷'=>'縷','陋'=>'陋','勒'=>'勒','肋'=>'肋','凜'=>'凜','凌'=>'凌','稜'=>'稜','綾'=>'綾','菱'=>'菱','陵'=>'陵','讀'=>'讀','拏'=>'拏','樂'=>'樂','諾'=>'諾','丹'=>'丹','寧'=>'寧','怒'=>'怒','率'=>'率','異'=>'異','北'=>'北','磻'=>'磻','便'=>'便','復'=>'復','不'=>'不','泌'=>'泌','數'=>'數','索'=>'索','參'=>'參','塞'=>'塞','省'=>'省','葉'=>'葉','說'=>'說','殺'=>'殺','辰'=>'辰','沈'=>'沈','拾'=>'拾','若'=>'若','掠'=>'掠','略'=>'略','亮'=>'亮','兩'=>'兩','凉'=>'凉','梁'=>'梁','糧'=>'糧','良'=>'良','諒'=>'諒','量'=>'量','勵'=>'勵','呂'=>'呂','女'=>'女','廬'=>'廬','旅'=>'旅','濾'=>'濾','礪'=>'礪','閭'=>'閭','驪'=>'驪','麗'=>'麗','黎'=>'黎','力'=>'力','曆'=>'曆','歷'=>'歷','轢'=>'轢','年'=>'年','憐'=>'憐','戀'=>'戀','撚'=>'撚','漣'=>'漣','煉'=>'煉','璉'=>'璉','秊'=>'秊','練'=>'練','聯'=>'聯','輦'=>'輦','蓮'=>'蓮','連'=>'連','鍊'=>'鍊','列'=>'列','劣'=>'劣','咽'=>'咽','烈'=>'烈','裂'=>'裂','說'=>'說','廉'=>'廉','念'=>'念','捻'=>'捻','殮'=>'殮','簾'=>'簾','獵'=>'獵','令'=>'令','囹'=>'囹','寧'=>'寧','嶺'=>'嶺','怜'=>'怜','玲'=>'玲','瑩'=>'瑩','羚'=>'羚','聆'=>'聆','鈴'=>'鈴','零'=>'零','靈'=>'靈','領'=>'領','例'=>'例','禮'=>'禮','醴'=>'醴','隸'=>'隸','惡'=>'惡','了'=>'了','僚'=>'僚','寮'=>'寮','尿'=>'尿','料'=>'料','樂'=>'樂','燎'=>'燎','療'=>'療','蓼'=>'蓼','遼'=>'遼','龍'=>'龍','暈'=>'暈','阮'=>'阮','劉'=>'劉','杻'=>'杻','柳'=>'柳','流'=>'流','溜'=>'溜','琉'=>'琉','留'=>'留','硫'=>'硫','紐'=>'紐','類'=>'類','六'=>'六','戮'=>'戮','陸'=>'陸','倫'=>'倫','崙'=>'崙','淪'=>'淪','輪'=>'輪','律'=>'律','慄'=>'慄','栗'=>'栗','率'=>'率','隆'=>'隆','利'=>'利','吏'=>'吏','履'=>'履','易'=>'易','李'=>'李','梨'=>'梨','泥'=>'泥','理'=>'理','痢'=>'痢','罹'=>'罹','裏'=>'裏','裡'=>'裡','里'=>'里','離'=>'離','匿'=>'匿','溺'=>'溺','吝'=>'吝','燐'=>'燐','璘'=>'璘','藺'=>'藺','隣'=>'隣','鱗'=>'鱗','麟'=>'麟','林'=>'林','淋'=>'淋','臨'=>'臨','立'=>'立','笠'=>'笠','粒'=>'粒','狀'=>'狀','炙'=>'炙','識'=>'識','什'=>'什','茶'=>'茶','刺'=>'刺','切'=>'切','度'=>'度','拓'=>'拓','糖'=>'糖','宅'=>'宅','洞'=>'洞','暴'=>'暴','輻'=>'輻','行'=>'行','降'=>'降','見'=>'見','廓'=>'廓','兀'=>'兀','嗀'=>'嗀','塚'=>'塚','晴'=>'晴','凞'=>'凞','猪'=>'猪','益'=>'益','礼'=>'礼','神'=>'神','祥'=>'祥','福'=>'福','靖'=>'靖','精'=>'精','羽'=>'羽','蘒'=>'蘒','諸'=>'諸','逸'=>'逸','都'=>'都','飯'=>'飯','飼'=>'飼','館'=>'館','鶴'=>'鶴','侮'=>'侮','僧'=>'僧','免'=>'免','勉'=>'勉','勤'=>'勤','卑'=>'卑','喝'=>'喝','嘆'=>'嘆','器'=>'器','塀'=>'塀','墨'=>'墨','層'=>'層','屮'=>'屮','悔'=>'悔','慨'=>'慨','憎'=>'憎','懲'=>'懲','敏'=>'敏','既'=>'既','暑'=>'暑','梅'=>'梅','海'=>'海','渚'=>'渚','漢'=>'漢','煮'=>'煮','爫'=>'爫','琢'=>'琢','碑'=>'碑','社'=>'社','祉'=>'祉','祈'=>'祈','祐'=>'祐','祖'=>'祖','祝'=>'祝','禍'=>'禍','禎'=>'禎','穀'=>'穀','突'=>'突','節'=>'節','練'=>'練','縉'=>'縉','繁'=>'繁','署'=>'署','者'=>'者','臭'=>'臭','艹'=>'艹','艹'=>'艹','著'=>'著','褐'=>'褐','視'=>'視','謁'=>'謁','謹'=>'謹','賓'=>'賓','贈'=>'贈','辶'=>'辶','逸'=>'逸','難'=>'難','響'=>'響','頻'=>'頻','並'=>'並','况'=>'况','全'=>'全','侀'=>'侀','充'=>'充','冀'=>'冀','勇'=>'勇','勺'=>'勺','喝'=>'喝','啕'=>'啕','喙'=>'喙','嗢'=>'嗢','塚'=>'塚','墳'=>'墳','奄'=>'奄','奔'=>'奔','婢'=>'婢','嬨'=>'嬨','廒'=>'廒','廙'=>'廙','彩'=>'彩','徭'=>'徭','惘'=>'惘','慎'=>'慎','愈'=>'愈','憎'=>'憎','慠'=>'慠','懲'=>'懲','戴'=>'戴','揄'=>'揄','搜'=>'搜','摒'=>'摒','敖'=>'敖','晴'=>'晴','朗'=>'朗','望'=>'望','杖'=>'杖','歹'=>'歹','殺'=>'殺','流'=>'流','滛'=>'滛','滋'=>'滋','漢'=>'漢','瀞'=>'瀞','煮'=>'煮','瞧'=>'瞧','爵'=>'爵','犯'=>'犯','猪'=>'猪','瑱'=>'瑱','甆'=>'甆','画'=>'画','瘝'=>'瘝','瘟'=>'瘟','益'=>'益','盛'=>'盛','直'=>'直','睊'=>'睊','着'=>'着','磌'=>'磌','窱'=>'窱','節'=>'節','类'=>'类','絛'=>'絛','練'=>'練','缾'=>'缾','者'=>'者','荒'=>'荒','華'=>'華','蝹'=>'蝹','襁'=>'襁','覆'=>'覆','視'=>'視','調'=>'調','諸'=>'諸','請'=>'請','謁'=>'謁','諾'=>'諾','諭'=>'諭','謹'=>'謹','變'=>'變','贈'=>'贈','輸'=>'輸','遲'=>'遲','醙'=>'醙','鉶'=>'鉶','陼'=>'陼','難'=>'難','靖'=>'靖','韛'=>'韛','響'=>'響','頋'=>'頋','頻'=>'頻','鬒'=>'鬒','龜'=>'龜','𢡊'=>'𢡊','𢡄'=>'𢡄','𣏕'=>'𣏕','㮝'=>'㮝','䀘'=>'䀘','䀹'=>'䀹','𥉉'=>'𥉉','𥳐'=>'𥳐','𧻓'=>'𧻓','齃'=>'齃','龎'=>'龎','ff'=>'ff','fi'=>'fi','fl'=>'fl','ffi'=>'ffi','ffl'=>'ffl','ſt'=>'st','st'=>'st','ﬓ'=>'մն','ﬔ'=>'մե','ﬕ'=>'մի','ﬖ'=>'վն','ﬗ'=>'մխ','יִ'=>'יִ','ײַ'=>'ײַ','ﬠ'=>'ע','ﬡ'=>'א','ﬢ'=>'ד','ﬣ'=>'ה','ﬤ'=>'כ','ﬥ'=>'ל','ﬦ'=>'ם','ﬧ'=>'ר','ﬨ'=>'ת','﬩'=>'+','שׁ'=>'שׁ','שׂ'=>'שׂ','שּׁ'=>'שּׁ','שּׂ'=>'שּׂ','אַ'=>'אַ','אָ'=>'אָ','אּ'=>'אּ','בּ'=>'בּ','גּ'=>'גּ','דּ'=>'דּ','הּ'=>'הּ','וּ'=>'וּ','זּ'=>'זּ','טּ'=>'טּ','יּ'=>'יּ','ךּ'=>'ךּ','כּ'=>'כּ','לּ'=>'לּ','מּ'=>'מּ','נּ'=>'נּ','סּ'=>'סּ','ףּ'=>'ףּ','פּ'=>'פּ','צּ'=>'צּ','קּ'=>'קּ','רּ'=>'רּ','שּ'=>'שּ','תּ'=>'תּ','וֹ'=>'וֹ','בֿ'=>'בֿ','כֿ'=>'כֿ','פֿ'=>'פֿ','ﭏ'=>'אל','ﭐ'=>'ٱ','ﭑ'=>'ٱ','ﭒ'=>'ٻ','ﭓ'=>'ٻ','ﭔ'=>'ٻ','ﭕ'=>'ٻ','ﭖ'=>'پ','ﭗ'=>'پ','ﭘ'=>'پ','ﭙ'=>'پ','ﭚ'=>'ڀ','ﭛ'=>'ڀ','ﭜ'=>'ڀ','ﭝ'=>'ڀ','ﭞ'=>'ٺ','ﭟ'=>'ٺ','ﭠ'=>'ٺ','ﭡ'=>'ٺ','ﭢ'=>'ٿ','ﭣ'=>'ٿ','ﭤ'=>'ٿ','ﭥ'=>'ٿ','ﭦ'=>'ٹ','ﭧ'=>'ٹ','ﭨ'=>'ٹ','ﭩ'=>'ٹ','ﭪ'=>'ڤ','ﭫ'=>'ڤ','ﭬ'=>'ڤ','ﭭ'=>'ڤ','ﭮ'=>'ڦ','ﭯ'=>'ڦ','ﭰ'=>'ڦ','ﭱ'=>'ڦ','ﭲ'=>'ڄ','ﭳ'=>'ڄ','ﭴ'=>'ڄ','ﭵ'=>'ڄ','ﭶ'=>'ڃ','ﭷ'=>'ڃ','ﭸ'=>'ڃ','ﭹ'=>'ڃ','ﭺ'=>'چ','ﭻ'=>'چ','ﭼ'=>'چ','ﭽ'=>'چ','ﭾ'=>'ڇ','ﭿ'=>'ڇ','ﮀ'=>'ڇ','ﮁ'=>'ڇ','ﮂ'=>'ڍ','ﮃ'=>'ڍ','ﮄ'=>'ڌ','ﮅ'=>'ڌ','ﮆ'=>'ڎ','ﮇ'=>'ڎ','ﮈ'=>'ڈ','ﮉ'=>'ڈ','ﮊ'=>'ژ','ﮋ'=>'ژ','ﮌ'=>'ڑ','ﮍ'=>'ڑ','ﮎ'=>'ک','ﮏ'=>'ک','ﮐ'=>'ک','ﮑ'=>'ک','ﮒ'=>'گ','ﮓ'=>'گ','ﮔ'=>'گ','ﮕ'=>'گ','ﮖ'=>'ڳ','ﮗ'=>'ڳ','ﮘ'=>'ڳ','ﮙ'=>'ڳ','ﮚ'=>'ڱ','ﮛ'=>'ڱ','ﮜ'=>'ڱ','ﮝ'=>'ڱ','ﮞ'=>'ں','ﮟ'=>'ں','ﮠ'=>'ڻ','ﮡ'=>'ڻ','ﮢ'=>'ڻ','ﮣ'=>'ڻ','ﮤ'=>'ۀ','ﮥ'=>'ۀ','ﮦ'=>'ہ','ﮧ'=>'ہ','ﮨ'=>'ہ','ﮩ'=>'ہ','ﮪ'=>'ھ','ﮫ'=>'ھ','ﮬ'=>'ھ','ﮭ'=>'ھ','ﮮ'=>'ے','ﮯ'=>'ے','ﮰ'=>'ۓ','ﮱ'=>'ۓ','ﯓ'=>'ڭ','ﯔ'=>'ڭ','ﯕ'=>'ڭ','ﯖ'=>'ڭ','ﯗ'=>'ۇ','ﯘ'=>'ۇ','ﯙ'=>'ۆ','ﯚ'=>'ۆ','ﯛ'=>'ۈ','ﯜ'=>'ۈ','ﯝ'=>'ۇٴ','ﯞ'=>'ۋ','ﯟ'=>'ۋ','ﯠ'=>'ۅ','ﯡ'=>'ۅ','ﯢ'=>'ۉ','ﯣ'=>'ۉ','ﯤ'=>'ې','ﯥ'=>'ې','ﯦ'=>'ې','ﯧ'=>'ې','ﯨ'=>'ى','ﯩ'=>'ى','ﯪ'=>'ئا','ﯫ'=>'ئا','ﯬ'=>'ئە','ﯭ'=>'ئە','ﯮ'=>'ئو','ﯯ'=>'ئو','ﯰ'=>'ئۇ','ﯱ'=>'ئۇ','ﯲ'=>'ئۆ','ﯳ'=>'ئۆ','ﯴ'=>'ئۈ','ﯵ'=>'ئۈ','ﯶ'=>'ئې','ﯷ'=>'ئې','ﯸ'=>'ئې','ﯹ'=>'ئى','ﯺ'=>'ئى','ﯻ'=>'ئى','ﯼ'=>'ی','ﯽ'=>'ی','ﯾ'=>'ی','ﯿ'=>'ی','ﰀ'=>'ئج','ﰁ'=>'ئح','ﰂ'=>'ئم','ﰃ'=>'ئى','ﰄ'=>'ئي','ﰅ'=>'بج','ﰆ'=>'بح','ﰇ'=>'بخ','ﰈ'=>'بم','ﰉ'=>'بى','ﰊ'=>'بي','ﰋ'=>'تج','ﰌ'=>'تح','ﰍ'=>'تخ','ﰎ'=>'تم','ﰏ'=>'تى','ﰐ'=>'تي','ﰑ'=>'ثج','ﰒ'=>'ثم','ﰓ'=>'ثى','ﰔ'=>'ثي','ﰕ'=>'جح','ﰖ'=>'جم','ﰗ'=>'حج','ﰘ'=>'حم','ﰙ'=>'خج','ﰚ'=>'خح','ﰛ'=>'خم','ﰜ'=>'سج','ﰝ'=>'سح','ﰞ'=>'سخ','ﰟ'=>'سم','ﰠ'=>'صح','ﰡ'=>'صم','ﰢ'=>'ضج','ﰣ'=>'ضح','ﰤ'=>'ضخ','ﰥ'=>'ضم','ﰦ'=>'طح','ﰧ'=>'طم','ﰨ'=>'ظم','ﰩ'=>'عج','ﰪ'=>'عم','ﰫ'=>'غج','ﰬ'=>'غم','ﰭ'=>'فج','ﰮ'=>'فح','ﰯ'=>'فخ','ﰰ'=>'فم','ﰱ'=>'فى','ﰲ'=>'في','ﰳ'=>'قح','ﰴ'=>'قم','ﰵ'=>'قى','ﰶ'=>'قي','ﰷ'=>'كا','ﰸ'=>'كج','ﰹ'=>'كح','ﰺ'=>'كخ','ﰻ'=>'كل','ﰼ'=>'كم','ﰽ'=>'كى','ﰾ'=>'كي','ﰿ'=>'لج','ﱀ'=>'لح','ﱁ'=>'لخ','ﱂ'=>'لم','ﱃ'=>'لى','ﱄ'=>'لي','ﱅ'=>'مج','ﱆ'=>'مح','ﱇ'=>'مخ','ﱈ'=>'مم','ﱉ'=>'مى','ﱊ'=>'مي','ﱋ'=>'نج','ﱌ'=>'نح','ﱍ'=>'نخ','ﱎ'=>'نم','ﱏ'=>'نى','ﱐ'=>'ني','ﱑ'=>'هج','ﱒ'=>'هم','ﱓ'=>'هى','ﱔ'=>'هي','ﱕ'=>'يج','ﱖ'=>'يح','ﱗ'=>'يخ','ﱘ'=>'يم','ﱙ'=>'يى','ﱚ'=>'يي','ﱛ'=>'ذٰ','ﱜ'=>'رٰ','ﱝ'=>'ىٰ','ﱞ'=>' ٌّ','ﱟ'=>' ٍّ','ﱠ'=>' َّ','ﱡ'=>' ُّ','ﱢ'=>' ِّ','ﱣ'=>' ّٰ','ﱤ'=>'ئر','ﱥ'=>'ئز','ﱦ'=>'ئم','ﱧ'=>'ئن','ﱨ'=>'ئى','ﱩ'=>'ئي','ﱪ'=>'بر','ﱫ'=>'بز','ﱬ'=>'بم','ﱭ'=>'بن','ﱮ'=>'بى','ﱯ'=>'بي','ﱰ'=>'تر','ﱱ'=>'تز','ﱲ'=>'تم','ﱳ'=>'تن','ﱴ'=>'تى','ﱵ'=>'تي','ﱶ'=>'ثر','ﱷ'=>'ثز','ﱸ'=>'ثم','ﱹ'=>'ثن','ﱺ'=>'ثى','ﱻ'=>'ثي','ﱼ'=>'فى','ﱽ'=>'في','ﱾ'=>'قى','ﱿ'=>'قي','ﲀ'=>'كا','ﲁ'=>'كل','ﲂ'=>'كم','ﲃ'=>'كى','ﲄ'=>'كي','ﲅ'=>'لم','ﲆ'=>'لى','ﲇ'=>'لي','ﲈ'=>'ما','ﲉ'=>'مم','ﲊ'=>'نر','ﲋ'=>'نز','ﲌ'=>'نم','ﲍ'=>'نن','ﲎ'=>'نى','ﲏ'=>'ني','ﲐ'=>'ىٰ','ﲑ'=>'ير','ﲒ'=>'يز','ﲓ'=>'يم','ﲔ'=>'ين','ﲕ'=>'يى','ﲖ'=>'يي','ﲗ'=>'ئج','ﲘ'=>'ئح','ﲙ'=>'ئخ','ﲚ'=>'ئم','ﲛ'=>'ئه','ﲜ'=>'بج','ﲝ'=>'بح','ﲞ'=>'بخ','ﲟ'=>'بم','ﲠ'=>'به','ﲡ'=>'تج','ﲢ'=>'تح','ﲣ'=>'تخ','ﲤ'=>'تم','ﲥ'=>'ته','ﲦ'=>'ثم','ﲧ'=>'جح','ﲨ'=>'جم','ﲩ'=>'حج','ﲪ'=>'حم','ﲫ'=>'خج','ﲬ'=>'خم','ﲭ'=>'سج','ﲮ'=>'سح','ﲯ'=>'سخ','ﲰ'=>'سم','ﲱ'=>'صح','ﲲ'=>'صخ','ﲳ'=>'صم','ﲴ'=>'ضج','ﲵ'=>'ضح','ﲶ'=>'ضخ','ﲷ'=>'ضم','ﲸ'=>'طح','ﲹ'=>'ظم','ﲺ'=>'عج','ﲻ'=>'عم','ﲼ'=>'غج','ﲽ'=>'غم','ﲾ'=>'فج','ﲿ'=>'فح','ﳀ'=>'فخ','ﳁ'=>'فم','ﳂ'=>'قح','ﳃ'=>'قم','ﳄ'=>'كج','ﳅ'=>'كح','ﳆ'=>'كخ','ﳇ'=>'كل','ﳈ'=>'كم','ﳉ'=>'لج','ﳊ'=>'لح','ﳋ'=>'لخ','ﳌ'=>'لم','ﳍ'=>'له','ﳎ'=>'مج','ﳏ'=>'مح','ﳐ'=>'مخ','ﳑ'=>'مم','ﳒ'=>'نج','ﳓ'=>'نح','ﳔ'=>'نخ','ﳕ'=>'نم','ﳖ'=>'نه','ﳗ'=>'هج','ﳘ'=>'هم','ﳙ'=>'هٰ','ﳚ'=>'يج','ﳛ'=>'يح','ﳜ'=>'يخ','ﳝ'=>'يم','ﳞ'=>'يه','ﳟ'=>'ئم','ﳠ'=>'ئه','ﳡ'=>'بم','ﳢ'=>'به','ﳣ'=>'تم','ﳤ'=>'ته','ﳥ'=>'ثم','ﳦ'=>'ثه','ﳧ'=>'سم','ﳨ'=>'سه','ﳩ'=>'شم','ﳪ'=>'شه','ﳫ'=>'كل','ﳬ'=>'كم','ﳭ'=>'لم','ﳮ'=>'نم','ﳯ'=>'نه','ﳰ'=>'يم','ﳱ'=>'يه','ﳲ'=>'ـَّ','ﳳ'=>'ـُّ','ﳴ'=>'ـِّ','ﳵ'=>'طى','ﳶ'=>'طي','ﳷ'=>'عى','ﳸ'=>'عي','ﳹ'=>'غى','ﳺ'=>'غي','ﳻ'=>'سى','ﳼ'=>'سي','ﳽ'=>'شى','ﳾ'=>'شي','ﳿ'=>'حى','ﴀ'=>'حي','ﴁ'=>'جى','ﴂ'=>'جي','ﴃ'=>'خى','ﴄ'=>'خي','ﴅ'=>'صى','ﴆ'=>'صي','ﴇ'=>'ضى','ﴈ'=>'ضي','ﴉ'=>'شج','ﴊ'=>'شح','ﴋ'=>'شخ','ﴌ'=>'شم','ﴍ'=>'شر','ﴎ'=>'سر','ﴏ'=>'صر','ﴐ'=>'ضر','ﴑ'=>'طى','ﴒ'=>'طي','ﴓ'=>'عى','ﴔ'=>'عي','ﴕ'=>'غى','ﴖ'=>'غي','ﴗ'=>'سى','ﴘ'=>'سي','ﴙ'=>'شى','ﴚ'=>'شي','ﴛ'=>'حى','ﴜ'=>'حي','ﴝ'=>'جى','ﴞ'=>'جي','ﴟ'=>'خى','ﴠ'=>'خي','ﴡ'=>'صى','ﴢ'=>'صي','ﴣ'=>'ضى','ﴤ'=>'ضي','ﴥ'=>'شج','ﴦ'=>'شح','ﴧ'=>'شخ','ﴨ'=>'شم','ﴩ'=>'شر','ﴪ'=>'سر','ﴫ'=>'صر','ﴬ'=>'ضر','ﴭ'=>'شج','ﴮ'=>'شح','ﴯ'=>'شخ','ﴰ'=>'شم','ﴱ'=>'سه','ﴲ'=>'شه','ﴳ'=>'طم','ﴴ'=>'سج','ﴵ'=>'سح','ﴶ'=>'سخ','ﴷ'=>'شج','ﴸ'=>'شح','ﴹ'=>'شخ','ﴺ'=>'طم','ﴻ'=>'ظم','ﴼ'=>'اً','ﴽ'=>'اً','ﵐ'=>'تجم','ﵑ'=>'تحج','ﵒ'=>'تحج','ﵓ'=>'تحم','ﵔ'=>'تخم','ﵕ'=>'تمج','ﵖ'=>'تمح','ﵗ'=>'تمخ','ﵘ'=>'جمح','ﵙ'=>'جمح','ﵚ'=>'حمي','ﵛ'=>'حمى','ﵜ'=>'سحج','ﵝ'=>'سجح','ﵞ'=>'سجى','ﵟ'=>'سمح','ﵠ'=>'سمح','ﵡ'=>'سمج','ﵢ'=>'سمم','ﵣ'=>'سمم','ﵤ'=>'صحح','ﵥ'=>'صحح','ﵦ'=>'صمم','ﵧ'=>'شحم','ﵨ'=>'شحم','ﵩ'=>'شجي','ﵪ'=>'شمخ','ﵫ'=>'شمخ','ﵬ'=>'شمم','ﵭ'=>'شمم','ﵮ'=>'ضحى','ﵯ'=>'ضخم','ﵰ'=>'ضخم','ﵱ'=>'طمح','ﵲ'=>'طمح','ﵳ'=>'طمم','ﵴ'=>'طمي','ﵵ'=>'عجم','ﵶ'=>'عمم','ﵷ'=>'عمم','ﵸ'=>'عمى','ﵹ'=>'غمم','ﵺ'=>'غمي','ﵻ'=>'غمى','ﵼ'=>'فخم','ﵽ'=>'فخم','ﵾ'=>'قمح','ﵿ'=>'قمم','ﶀ'=>'لحم','ﶁ'=>'لحي','ﶂ'=>'لحى','ﶃ'=>'لجج','ﶄ'=>'لجج','ﶅ'=>'لخم','ﶆ'=>'لخم','ﶇ'=>'لمح','ﶈ'=>'لمح','ﶉ'=>'محج','ﶊ'=>'محم','ﶋ'=>'محي','ﶌ'=>'مجح','ﶍ'=>'مجم','ﶎ'=>'مخج','ﶏ'=>'مخم','ﶒ'=>'مجخ','ﶓ'=>'همج','ﶔ'=>'همم','ﶕ'=>'نحم','ﶖ'=>'نحى','ﶗ'=>'نجم','ﶘ'=>'نجم','ﶙ'=>'نجى','ﶚ'=>'نمي','ﶛ'=>'نمى','ﶜ'=>'يمم','ﶝ'=>'يمم','ﶞ'=>'بخي','ﶟ'=>'تجي','ﶠ'=>'تجى','ﶡ'=>'تخي','ﶢ'=>'تخى','ﶣ'=>'تمي','ﶤ'=>'تمى','ﶥ'=>'جمي','ﶦ'=>'جحى','ﶧ'=>'جمى','ﶨ'=>'سخى','ﶩ'=>'صحي','ﶪ'=>'شحي','ﶫ'=>'ضحي','ﶬ'=>'لجي','ﶭ'=>'لمي','ﶮ'=>'يحي','ﶯ'=>'يجي','ﶰ'=>'يمي','ﶱ'=>'ممي','ﶲ'=>'قمي','ﶳ'=>'نحي','ﶴ'=>'قمح','ﶵ'=>'لحم','ﶶ'=>'عمي','ﶷ'=>'كمي','ﶸ'=>'نجح','ﶹ'=>'مخي','ﶺ'=>'لجم','ﶻ'=>'كمم','ﶼ'=>'لجم','ﶽ'=>'نجح','ﶾ'=>'جحي','ﶿ'=>'حجي','ﷀ'=>'مجي','ﷁ'=>'فمي','ﷂ'=>'بحي','ﷃ'=>'كمم','ﷄ'=>'عجم','ﷅ'=>'صمم','ﷆ'=>'سخي','ﷇ'=>'نجي','ﷰ'=>'صلے','ﷱ'=>'قلے','ﷲ'=>'الله','ﷳ'=>'اكبر','ﷴ'=>'محمد','ﷵ'=>'صلعم','ﷶ'=>'رسول','ﷷ'=>'عليه','ﷸ'=>'وسلم','ﷹ'=>'صلى','ﷺ'=>'صلى الله عليه وسلم','ﷻ'=>'جل جلاله','﷼'=>'ریال','︐'=>',','︑'=>'、','︒'=>'。','︓'=>':','︔'=>';','︕'=>'!','︖'=>'?','︗'=>'〖','︘'=>'〗','︙'=>'...','︰'=>'..','︱'=>'—','︲'=>'–','︳'=>'_','︴'=>'_','︵'=>'(','︶'=>')','︷'=>'{','︸'=>'}','︹'=>'〔','︺'=>'〕','︻'=>'【','︼'=>'】','︽'=>'《','︾'=>'》','︿'=>'〈','﹀'=>'〉','﹁'=>'「','﹂'=>'」','﹃'=>'『','﹄'=>'』','﹇'=>'[','﹈'=>']','﹉'=>' ̅','﹊'=>' ̅','﹋'=>' ̅','﹌'=>' ̅','﹍'=>'_','﹎'=>'_','﹏'=>'_','﹐'=>',','﹑'=>'、','﹒'=>'.','﹔'=>';','﹕'=>':','﹖'=>'?','﹗'=>'!','﹘'=>'—','﹙'=>'(','﹚'=>')','﹛'=>'{','﹜'=>'}','﹝'=>'〔','﹞'=>'〕','﹟'=>'#','﹠'=>'&','﹡'=>'*','﹢'=>'+','﹣'=>'-','﹤'=>'<','﹥'=>'>','﹦'=>'=','﹨'=>'\\','﹩'=>'$','﹪'=>'%','﹫'=>'@','ﹰ'=>' ً','ﹱ'=>'ـً','ﹲ'=>' ٌ','ﹴ'=>' ٍ','ﹶ'=>' َ','ﹷ'=>'ـَ','ﹸ'=>' ُ','ﹹ'=>'ـُ','ﹺ'=>' ِ','ﹻ'=>'ـِ','ﹼ'=>' ّ','ﹽ'=>'ـّ','ﹾ'=>' ْ','ﹿ'=>'ـْ','ﺀ'=>'ء','ﺁ'=>'آ','ﺂ'=>'آ','ﺃ'=>'أ','ﺄ'=>'أ','ﺅ'=>'ؤ','ﺆ'=>'ؤ','ﺇ'=>'إ','ﺈ'=>'إ','ﺉ'=>'ئ','ﺊ'=>'ئ','ﺋ'=>'ئ','ﺌ'=>'ئ','ﺍ'=>'ا','ﺎ'=>'ا','ﺏ'=>'ب','ﺐ'=>'ب','ﺑ'=>'ب','ﺒ'=>'ب','ﺓ'=>'ة','ﺔ'=>'ة','ﺕ'=>'ت','ﺖ'=>'ت','ﺗ'=>'ت','ﺘ'=>'ت','ﺙ'=>'ث','ﺚ'=>'ث','ﺛ'=>'ث','ﺜ'=>'ث','ﺝ'=>'ج','ﺞ'=>'ج','ﺟ'=>'ج','ﺠ'=>'ج','ﺡ'=>'ح','ﺢ'=>'ح','ﺣ'=>'ح','ﺤ'=>'ح','ﺥ'=>'خ','ﺦ'=>'خ','ﺧ'=>'خ','ﺨ'=>'خ','ﺩ'=>'د','ﺪ'=>'د','ﺫ'=>'ذ','ﺬ'=>'ذ','ﺭ'=>'ر','ﺮ'=>'ر','ﺯ'=>'ز','ﺰ'=>'ز','ﺱ'=>'س','ﺲ'=>'س','ﺳ'=>'س','ﺴ'=>'س','ﺵ'=>'ش','ﺶ'=>'ش','ﺷ'=>'ش','ﺸ'=>'ش','ﺹ'=>'ص','ﺺ'=>'ص','ﺻ'=>'ص','ﺼ'=>'ص','ﺽ'=>'ض','ﺾ'=>'ض','ﺿ'=>'ض','ﻀ'=>'ض','ﻁ'=>'ط','ﻂ'=>'ط','ﻃ'=>'ط','ﻄ'=>'ط','ﻅ'=>'ظ','ﻆ'=>'ظ','ﻇ'=>'ظ','ﻈ'=>'ظ','ﻉ'=>'ع','ﻊ'=>'ع','ﻋ'=>'ع','ﻌ'=>'ع','ﻍ'=>'غ','ﻎ'=>'غ','ﻏ'=>'غ','ﻐ'=>'غ','ﻑ'=>'ف','ﻒ'=>'ف','ﻓ'=>'ف','ﻔ'=>'ف','ﻕ'=>'ق','ﻖ'=>'ق','ﻗ'=>'ق','ﻘ'=>'ق','ﻙ'=>'ك','ﻚ'=>'ك','ﻛ'=>'ك','ﻜ'=>'ك','ﻝ'=>'ل','ﻞ'=>'ل','ﻟ'=>'ل','ﻠ'=>'ل','ﻡ'=>'م','ﻢ'=>'م','ﻣ'=>'م','ﻤ'=>'م','ﻥ'=>'ن','ﻦ'=>'ن','ﻧ'=>'ن','ﻨ'=>'ن','ﻩ'=>'ه','ﻪ'=>'ه','ﻫ'=>'ه','ﻬ'=>'ه','ﻭ'=>'و','ﻮ'=>'و','ﻯ'=>'ى','ﻰ'=>'ى','ﻱ'=>'ي','ﻲ'=>'ي','ﻳ'=>'ي','ﻴ'=>'ي','ﻵ'=>'لآ','ﻶ'=>'لآ','ﻷ'=>'لأ','ﻸ'=>'لأ','ﻹ'=>'لإ','ﻺ'=>'لإ','ﻻ'=>'لا','ﻼ'=>'لا','!'=>'!','"'=>'"','#'=>'#','$'=>'$','%'=>'%','&'=>'&','''=>'\'','('=>'(',')'=>')','*'=>'*','+'=>'+',','=>',','-'=>'-','.'=>'.','/'=>'/','0'=>'0','1'=>'1','2'=>'2','3'=>'3','4'=>'4','5'=>'5','6'=>'6','7'=>'7','8'=>'8','9'=>'9',':'=>':',';'=>';','<'=>'<','='=>'=','>'=>'>','?'=>'?','@'=>'@','A'=>'A','B'=>'B','C'=>'C','D'=>'D','E'=>'E','F'=>'F','G'=>'G','H'=>'H','I'=>'I','J'=>'J','K'=>'K','L'=>'L','M'=>'M','N'=>'N','O'=>'O','P'=>'P','Q'=>'Q','R'=>'R','S'=>'S','T'=>'T','U'=>'U','V'=>'V','W'=>'W','X'=>'X','Y'=>'Y','Z'=>'Z','['=>'[','\'=>'\\',']'=>']','^'=>'^','_'=>'_','`'=>'`','a'=>'a','b'=>'b','c'=>'c','d'=>'d','e'=>'e','f'=>'f','g'=>'g','h'=>'h','i'=>'i','j'=>'j','k'=>'k','l'=>'l','m'=>'m','n'=>'n','o'=>'o','p'=>'p','q'=>'q','r'=>'r','s'=>'s','t'=>'t','u'=>'u','v'=>'v','w'=>'w','x'=>'x','y'=>'y','z'=>'z','{'=>'{','|'=>'|','}'=>'}','~'=>'~','⦅'=>'⦅','⦆'=>'⦆','。'=>'。','「'=>'「','」'=>'」','、'=>'、','・'=>'・','ヲ'=>'ヲ','ァ'=>'ァ','ィ'=>'ィ','ゥ'=>'ゥ','ェ'=>'ェ','ォ'=>'ォ','ャ'=>'ャ','ュ'=>'ュ','ョ'=>'ョ','ッ'=>'ッ','ー'=>'ー','ア'=>'ア','イ'=>'イ','ウ'=>'ウ','エ'=>'エ','オ'=>'オ','カ'=>'カ','キ'=>'キ','ク'=>'ク','ケ'=>'ケ','コ'=>'コ','サ'=>'サ','シ'=>'シ','ス'=>'ス','セ'=>'セ','ソ'=>'ソ','タ'=>'タ','チ'=>'チ','ツ'=>'ツ','テ'=>'テ','ト'=>'ト','ナ'=>'ナ','ニ'=>'ニ','ヌ'=>'ヌ','ネ'=>'ネ','ノ'=>'ノ','ハ'=>'ハ','ヒ'=>'ヒ','フ'=>'フ','ヘ'=>'ヘ','ホ'=>'ホ','マ'=>'マ','ミ'=>'ミ','ム'=>'ム','メ'=>'メ','モ'=>'モ','ヤ'=>'ヤ','ユ'=>'ユ','ヨ'=>'ヨ','ラ'=>'ラ','リ'=>'リ','ル'=>'ル','レ'=>'レ','ロ'=>'ロ','ワ'=>'ワ','ン'=>'ン','゙'=>'゙','゚'=>'゚','ᅠ'=>'ᅠ','ᄀ'=>'ᄀ','ᄁ'=>'ᄁ','ᆪ'=>'ᆪ','ᄂ'=>'ᄂ','ᆬ'=>'ᆬ','ᆭ'=>'ᆭ','ᄃ'=>'ᄃ','ᄄ'=>'ᄄ','ᄅ'=>'ᄅ','ᆰ'=>'ᆰ','ᆱ'=>'ᆱ','ᆲ'=>'ᆲ','ᆳ'=>'ᆳ','ᆴ'=>'ᆴ','ᆵ'=>'ᆵ','ᄚ'=>'ᄚ','ᄆ'=>'ᄆ','ᄇ'=>'ᄇ','ᄈ'=>'ᄈ','ᄡ'=>'ᄡ','ᄉ'=>'ᄉ','ᄊ'=>'ᄊ','ᄋ'=>'ᄋ','ᄌ'=>'ᄌ','ᄍ'=>'ᄍ','ᄎ'=>'ᄎ','ᄏ'=>'ᄏ','ᄐ'=>'ᄐ','ᄑ'=>'ᄑ','ᄒ'=>'ᄒ','ᅡ'=>'ᅡ','ᅢ'=>'ᅢ','ᅣ'=>'ᅣ','ᅤ'=>'ᅤ','ᅥ'=>'ᅥ','ᅦ'=>'ᅦ','ᅧ'=>'ᅧ','ᅨ'=>'ᅨ','ᅩ'=>'ᅩ','ᅪ'=>'ᅪ','ᅫ'=>'ᅫ','ᅬ'=>'ᅬ','ᅭ'=>'ᅭ','ᅮ'=>'ᅮ','ᅯ'=>'ᅯ','ᅰ'=>'ᅰ','ᅱ'=>'ᅱ','ᅲ'=>'ᅲ','ᅳ'=>'ᅳ','ᅴ'=>'ᅴ','ᅵ'=>'ᅵ','¢'=>'¢','£'=>'£','¬'=>'¬',' ̄'=>' ̄','¦'=>'¦','¥'=>'¥','₩'=>'₩','│'=>'│','←'=>'←','↑'=>'↑','→'=>'→','↓'=>'↓','■'=>'■','○'=>'○','𝅗𝅥'=>'𝅗𝅥','𝅘𝅥'=>'𝅘𝅥','𝅘𝅥𝅮'=>'𝅘𝅥𝅮','𝅘𝅥𝅯'=>'𝅘𝅥𝅯','𝅘𝅥𝅰'=>'𝅘𝅥𝅰','𝅘𝅥𝅱'=>'𝅘𝅥𝅱','𝅘𝅥𝅲'=>'𝅘𝅥𝅲','𝆹𝅥'=>'𝆹𝅥','𝆺𝅥'=>'𝆺𝅥','𝆹𝅥𝅮'=>'𝆹𝅥𝅮','𝆺𝅥𝅮'=>'𝆺𝅥𝅮','𝆹𝅥𝅯'=>'𝆹𝅥𝅯','𝆺𝅥𝅯'=>'𝆺𝅥𝅯','𝐀'=>'A','𝐁'=>'B','𝐂'=>'C','𝐃'=>'D','𝐄'=>'E','𝐅'=>'F','𝐆'=>'G','𝐇'=>'H','𝐈'=>'I','𝐉'=>'J','𝐊'=>'K','𝐋'=>'L','𝐌'=>'M','𝐍'=>'N','𝐎'=>'O','𝐏'=>'P','𝐐'=>'Q','𝐑'=>'R','𝐒'=>'S','𝐓'=>'T','𝐔'=>'U','𝐕'=>'V','𝐖'=>'W','𝐗'=>'X','𝐘'=>'Y','𝐙'=>'Z','𝐚'=>'a','𝐛'=>'b','𝐜'=>'c','𝐝'=>'d','𝐞'=>'e','𝐟'=>'f','𝐠'=>'g','𝐡'=>'h','𝐢'=>'i','𝐣'=>'j','𝐤'=>'k','𝐥'=>'l','𝐦'=>'m','𝐧'=>'n','𝐨'=>'o','𝐩'=>'p','𝐪'=>'q','𝐫'=>'r','𝐬'=>'s','𝐭'=>'t','𝐮'=>'u','𝐯'=>'v','𝐰'=>'w','𝐱'=>'x','𝐲'=>'y','𝐳'=>'z','𝐴'=>'A','𝐵'=>'B','𝐶'=>'C','𝐷'=>'D','𝐸'=>'E','𝐹'=>'F','𝐺'=>'G','𝐻'=>'H','𝐼'=>'I','𝐽'=>'J','𝐾'=>'K','𝐿'=>'L','𝑀'=>'M','𝑁'=>'N','𝑂'=>'O','𝑃'=>'P','𝑄'=>'Q','𝑅'=>'R','𝑆'=>'S','𝑇'=>'T','𝑈'=>'U','𝑉'=>'V','𝑊'=>'W','𝑋'=>'X','𝑌'=>'Y','𝑍'=>'Z','𝑎'=>'a','𝑏'=>'b','𝑐'=>'c','𝑑'=>'d','𝑒'=>'e','𝑓'=>'f','𝑔'=>'g','𝑖'=>'i','𝑗'=>'j','𝑘'=>'k','𝑙'=>'l','𝑚'=>'m','𝑛'=>'n','𝑜'=>'o','𝑝'=>'p','𝑞'=>'q','𝑟'=>'r','𝑠'=>'s','𝑡'=>'t','𝑢'=>'u','𝑣'=>'v','𝑤'=>'w','𝑥'=>'x','𝑦'=>'y','𝑧'=>'z','𝑨'=>'A','𝑩'=>'B','𝑪'=>'C','𝑫'=>'D','𝑬'=>'E','𝑭'=>'F','𝑮'=>'G','𝑯'=>'H','𝑰'=>'I','𝑱'=>'J','𝑲'=>'K','𝑳'=>'L','𝑴'=>'M','𝑵'=>'N','𝑶'=>'O','𝑷'=>'P','𝑸'=>'Q','𝑹'=>'R','𝑺'=>'S','𝑻'=>'T','𝑼'=>'U','𝑽'=>'V','𝑾'=>'W','𝑿'=>'X','𝒀'=>'Y','𝒁'=>'Z','𝒂'=>'a','𝒃'=>'b','𝒄'=>'c','𝒅'=>'d','𝒆'=>'e','𝒇'=>'f','𝒈'=>'g','𝒉'=>'h','𝒊'=>'i','𝒋'=>'j','𝒌'=>'k','𝒍'=>'l','𝒎'=>'m','𝒏'=>'n','𝒐'=>'o','𝒑'=>'p','𝒒'=>'q','𝒓'=>'r','𝒔'=>'s','𝒕'=>'t','𝒖'=>'u','𝒗'=>'v','𝒘'=>'w','𝒙'=>'x','𝒚'=>'y','𝒛'=>'z','𝒜'=>'A','𝒞'=>'C','𝒟'=>'D','𝒢'=>'G','𝒥'=>'J','𝒦'=>'K','𝒩'=>'N','𝒪'=>'O','𝒫'=>'P','𝒬'=>'Q','𝒮'=>'S','𝒯'=>'T','𝒰'=>'U','𝒱'=>'V','𝒲'=>'W','𝒳'=>'X','𝒴'=>'Y','𝒵'=>'Z','𝒶'=>'a','𝒷'=>'b','𝒸'=>'c','𝒹'=>'d','𝒻'=>'f','𝒽'=>'h','𝒾'=>'i','𝒿'=>'j','𝓀'=>'k','𝓁'=>'l','𝓂'=>'m','𝓃'=>'n','𝓅'=>'p','𝓆'=>'q','𝓇'=>'r','𝓈'=>'s','𝓉'=>'t','𝓊'=>'u','𝓋'=>'v','𝓌'=>'w','𝓍'=>'x','𝓎'=>'y','𝓏'=>'z','𝓐'=>'A','𝓑'=>'B','𝓒'=>'C','𝓓'=>'D','𝓔'=>'E','𝓕'=>'F','𝓖'=>'G','𝓗'=>'H','𝓘'=>'I','𝓙'=>'J','𝓚'=>'K','𝓛'=>'L','𝓜'=>'M','𝓝'=>'N','𝓞'=>'O','𝓟'=>'P','𝓠'=>'Q','𝓡'=>'R','𝓢'=>'S','𝓣'=>'T','𝓤'=>'U','𝓥'=>'V','𝓦'=>'W','𝓧'=>'X','𝓨'=>'Y','𝓩'=>'Z','𝓪'=>'a','𝓫'=>'b','𝓬'=>'c','𝓭'=>'d','𝓮'=>'e','𝓯'=>'f','𝓰'=>'g','𝓱'=>'h','𝓲'=>'i','𝓳'=>'j','𝓴'=>'k','𝓵'=>'l','𝓶'=>'m','𝓷'=>'n','𝓸'=>'o','𝓹'=>'p','𝓺'=>'q','𝓻'=>'r','𝓼'=>'s','𝓽'=>'t','𝓾'=>'u','𝓿'=>'v','𝔀'=>'w','𝔁'=>'x','𝔂'=>'y','𝔃'=>'z','𝔄'=>'A','𝔅'=>'B','𝔇'=>'D','𝔈'=>'E','𝔉'=>'F','𝔊'=>'G','𝔍'=>'J','𝔎'=>'K','𝔏'=>'L','𝔐'=>'M','𝔑'=>'N','𝔒'=>'O','𝔓'=>'P','𝔔'=>'Q','𝔖'=>'S','𝔗'=>'T','𝔘'=>'U','𝔙'=>'V','𝔚'=>'W','𝔛'=>'X','𝔜'=>'Y','𝔞'=>'a','𝔟'=>'b','𝔠'=>'c','𝔡'=>'d','𝔢'=>'e','𝔣'=>'f','𝔤'=>'g','𝔥'=>'h','𝔦'=>'i','𝔧'=>'j','𝔨'=>'k','𝔩'=>'l','𝔪'=>'m','𝔫'=>'n','𝔬'=>'o','𝔭'=>'p','𝔮'=>'q','𝔯'=>'r','𝔰'=>'s','𝔱'=>'t','𝔲'=>'u','𝔳'=>'v','𝔴'=>'w','𝔵'=>'x','𝔶'=>'y','𝔷'=>'z','𝔸'=>'A','𝔹'=>'B','𝔻'=>'D','𝔼'=>'E','𝔽'=>'F','𝔾'=>'G','𝕀'=>'I','𝕁'=>'J','𝕂'=>'K','𝕃'=>'L','𝕄'=>'M','𝕆'=>'O','𝕊'=>'S','𝕋'=>'T','𝕌'=>'U','𝕍'=>'V','𝕎'=>'W','𝕏'=>'X','𝕐'=>'Y','𝕒'=>'a','𝕓'=>'b','𝕔'=>'c','𝕕'=>'d','𝕖'=>'e','𝕗'=>'f','𝕘'=>'g','𝕙'=>'h','𝕚'=>'i','𝕛'=>'j','𝕜'=>'k','𝕝'=>'l','𝕞'=>'m','𝕟'=>'n','𝕠'=>'o','𝕡'=>'p','𝕢'=>'q','𝕣'=>'r','𝕤'=>'s','𝕥'=>'t','𝕦'=>'u','𝕧'=>'v','𝕨'=>'w','𝕩'=>'x','𝕪'=>'y','𝕫'=>'z','𝕬'=>'A','𝕭'=>'B','𝕮'=>'C','𝕯'=>'D','𝕰'=>'E','𝕱'=>'F','𝕲'=>'G','𝕳'=>'H','𝕴'=>'I','𝕵'=>'J','𝕶'=>'K','𝕷'=>'L','𝕸'=>'M','𝕹'=>'N','𝕺'=>'O','𝕻'=>'P','𝕼'=>'Q','𝕽'=>'R','𝕾'=>'S','𝕿'=>'T','𝖀'=>'U','𝖁'=>'V','𝖂'=>'W','𝖃'=>'X','𝖄'=>'Y','𝖅'=>'Z','𝖆'=>'a','𝖇'=>'b','𝖈'=>'c','𝖉'=>'d','𝖊'=>'e','𝖋'=>'f','𝖌'=>'g','𝖍'=>'h','𝖎'=>'i','𝖏'=>'j','𝖐'=>'k','𝖑'=>'l','𝖒'=>'m','𝖓'=>'n','𝖔'=>'o','𝖕'=>'p','𝖖'=>'q','𝖗'=>'r','𝖘'=>'s','𝖙'=>'t','𝖚'=>'u','𝖛'=>'v','𝖜'=>'w','𝖝'=>'x','𝖞'=>'y','𝖟'=>'z','𝖠'=>'A','𝖡'=>'B','𝖢'=>'C','𝖣'=>'D','𝖤'=>'E','𝖥'=>'F','𝖦'=>'G','𝖧'=>'H','𝖨'=>'I','𝖩'=>'J','𝖪'=>'K','𝖫'=>'L','𝖬'=>'M','𝖭'=>'N','𝖮'=>'O','𝖯'=>'P','𝖰'=>'Q','𝖱'=>'R','𝖲'=>'S','𝖳'=>'T','𝖴'=>'U','𝖵'=>'V','𝖶'=>'W','𝖷'=>'X','𝖸'=>'Y','𝖹'=>'Z','𝖺'=>'a','𝖻'=>'b','𝖼'=>'c','𝖽'=>'d','𝖾'=>'e','𝖿'=>'f','𝗀'=>'g','𝗁'=>'h','𝗂'=>'i','𝗃'=>'j','𝗄'=>'k','𝗅'=>'l','𝗆'=>'m','𝗇'=>'n','𝗈'=>'o','𝗉'=>'p','𝗊'=>'q','𝗋'=>'r','𝗌'=>'s','𝗍'=>'t','𝗎'=>'u','𝗏'=>'v','𝗐'=>'w','𝗑'=>'x','𝗒'=>'y','𝗓'=>'z','𝗔'=>'A','𝗕'=>'B','𝗖'=>'C','𝗗'=>'D','𝗘'=>'E','𝗙'=>'F','𝗚'=>'G','𝗛'=>'H','𝗜'=>'I','𝗝'=>'J','𝗞'=>'K','𝗟'=>'L','𝗠'=>'M','𝗡'=>'N','𝗢'=>'O','𝗣'=>'P','𝗤'=>'Q','𝗥'=>'R','𝗦'=>'S','𝗧'=>'T','𝗨'=>'U','𝗩'=>'V','𝗪'=>'W','𝗫'=>'X','𝗬'=>'Y','𝗭'=>'Z','𝗮'=>'a','𝗯'=>'b','𝗰'=>'c','𝗱'=>'d','𝗲'=>'e','𝗳'=>'f','𝗴'=>'g','𝗵'=>'h','𝗶'=>'i','𝗷'=>'j','𝗸'=>'k','𝗹'=>'l','𝗺'=>'m','𝗻'=>'n','𝗼'=>'o','𝗽'=>'p','𝗾'=>'q','𝗿'=>'r','𝘀'=>'s','𝘁'=>'t','𝘂'=>'u','𝘃'=>'v','𝘄'=>'w','𝘅'=>'x','𝘆'=>'y','𝘇'=>'z','𝘈'=>'A','𝘉'=>'B','𝘊'=>'C','𝘋'=>'D','𝘌'=>'E','𝘍'=>'F','𝘎'=>'G','𝘏'=>'H','𝘐'=>'I','𝘑'=>'J','𝘒'=>'K','𝘓'=>'L','𝘔'=>'M','𝘕'=>'N','𝘖'=>'O','𝘗'=>'P','𝘘'=>'Q','𝘙'=>'R','𝘚'=>'S','𝘛'=>'T','𝘜'=>'U','𝘝'=>'V','𝘞'=>'W','𝘟'=>'X','𝘠'=>'Y','𝘡'=>'Z','𝘢'=>'a','𝘣'=>'b','𝘤'=>'c','𝘥'=>'d','𝘦'=>'e','𝘧'=>'f','𝘨'=>'g','𝘩'=>'h','𝘪'=>'i','𝘫'=>'j','𝘬'=>'k','𝘭'=>'l','𝘮'=>'m','𝘯'=>'n','𝘰'=>'o','𝘱'=>'p','𝘲'=>'q','𝘳'=>'r','𝘴'=>'s','𝘵'=>'t','𝘶'=>'u','𝘷'=>'v','𝘸'=>'w','𝘹'=>'x','𝘺'=>'y','𝘻'=>'z','𝘼'=>'A','𝘽'=>'B','𝘾'=>'C','𝘿'=>'D','𝙀'=>'E','𝙁'=>'F','𝙂'=>'G','𝙃'=>'H','𝙄'=>'I','𝙅'=>'J','𝙆'=>'K','𝙇'=>'L','𝙈'=>'M','𝙉'=>'N','𝙊'=>'O','𝙋'=>'P','𝙌'=>'Q','𝙍'=>'R','𝙎'=>'S','𝙏'=>'T','𝙐'=>'U','𝙑'=>'V','𝙒'=>'W','𝙓'=>'X','𝙔'=>'Y','𝙕'=>'Z','𝙖'=>'a','𝙗'=>'b','𝙘'=>'c','𝙙'=>'d','𝙚'=>'e','𝙛'=>'f','𝙜'=>'g','𝙝'=>'h','𝙞'=>'i','𝙟'=>'j','𝙠'=>'k','𝙡'=>'l','𝙢'=>'m','𝙣'=>'n','𝙤'=>'o','𝙥'=>'p','𝙦'=>'q','𝙧'=>'r','𝙨'=>'s','𝙩'=>'t','𝙪'=>'u','𝙫'=>'v','𝙬'=>'w','𝙭'=>'x','𝙮'=>'y','𝙯'=>'z','𝙰'=>'A','𝙱'=>'B','𝙲'=>'C','𝙳'=>'D','𝙴'=>'E','𝙵'=>'F','𝙶'=>'G','𝙷'=>'H','𝙸'=>'I','𝙹'=>'J','𝙺'=>'K','𝙻'=>'L','𝙼'=>'M','𝙽'=>'N','𝙾'=>'O','𝙿'=>'P','𝚀'=>'Q','𝚁'=>'R','𝚂'=>'S','𝚃'=>'T','𝚄'=>'U','𝚅'=>'V','𝚆'=>'W','𝚇'=>'X','𝚈'=>'Y','𝚉'=>'Z','𝚊'=>'a','𝚋'=>'b','𝚌'=>'c','𝚍'=>'d','𝚎'=>'e','𝚏'=>'f','𝚐'=>'g','𝚑'=>'h','𝚒'=>'i','𝚓'=>'j','𝚔'=>'k','𝚕'=>'l','𝚖'=>'m','𝚗'=>'n','𝚘'=>'o','𝚙'=>'p','𝚚'=>'q','𝚛'=>'r','𝚜'=>'s','𝚝'=>'t','𝚞'=>'u','𝚟'=>'v','𝚠'=>'w','𝚡'=>'x','𝚢'=>'y','𝚣'=>'z','𝚤'=>'ı','𝚥'=>'ȷ','𝚨'=>'Α','𝚩'=>'Β','𝚪'=>'Γ','𝚫'=>'Δ','𝚬'=>'Ε','𝚭'=>'Ζ','𝚮'=>'Η','𝚯'=>'Θ','𝚰'=>'Ι','𝚱'=>'Κ','𝚲'=>'Λ','𝚳'=>'Μ','𝚴'=>'Ν','𝚵'=>'Ξ','𝚶'=>'Ο','𝚷'=>'Π','𝚸'=>'Ρ','𝚹'=>'Θ','𝚺'=>'Σ','𝚻'=>'Τ','𝚼'=>'Υ','𝚽'=>'Φ','𝚾'=>'Χ','𝚿'=>'Ψ','𝛀'=>'Ω','𝛁'=>'∇','𝛂'=>'α','𝛃'=>'β','𝛄'=>'γ','𝛅'=>'δ','𝛆'=>'ε','𝛇'=>'ζ','𝛈'=>'η','𝛉'=>'θ','𝛊'=>'ι','𝛋'=>'κ','𝛌'=>'λ','𝛍'=>'μ','𝛎'=>'ν','𝛏'=>'ξ','𝛐'=>'ο','𝛑'=>'π','𝛒'=>'ρ','𝛓'=>'ς','𝛔'=>'σ','𝛕'=>'τ','𝛖'=>'υ','𝛗'=>'φ','𝛘'=>'χ','𝛙'=>'ψ','𝛚'=>'ω','𝛛'=>'∂','𝛜'=>'ε','𝛝'=>'θ','𝛞'=>'κ','𝛟'=>'φ','𝛠'=>'ρ','𝛡'=>'π','𝛢'=>'Α','𝛣'=>'Β','𝛤'=>'Γ','𝛥'=>'Δ','𝛦'=>'Ε','𝛧'=>'Ζ','𝛨'=>'Η','𝛩'=>'Θ','𝛪'=>'Ι','𝛫'=>'Κ','𝛬'=>'Λ','𝛭'=>'Μ','𝛮'=>'Ν','𝛯'=>'Ξ','𝛰'=>'Ο','𝛱'=>'Π','𝛲'=>'Ρ','𝛳'=>'Θ','𝛴'=>'Σ','𝛵'=>'Τ','𝛶'=>'Υ','𝛷'=>'Φ','𝛸'=>'Χ','𝛹'=>'Ψ','𝛺'=>'Ω','𝛻'=>'∇','𝛼'=>'α','𝛽'=>'β','𝛾'=>'γ','𝛿'=>'δ','𝜀'=>'ε','𝜁'=>'ζ','𝜂'=>'η','𝜃'=>'θ','𝜄'=>'ι','𝜅'=>'κ','𝜆'=>'λ','𝜇'=>'μ','𝜈'=>'ν','𝜉'=>'ξ','𝜊'=>'ο','𝜋'=>'π','𝜌'=>'ρ','𝜍'=>'ς','𝜎'=>'σ','𝜏'=>'τ','𝜐'=>'υ','𝜑'=>'φ','𝜒'=>'χ','𝜓'=>'ψ','𝜔'=>'ω','𝜕'=>'∂','𝜖'=>'ε','𝜗'=>'θ','𝜘'=>'κ','𝜙'=>'φ','𝜚'=>'ρ','𝜛'=>'π','𝜜'=>'Α','𝜝'=>'Β','𝜞'=>'Γ','𝜟'=>'Δ','𝜠'=>'Ε','𝜡'=>'Ζ','𝜢'=>'Η','𝜣'=>'Θ','𝜤'=>'Ι','𝜥'=>'Κ','𝜦'=>'Λ','𝜧'=>'Μ','𝜨'=>'Ν','𝜩'=>'Ξ','𝜪'=>'Ο','𝜫'=>'Π','𝜬'=>'Ρ','𝜭'=>'Θ','𝜮'=>'Σ','𝜯'=>'Τ','𝜰'=>'Υ','𝜱'=>'Φ','𝜲'=>'Χ','𝜳'=>'Ψ','𝜴'=>'Ω','𝜵'=>'∇','𝜶'=>'α','𝜷'=>'β','𝜸'=>'γ','𝜹'=>'δ','𝜺'=>'ε','𝜻'=>'ζ','𝜼'=>'η','𝜽'=>'θ','𝜾'=>'ι','𝜿'=>'κ','𝝀'=>'λ','𝝁'=>'μ','𝝂'=>'ν','𝝃'=>'ξ','𝝄'=>'ο','𝝅'=>'π','𝝆'=>'ρ','𝝇'=>'ς','𝝈'=>'σ','𝝉'=>'τ','𝝊'=>'υ','𝝋'=>'φ','𝝌'=>'χ','𝝍'=>'ψ','𝝎'=>'ω','𝝏'=>'∂','𝝐'=>'ε','𝝑'=>'θ','𝝒'=>'κ','𝝓'=>'φ','𝝔'=>'ρ','𝝕'=>'π','𝝖'=>'Α','𝝗'=>'Β','𝝘'=>'Γ','𝝙'=>'Δ','𝝚'=>'Ε','𝝛'=>'Ζ','𝝜'=>'Η','𝝝'=>'Θ','𝝞'=>'Ι','𝝟'=>'Κ','𝝠'=>'Λ','𝝡'=>'Μ','𝝢'=>'Ν','𝝣'=>'Ξ','𝝤'=>'Ο','𝝥'=>'Π','𝝦'=>'Ρ','𝝧'=>'Θ','𝝨'=>'Σ','𝝩'=>'Τ','𝝪'=>'Υ','𝝫'=>'Φ','𝝬'=>'Χ','𝝭'=>'Ψ','𝝮'=>'Ω','𝝯'=>'∇','𝝰'=>'α','𝝱'=>'β','𝝲'=>'γ','𝝳'=>'δ','𝝴'=>'ε','𝝵'=>'ζ','𝝶'=>'η','𝝷'=>'θ','𝝸'=>'ι','𝝹'=>'κ','𝝺'=>'λ','𝝻'=>'μ','𝝼'=>'ν','𝝽'=>'ξ','𝝾'=>'ο','𝝿'=>'π','𝞀'=>'ρ','𝞁'=>'ς','𝞂'=>'σ','𝞃'=>'τ','𝞄'=>'υ','𝞅'=>'φ','𝞆'=>'χ','𝞇'=>'ψ','𝞈'=>'ω','𝞉'=>'∂','𝞊'=>'ε','𝞋'=>'θ','𝞌'=>'κ','𝞍'=>'φ','𝞎'=>'ρ','𝞏'=>'π','𝞐'=>'Α','𝞑'=>'Β','𝞒'=>'Γ','𝞓'=>'Δ','𝞔'=>'Ε','𝞕'=>'Ζ','𝞖'=>'Η','𝞗'=>'Θ','𝞘'=>'Ι','𝞙'=>'Κ','𝞚'=>'Λ','𝞛'=>'Μ','𝞜'=>'Ν','𝞝'=>'Ξ','𝞞'=>'Ο','𝞟'=>'Π','𝞠'=>'Ρ','𝞡'=>'Θ','𝞢'=>'Σ','𝞣'=>'Τ','𝞤'=>'Υ','𝞥'=>'Φ','𝞦'=>'Χ','𝞧'=>'Ψ','𝞨'=>'Ω','𝞩'=>'∇','𝞪'=>'α','𝞫'=>'β','𝞬'=>'γ','𝞭'=>'δ','𝞮'=>'ε','𝞯'=>'ζ','𝞰'=>'η','𝞱'=>'θ','𝞲'=>'ι','𝞳'=>'κ','𝞴'=>'λ','𝞵'=>'μ','𝞶'=>'ν','𝞷'=>'ξ','𝞸'=>'ο','𝞹'=>'π','𝞺'=>'ρ','𝞻'=>'ς','𝞼'=>'σ','𝞽'=>'τ','𝞾'=>'υ','𝞿'=>'φ','𝟀'=>'χ','𝟁'=>'ψ','𝟂'=>'ω','𝟃'=>'∂','𝟄'=>'ε','𝟅'=>'θ','𝟆'=>'κ','𝟇'=>'φ','𝟈'=>'ρ','𝟉'=>'π','𝟊'=>'Ϝ','𝟋'=>'ϝ','𝟎'=>'0','𝟏'=>'1','𝟐'=>'2','𝟑'=>'3','𝟒'=>'4','𝟓'=>'5','𝟔'=>'6','𝟕'=>'7','𝟖'=>'8','𝟗'=>'9','𝟘'=>'0','𝟙'=>'1','𝟚'=>'2','𝟛'=>'3','𝟜'=>'4','𝟝'=>'5','𝟞'=>'6','𝟟'=>'7','𝟠'=>'8','𝟡'=>'9','𝟢'=>'0','𝟣'=>'1','𝟤'=>'2','𝟥'=>'3','𝟦'=>'4','𝟧'=>'5','𝟨'=>'6','𝟩'=>'7','𝟪'=>'8','𝟫'=>'9','𝟬'=>'0','𝟭'=>'1','𝟮'=>'2','𝟯'=>'3','𝟰'=>'4','𝟱'=>'5','𝟲'=>'6','𝟳'=>'7','𝟴'=>'8','𝟵'=>'9','𝟶'=>'0','𝟷'=>'1','𝟸'=>'2','𝟹'=>'3','𝟺'=>'4','𝟻'=>'5','𝟼'=>'6','𝟽'=>'7','𝟾'=>'8','𝟿'=>'9','丽'=>'丽','丸'=>'丸','乁'=>'乁','𠄢'=>'𠄢','你'=>'你','侮'=>'侮','侻'=>'侻','倂'=>'倂','偺'=>'偺','備'=>'備','僧'=>'僧','像'=>'像','㒞'=>'㒞','𠘺'=>'𠘺','免'=>'免','兔'=>'兔','兤'=>'兤','具'=>'具','𠔜'=>'𠔜','㒹'=>'㒹','內'=>'內','再'=>'再','𠕋'=>'𠕋','冗'=>'冗','冤'=>'冤','仌'=>'仌','冬'=>'冬','况'=>'况','𩇟'=>'𩇟','凵'=>'凵','刃'=>'刃','㓟'=>'㓟','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','㔕'=>'㔕','勇'=>'勇','勉'=>'勉','勤'=>'勤','勺'=>'勺','包'=>'包','匆'=>'匆','北'=>'北','卉'=>'卉','卑'=>'卑','博'=>'博','即'=>'即','卽'=>'卽','卿'=>'卿','卿'=>'卿','卿'=>'卿','𠨬'=>'𠨬','灰'=>'灰','及'=>'及','叟'=>'叟','𠭣'=>'𠭣','叫'=>'叫','叱'=>'叱','吆'=>'吆','咞'=>'咞','吸'=>'吸','呈'=>'呈','周'=>'周','咢'=>'咢','哶'=>'哶','唐'=>'唐','啓'=>'啓','啣'=>'啣','善'=>'善','善'=>'善','喙'=>'喙','喫'=>'喫','喳'=>'喳','嗂'=>'嗂','圖'=>'圖','嘆'=>'嘆','圗'=>'圗','噑'=>'噑','噴'=>'噴','切'=>'切','壮'=>'壮','城'=>'城','埴'=>'埴','堍'=>'堍','型'=>'型','堲'=>'堲','報'=>'報','墬'=>'墬','𡓤'=>'𡓤','売'=>'売','壷'=>'壷','夆'=>'夆','多'=>'多','夢'=>'夢','奢'=>'奢','𡚨'=>'𡚨','𡛪'=>'𡛪','姬'=>'姬','娛'=>'娛','娧'=>'娧','姘'=>'姘','婦'=>'婦','㛮'=>'㛮','㛼'=>'㛼','嬈'=>'嬈','嬾'=>'嬾','嬾'=>'嬾','𡧈'=>'𡧈','寃'=>'寃','寘'=>'寘','寧'=>'寧','寳'=>'寳','𡬘'=>'𡬘','寿'=>'寿','将'=>'将','当'=>'当','尢'=>'尢','㞁'=>'㞁','屠'=>'屠','屮'=>'屮','峀'=>'峀','岍'=>'岍','𡷤'=>'𡷤','嵃'=>'嵃','𡷦'=>'𡷦','嵮'=>'嵮','嵫'=>'嵫','嵼'=>'嵼','巡'=>'巡','巢'=>'巢','㠯'=>'㠯','巽'=>'巽','帨'=>'帨','帽'=>'帽','幩'=>'幩','㡢'=>'㡢','𢆃'=>'𢆃','㡼'=>'㡼','庰'=>'庰','庳'=>'庳','庶'=>'庶','廊'=>'廊','𪎒'=>'𪎒','廾'=>'廾','𢌱'=>'𢌱','𢌱'=>'𢌱','舁'=>'舁','弢'=>'弢','弢'=>'弢','㣇'=>'㣇','𣊸'=>'𣊸','𦇚'=>'𦇚','形'=>'形','彫'=>'彫','㣣'=>'㣣','徚'=>'徚','忍'=>'忍','志'=>'志','忹'=>'忹','悁'=>'悁','㤺'=>'㤺','㤜'=>'㤜','悔'=>'悔','𢛔'=>'𢛔','惇'=>'惇','慈'=>'慈','慌'=>'慌','慎'=>'慎','慌'=>'慌','慺'=>'慺','憎'=>'憎','憲'=>'憲','憤'=>'憤','憯'=>'憯','懞'=>'懞','懲'=>'懲','懶'=>'懶','成'=>'成','戛'=>'戛','扝'=>'扝','抱'=>'抱','拔'=>'拔','捐'=>'捐','𢬌'=>'𢬌','挽'=>'挽','拼'=>'拼','捨'=>'捨','掃'=>'掃','揤'=>'揤','𢯱'=>'𢯱','搢'=>'搢','揅'=>'揅','掩'=>'掩','㨮'=>'㨮','摩'=>'摩','摾'=>'摾','撝'=>'撝','摷'=>'摷','㩬'=>'㩬','敏'=>'敏','敬'=>'敬','𣀊'=>'𣀊','旣'=>'旣','書'=>'書','晉'=>'晉','㬙'=>'㬙','暑'=>'暑','㬈'=>'㬈','㫤'=>'㫤','冒'=>'冒','冕'=>'冕','最'=>'最','暜'=>'暜','肭'=>'肭','䏙'=>'䏙','朗'=>'朗','望'=>'望','朡'=>'朡','杞'=>'杞','杓'=>'杓','𣏃'=>'𣏃','㭉'=>'㭉','柺'=>'柺','枅'=>'枅','桒'=>'桒','梅'=>'梅','𣑭'=>'𣑭','梎'=>'梎','栟'=>'栟','椔'=>'椔','㮝'=>'㮝','楂'=>'楂','榣'=>'榣','槪'=>'槪','檨'=>'檨','𣚣'=>'𣚣','櫛'=>'櫛','㰘'=>'㰘','次'=>'次','𣢧'=>'𣢧','歔'=>'歔','㱎'=>'㱎','歲'=>'歲','殟'=>'殟','殺'=>'殺','殻'=>'殻','𣪍'=>'𣪍','𡴋'=>'𡴋','𣫺'=>'𣫺','汎'=>'汎','𣲼'=>'𣲼','沿'=>'沿','泍'=>'泍','汧'=>'汧','洖'=>'洖','派'=>'派','海'=>'海','流'=>'流','浩'=>'浩','浸'=>'浸','涅'=>'涅','𣴞'=>'𣴞','洴'=>'洴','港'=>'港','湮'=>'湮','㴳'=>'㴳','滋'=>'滋','滇'=>'滇','𣻑'=>'𣻑','淹'=>'淹','潮'=>'潮','𣽞'=>'𣽞','𣾎'=>'𣾎','濆'=>'濆','瀹'=>'瀹','瀞'=>'瀞','瀛'=>'瀛','㶖'=>'㶖','灊'=>'灊','災'=>'災','灷'=>'灷','炭'=>'炭','𠔥'=>'𠔥','煅'=>'煅','𤉣'=>'𤉣','熜'=>'熜','𤎫'=>'𤎫','爨'=>'爨','爵'=>'爵','牐'=>'牐','𤘈'=>'𤘈','犀'=>'犀','犕'=>'犕','𤜵'=>'𤜵','𤠔'=>'𤠔','獺'=>'獺','王'=>'王','㺬'=>'㺬','玥'=>'玥','㺸'=>'㺸','㺸'=>'㺸','瑇'=>'瑇','瑜'=>'瑜','瑱'=>'瑱','璅'=>'璅','瓊'=>'瓊','㼛'=>'㼛','甤'=>'甤','𤰶'=>'𤰶','甾'=>'甾','𤲒'=>'𤲒','異'=>'異','𢆟'=>'𢆟','瘐'=>'瘐','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'𥁄','㿼'=>'㿼','䀈'=>'䀈','直'=>'直','𥃳'=>'𥃳','𥃲'=>'𥃲','𥄙'=>'𥄙','𥄳'=>'𥄳','眞'=>'眞','真'=>'真','真'=>'真','睊'=>'睊','䀹'=>'䀹','瞋'=>'瞋','䁆'=>'䁆','䂖'=>'䂖','𥐝'=>'𥐝','硎'=>'硎','碌'=>'碌','磌'=>'磌','䃣'=>'䃣','𥘦'=>'𥘦','祖'=>'祖','𥚚'=>'𥚚','𥛅'=>'𥛅','福'=>'福','秫'=>'秫','䄯'=>'䄯','穀'=>'穀','穊'=>'穊','穏'=>'穏','𥥼'=>'𥥼','𥪧'=>'𥪧','𥪧'=>'𥪧','竮'=>'竮','䈂'=>'䈂','𥮫'=>'𥮫','篆'=>'篆','築'=>'築','䈧'=>'䈧','𥲀'=>'𥲀','糒'=>'糒','䊠'=>'䊠','糨'=>'糨','糣'=>'糣','紀'=>'紀','𥾆'=>'𥾆','絣'=>'絣','䌁'=>'䌁','緇'=>'緇','縂'=>'縂','繅'=>'繅','䌴'=>'䌴','𦈨'=>'𦈨','𦉇'=>'𦉇','䍙'=>'䍙','𦋙'=>'𦋙','罺'=>'罺','𦌾'=>'𦌾','羕'=>'羕','翺'=>'翺','者'=>'者','𦓚'=>'𦓚','𦔣'=>'𦔣','聠'=>'聠','𦖨'=>'𦖨','聰'=>'聰','𣍟'=>'𣍟','䏕'=>'䏕','育'=>'育','脃'=>'脃','䐋'=>'䐋','脾'=>'脾','媵'=>'媵','𦞧'=>'𦞧','𦞵'=>'𦞵','𣎓'=>'𣎓','𣎜'=>'𣎜','舁'=>'舁','舄'=>'舄','辞'=>'辞','䑫'=>'䑫','芑'=>'芑','芋'=>'芋','芝'=>'芝','劳'=>'劳','花'=>'花','芳'=>'芳','芽'=>'芽','苦'=>'苦','𦬼'=>'𦬼','若'=>'若','茝'=>'茝','荣'=>'荣','莭'=>'莭','茣'=>'茣','莽'=>'莽','菧'=>'菧','著'=>'著','荓'=>'荓','菊'=>'菊','菌'=>'菌','菜'=>'菜','𦰶'=>'𦰶','𦵫'=>'𦵫','𦳕'=>'𦳕','䔫'=>'䔫','蓱'=>'蓱','蓳'=>'蓳','蔖'=>'蔖','𧏊'=>'𧏊','蕤'=>'蕤','𦼬'=>'𦼬','䕝'=>'䕝','䕡'=>'䕡','𦾱'=>'𦾱','𧃒'=>'𧃒','䕫'=>'䕫','虐'=>'虐','虜'=>'虜','虧'=>'虧','虩'=>'虩','蚩'=>'蚩','蚈'=>'蚈','蜎'=>'蜎','蛢'=>'蛢','蝹'=>'蝹','蜨'=>'蜨','蝫'=>'蝫','螆'=>'螆','䗗'=>'䗗','蟡'=>'蟡','蠁'=>'蠁','䗹'=>'䗹','衠'=>'衠','衣'=>'衣','𧙧'=>'𧙧','裗'=>'裗','裞'=>'裞','䘵'=>'䘵','裺'=>'裺','㒻'=>'㒻','𧢮'=>'𧢮','𧥦'=>'𧥦','䚾'=>'䚾','䛇'=>'䛇','誠'=>'誠','諭'=>'諭','變'=>'變','豕'=>'豕','𧲨'=>'𧲨','貫'=>'貫','賁'=>'賁','贛'=>'贛','起'=>'起','𧼯'=>'𧼯','𠠄'=>'𠠄','跋'=>'跋','趼'=>'趼','跰'=>'跰','𠣞'=>'𠣞','軔'=>'軔','輸'=>'輸','𨗒'=>'𨗒','𨗭'=>'𨗭','邔'=>'邔','郱'=>'郱','鄑'=>'鄑','𨜮'=>'𨜮','鄛'=>'鄛','鈸'=>'鈸','鋗'=>'鋗','鋘'=>'鋘','鉼'=>'鉼','鏹'=>'鏹','鐕'=>'鐕','𨯺'=>'𨯺','開'=>'開','䦕'=>'䦕','閷'=>'閷','𨵷'=>'𨵷','䧦'=>'䧦','雃'=>'雃','嶲'=>'嶲','霣'=>'霣','𩅅'=>'𩅅','𩈚'=>'𩈚','䩮'=>'䩮','䩶'=>'䩶','韠'=>'韠','𩐊'=>'𩐊','䪲'=>'䪲','𩒖'=>'𩒖','頋'=>'頋','頋'=>'頋','頩'=>'頩','𩖶'=>'𩖶','飢'=>'飢','䬳'=>'䬳','餩'=>'餩','馧'=>'馧','駂'=>'駂','駾'=>'駾','䯎'=>'䯎','𩬰'=>'𩬰','鬒'=>'鬒','鱀'=>'鱀','鳽'=>'鳽','䳎'=>'䳎','䳭'=>'䳭','鵧'=>'鵧','𪃎'=>'𪃎','䳸'=>'䳸','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','麻'=>'麻','䵖'=>'䵖','黹'=>'黹','黾'=>'黾','鼅'=>'鼅','鼏'=>'鼏','鼖'=>'鼖','鼻'=>'鼻','𪘀'=>'𪘀');
\ No newline at end of file +$GLOBALS['utf_compatibility_decomp']=array(' '=>' ','¨'=>' ̈','ª'=>'a','¯'=>' ̄','²'=>'2','³'=>'3','´'=>' ́','µ'=>'μ','¸'=>' ̧','¹'=>'1','º'=>'o','¼'=>'1⁄4','½'=>'1⁄2','¾'=>'3⁄4','À'=>'À','Á'=>'Á','Â'=>'Â','Ã'=>'Ã','Ä'=>'Ä','Å'=>'Å','Ç'=>'Ç','È'=>'È','É'=>'É','Ê'=>'Ê','Ë'=>'Ë','Ì'=>'Ì','Í'=>'Í','Î'=>'Î','Ï'=>'Ï','Ñ'=>'Ñ','Ò'=>'Ò','Ó'=>'Ó','Ô'=>'Ô','Õ'=>'Õ','Ö'=>'Ö','Ù'=>'Ù','Ú'=>'Ú','Û'=>'Û','Ü'=>'Ü','Ý'=>'Ý','à'=>'à','á'=>'á','â'=>'â','ã'=>'ã','ä'=>'ä','å'=>'å','ç'=>'ç','è'=>'è','é'=>'é','ê'=>'ê','ë'=>'ë','ì'=>'ì','í'=>'í','î'=>'î','ï'=>'ï','ñ'=>'ñ','ò'=>'ò','ó'=>'ó','ô'=>'ô','õ'=>'õ','ö'=>'ö','ù'=>'ù','ú'=>'ú','û'=>'û','ü'=>'ü','ý'=>'ý','ÿ'=>'ÿ','Ā'=>'Ā','ā'=>'ā','Ă'=>'Ă','ă'=>'ă','Ą'=>'Ą','ą'=>'ą','Ć'=>'Ć','ć'=>'ć','Ĉ'=>'Ĉ','ĉ'=>'ĉ','Ċ'=>'Ċ','ċ'=>'ċ','Č'=>'Č','č'=>'č','Ď'=>'Ď','ď'=>'ď','Ē'=>'Ē','ē'=>'ē','Ĕ'=>'Ĕ','ĕ'=>'ĕ','Ė'=>'Ė','ė'=>'ė','Ę'=>'Ę','ę'=>'ę','Ě'=>'Ě','ě'=>'ě','Ĝ'=>'Ĝ','ĝ'=>'ĝ','Ğ'=>'Ğ','ğ'=>'ğ','Ġ'=>'Ġ','ġ'=>'ġ','Ģ'=>'Ģ','ģ'=>'ģ','Ĥ'=>'Ĥ','ĥ'=>'ĥ','Ĩ'=>'Ĩ','ĩ'=>'ĩ','Ī'=>'Ī','ī'=>'ī','Ĭ'=>'Ĭ','ĭ'=>'ĭ','Į'=>'Į','į'=>'į','İ'=>'İ','IJ'=>'IJ','ij'=>'ij','Ĵ'=>'Ĵ','ĵ'=>'ĵ','Ķ'=>'Ķ','ķ'=>'ķ','Ĺ'=>'Ĺ','ĺ'=>'ĺ','Ļ'=>'Ļ','ļ'=>'ļ','Ľ'=>'Ľ','ľ'=>'ľ','Ŀ'=>'L·','ŀ'=>'l·','Ń'=>'Ń','ń'=>'ń','Ņ'=>'Ņ','ņ'=>'ņ','Ň'=>'Ň','ň'=>'ň','ʼn'=>'ʼn','Ō'=>'Ō','ō'=>'ō','Ŏ'=>'Ŏ','ŏ'=>'ŏ','Ő'=>'Ő','ő'=>'ő','Ŕ'=>'Ŕ','ŕ'=>'ŕ','Ŗ'=>'Ŗ','ŗ'=>'ŗ','Ř'=>'Ř','ř'=>'ř','Ś'=>'Ś','ś'=>'ś','Ŝ'=>'Ŝ','ŝ'=>'ŝ','Ş'=>'Ş','ş'=>'ş','Š'=>'Š','š'=>'š','Ţ'=>'Ţ','ţ'=>'ţ','Ť'=>'Ť','ť'=>'ť','Ũ'=>'Ũ','ũ'=>'ũ','Ū'=>'Ū','ū'=>'ū','Ŭ'=>'Ŭ','ŭ'=>'ŭ','Ů'=>'Ů','ů'=>'ů','Ű'=>'Ű','ű'=>'ű','Ų'=>'Ų','ų'=>'ų','Ŵ'=>'Ŵ','ŵ'=>'ŵ','Ŷ'=>'Ŷ','ŷ'=>'ŷ','Ÿ'=>'Ÿ','Ź'=>'Ź','ź'=>'ź','Ż'=>'Ż','ż'=>'ż','Ž'=>'Ž','ž'=>'ž','ſ'=>'s','Ơ'=>'Ơ','ơ'=>'ơ','Ư'=>'Ư','ư'=>'ư','DŽ'=>'DŽ','Dž'=>'Dž','dž'=>'dž','LJ'=>'LJ','Lj'=>'Lj','lj'=>'lj','NJ'=>'NJ','Nj'=>'Nj','nj'=>'nj','Ǎ'=>'Ǎ','ǎ'=>'ǎ','Ǐ'=>'Ǐ','ǐ'=>'ǐ','Ǒ'=>'Ǒ','ǒ'=>'ǒ','Ǔ'=>'Ǔ','ǔ'=>'ǔ','Ǖ'=>'Ǖ','ǖ'=>'ǖ','Ǘ'=>'Ǘ','ǘ'=>'ǘ','Ǚ'=>'Ǚ','ǚ'=>'ǚ','Ǜ'=>'Ǜ','ǜ'=>'ǜ','Ǟ'=>'Ǟ','ǟ'=>'ǟ','Ǡ'=>'Ǡ','ǡ'=>'ǡ','Ǣ'=>'Ǣ','ǣ'=>'ǣ','Ǧ'=>'Ǧ','ǧ'=>'ǧ','Ǩ'=>'Ǩ','ǩ'=>'ǩ','Ǫ'=>'Ǫ','ǫ'=>'ǫ','Ǭ'=>'Ǭ','ǭ'=>'ǭ','Ǯ'=>'Ǯ','ǯ'=>'ǯ','ǰ'=>'ǰ','DZ'=>'DZ','Dz'=>'Dz','dz'=>'dz','Ǵ'=>'Ǵ','ǵ'=>'ǵ','Ǹ'=>'Ǹ','ǹ'=>'ǹ','Ǻ'=>'Ǻ','ǻ'=>'ǻ','Ǽ'=>'Ǽ','ǽ'=>'ǽ','Ǿ'=>'Ǿ','ǿ'=>'ǿ','Ȁ'=>'Ȁ','ȁ'=>'ȁ','Ȃ'=>'Ȃ','ȃ'=>'ȃ','Ȅ'=>'Ȅ','ȅ'=>'ȅ','Ȇ'=>'Ȇ','ȇ'=>'ȇ','Ȉ'=>'Ȉ','ȉ'=>'ȉ','Ȋ'=>'Ȋ','ȋ'=>'ȋ','Ȍ'=>'Ȍ','ȍ'=>'ȍ','Ȏ'=>'Ȏ','ȏ'=>'ȏ','Ȑ'=>'Ȑ','ȑ'=>'ȑ','Ȓ'=>'Ȓ','ȓ'=>'ȓ','Ȕ'=>'Ȕ','ȕ'=>'ȕ','Ȗ'=>'Ȗ','ȗ'=>'ȗ','Ș'=>'Ș','ș'=>'ș','Ț'=>'Ț','ț'=>'ț','Ȟ'=>'Ȟ','ȟ'=>'ȟ','Ȧ'=>'Ȧ','ȧ'=>'ȧ','Ȩ'=>'Ȩ','ȩ'=>'ȩ','Ȫ'=>'Ȫ','ȫ'=>'ȫ','Ȭ'=>'Ȭ','ȭ'=>'ȭ','Ȯ'=>'Ȯ','ȯ'=>'ȯ','Ȱ'=>'Ȱ','ȱ'=>'ȱ','Ȳ'=>'Ȳ','ȳ'=>'ȳ','ʰ'=>'h','ʱ'=>'ɦ','ʲ'=>'j','ʳ'=>'r','ʴ'=>'ɹ','ʵ'=>'ɻ','ʶ'=>'ʁ','ʷ'=>'w','ʸ'=>'y','˘'=>' ̆','˙'=>' ̇','˚'=>' ̊','˛'=>' ̨','˜'=>' ̃','˝'=>' ̋','ˠ'=>'ɣ','ˡ'=>'l','ˢ'=>'s','ˣ'=>'x','ˤ'=>'ʕ','̀'=>'̀','́'=>'́','̓'=>'̓','̈́'=>'̈́','ʹ'=>'ʹ','ͺ'=>' ͅ',';'=>';','΄'=>' ́','΅'=>' ̈́','Ά'=>'Ά','·'=>'·','Έ'=>'Έ','Ή'=>'Ή','Ί'=>'Ί','Ό'=>'Ό','Ύ'=>'Ύ','Ώ'=>'Ώ','ΐ'=>'ΐ','Ϊ'=>'Ϊ','Ϋ'=>'Ϋ','ά'=>'ά','έ'=>'έ','ή'=>'ή','ί'=>'ί','ΰ'=>'ΰ','ϊ'=>'ϊ','ϋ'=>'ϋ','ό'=>'ό','ύ'=>'ύ','ώ'=>'ώ','ϐ'=>'β','ϑ'=>'θ','ϒ'=>'Υ','ϓ'=>'Ύ','ϔ'=>'Ϋ','ϕ'=>'φ','ϖ'=>'π','ϰ'=>'κ','ϱ'=>'ρ','ϲ'=>'ς','ϴ'=>'Θ','ϵ'=>'ε','Ϲ'=>'Σ','Ѐ'=>'Ѐ','Ё'=>'Ё','Ѓ'=>'Ѓ','Ї'=>'Ї','Ќ'=>'Ќ','Ѝ'=>'Ѝ','Ў'=>'Ў','Й'=>'Й','й'=>'й','ѐ'=>'ѐ','ё'=>'ё','ѓ'=>'ѓ','ї'=>'ї','ќ'=>'ќ','ѝ'=>'ѝ','ў'=>'ў','Ѷ'=>'Ѷ','ѷ'=>'ѷ','Ӂ'=>'Ӂ','ӂ'=>'ӂ','Ӑ'=>'Ӑ','ӑ'=>'ӑ','Ӓ'=>'Ӓ','ӓ'=>'ӓ','Ӗ'=>'Ӗ','ӗ'=>'ӗ','Ӛ'=>'Ӛ','ӛ'=>'ӛ','Ӝ'=>'Ӝ','ӝ'=>'ӝ','Ӟ'=>'Ӟ','ӟ'=>'ӟ','Ӣ'=>'Ӣ','ӣ'=>'ӣ','Ӥ'=>'Ӥ','ӥ'=>'ӥ','Ӧ'=>'Ӧ','ӧ'=>'ӧ','Ӫ'=>'Ӫ','ӫ'=>'ӫ','Ӭ'=>'Ӭ','ӭ'=>'ӭ','Ӯ'=>'Ӯ','ӯ'=>'ӯ','Ӱ'=>'Ӱ','ӱ'=>'ӱ','Ӳ'=>'Ӳ','ӳ'=>'ӳ','Ӵ'=>'Ӵ','ӵ'=>'ӵ','Ӹ'=>'Ӹ','ӹ'=>'ӹ','և'=>'եւ','آ'=>'آ','أ'=>'أ','ؤ'=>'ؤ','إ'=>'إ','ئ'=>'ئ','ٵ'=>'اٴ','ٶ'=>'وٴ','ٷ'=>'ۇٴ','ٸ'=>'يٴ','ۀ'=>'ۀ','ۂ'=>'ۂ','ۓ'=>'ۓ','ऩ'=>'ऩ','ऱ'=>'ऱ','ऴ'=>'ऴ','क़'=>'क़','ख़'=>'ख़','ग़'=>'ग़','ज़'=>'ज़','ड़'=>'ड़','ढ़'=>'ढ़','फ़'=>'फ़','य़'=>'य़','ো'=>'ো','ৌ'=>'ৌ','ড়'=>'ড়','ঢ়'=>'ঢ়','য়'=>'য়','ਲ਼'=>'ਲ਼','ਸ਼'=>'ਸ਼','ਖ਼'=>'ਖ਼','ਗ਼'=>'ਗ਼','ਜ਼'=>'ਜ਼','ਫ਼'=>'ਫ਼','ୈ'=>'ୈ','ୋ'=>'ୋ','ୌ'=>'ୌ','ଡ଼'=>'ଡ଼','ଢ଼'=>'ଢ଼','ஔ'=>'ஔ','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','ై'=>'ై','ೀ'=>'ೀ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','ේ'=>'ේ','ො'=>'ො','ෝ'=>'ෝ','ෞ'=>'ෞ','ำ'=>'ํา','ຳ'=>'ໍາ','ໜ'=>'ຫນ','ໝ'=>'ຫມ','༌'=>'་','གྷ'=>'གྷ','ཌྷ'=>'ཌྷ','དྷ'=>'དྷ','བྷ'=>'བྷ','ཛྷ'=>'ཛྷ','ཀྵ'=>'ཀྵ','ཱི'=>'ཱི','ཱུ'=>'ཱུ','ྲྀ'=>'ྲྀ','ཷ'=>'ྲཱྀ','ླྀ'=>'ླྀ','ཹ'=>'ླཱྀ','ཱྀ'=>'ཱྀ','ྒྷ'=>'ྒྷ','ྜྷ'=>'ྜྷ','ྡྷ'=>'ྡྷ','ྦྷ'=>'ྦྷ','ྫྷ'=>'ྫྷ','ྐྵ'=>'ྐྵ','ဦ'=>'ဦ','ჼ'=>'ნ','ᬆ'=>'ᬆ','ᬈ'=>'ᬈ','ᬊ'=>'ᬊ','ᬌ'=>'ᬌ','ᬎ'=>'ᬎ','ᬒ'=>'ᬒ','ᬻ'=>'ᬻ','ᬽ'=>'ᬽ','ᭀ'=>'ᭀ','ᭁ'=>'ᭁ','ᭃ'=>'ᭃ','ᴬ'=>'A','ᴭ'=>'Æ','ᴮ'=>'B','ᴰ'=>'D','ᴱ'=>'E','ᴲ'=>'Ǝ','ᴳ'=>'G','ᴴ'=>'H','ᴵ'=>'I','ᴶ'=>'J','ᴷ'=>'K','ᴸ'=>'L','ᴹ'=>'M','ᴺ'=>'N','ᴼ'=>'O','ᴽ'=>'Ȣ','ᴾ'=>'P','ᴿ'=>'R','ᵀ'=>'T','ᵁ'=>'U','ᵂ'=>'W','ᵃ'=>'a','ᵄ'=>'ɐ','ᵅ'=>'ɑ','ᵆ'=>'ᴂ','ᵇ'=>'b','ᵈ'=>'d','ᵉ'=>'e','ᵊ'=>'ə','ᵋ'=>'ɛ','ᵌ'=>'ɜ','ᵍ'=>'g','ᵏ'=>'k','ᵐ'=>'m','ᵑ'=>'ŋ','ᵒ'=>'o','ᵓ'=>'ɔ','ᵔ'=>'ᴖ','ᵕ'=>'ᴗ','ᵖ'=>'p','ᵗ'=>'t','ᵘ'=>'u','ᵙ'=>'ᴝ','ᵚ'=>'ɯ','ᵛ'=>'v','ᵜ'=>'ᴥ','ᵝ'=>'β','ᵞ'=>'γ','ᵟ'=>'δ','ᵠ'=>'φ','ᵡ'=>'χ','ᵢ'=>'i','ᵣ'=>'r','ᵤ'=>'u','ᵥ'=>'v','ᵦ'=>'β','ᵧ'=>'γ','ᵨ'=>'ρ','ᵩ'=>'φ','ᵪ'=>'χ','ᵸ'=>'н','ᶛ'=>'ɒ','ᶜ'=>'c','ᶝ'=>'ɕ','ᶞ'=>'ð','ᶟ'=>'ɜ','ᶠ'=>'f','ᶡ'=>'ɟ','ᶢ'=>'ɡ','ᶣ'=>'ɥ','ᶤ'=>'ɨ','ᶥ'=>'ɩ','ᶦ'=>'ɪ','ᶧ'=>'ᵻ','ᶨ'=>'ʝ','ᶩ'=>'ɭ','ᶪ'=>'ᶅ','ᶫ'=>'ʟ','ᶬ'=>'ɱ','ᶭ'=>'ɰ','ᶮ'=>'ɲ','ᶯ'=>'ɳ','ᶰ'=>'ɴ','ᶱ'=>'ɵ','ᶲ'=>'ɸ','ᶳ'=>'ʂ','ᶴ'=>'ʃ','ᶵ'=>'ƫ','ᶶ'=>'ʉ','ᶷ'=>'ʊ','ᶸ'=>'ᴜ','ᶹ'=>'ʋ','ᶺ'=>'ʌ','ᶻ'=>'z','ᶼ'=>'ʐ','ᶽ'=>'ʑ','ᶾ'=>'ʒ','ᶿ'=>'θ','Ḁ'=>'Ḁ','ḁ'=>'ḁ','Ḃ'=>'Ḃ','ḃ'=>'ḃ','Ḅ'=>'Ḅ','ḅ'=>'ḅ','Ḇ'=>'Ḇ','ḇ'=>'ḇ','Ḉ'=>'Ḉ','ḉ'=>'ḉ','Ḋ'=>'Ḋ','ḋ'=>'ḋ','Ḍ'=>'Ḍ','ḍ'=>'ḍ','Ḏ'=>'Ḏ','ḏ'=>'ḏ','Ḑ'=>'Ḑ','ḑ'=>'ḑ','Ḓ'=>'Ḓ','ḓ'=>'ḓ','Ḕ'=>'Ḕ','ḕ'=>'ḕ','Ḗ'=>'Ḗ','ḗ'=>'ḗ','Ḙ'=>'Ḙ','ḙ'=>'ḙ','Ḛ'=>'Ḛ','ḛ'=>'ḛ','Ḝ'=>'Ḝ','ḝ'=>'ḝ','Ḟ'=>'Ḟ','ḟ'=>'ḟ','Ḡ'=>'Ḡ','ḡ'=>'ḡ','Ḣ'=>'Ḣ','ḣ'=>'ḣ','Ḥ'=>'Ḥ','ḥ'=>'ḥ','Ḧ'=>'Ḧ','ḧ'=>'ḧ','Ḩ'=>'Ḩ','ḩ'=>'ḩ','Ḫ'=>'Ḫ','ḫ'=>'ḫ','Ḭ'=>'Ḭ','ḭ'=>'ḭ','Ḯ'=>'Ḯ','ḯ'=>'ḯ','Ḱ'=>'Ḱ','ḱ'=>'ḱ','Ḳ'=>'Ḳ','ḳ'=>'ḳ','Ḵ'=>'Ḵ','ḵ'=>'ḵ','Ḷ'=>'Ḷ','ḷ'=>'ḷ','Ḹ'=>'Ḹ','ḹ'=>'ḹ','Ḻ'=>'Ḻ','ḻ'=>'ḻ','Ḽ'=>'Ḽ','ḽ'=>'ḽ','Ḿ'=>'Ḿ','ḿ'=>'ḿ','Ṁ'=>'Ṁ','ṁ'=>'ṁ','Ṃ'=>'Ṃ','ṃ'=>'ṃ','Ṅ'=>'Ṅ','ṅ'=>'ṅ','Ṇ'=>'Ṇ','ṇ'=>'ṇ','Ṉ'=>'Ṉ','ṉ'=>'ṉ','Ṋ'=>'Ṋ','ṋ'=>'ṋ','Ṍ'=>'Ṍ','ṍ'=>'ṍ','Ṏ'=>'Ṏ','ṏ'=>'ṏ','Ṑ'=>'Ṑ','ṑ'=>'ṑ','Ṓ'=>'Ṓ','ṓ'=>'ṓ','Ṕ'=>'Ṕ','ṕ'=>'ṕ','Ṗ'=>'Ṗ','ṗ'=>'ṗ','Ṙ'=>'Ṙ','ṙ'=>'ṙ','Ṛ'=>'Ṛ','ṛ'=>'ṛ','Ṝ'=>'Ṝ','ṝ'=>'ṝ','Ṟ'=>'Ṟ','ṟ'=>'ṟ','Ṡ'=>'Ṡ','ṡ'=>'ṡ','Ṣ'=>'Ṣ','ṣ'=>'ṣ','Ṥ'=>'Ṥ','ṥ'=>'ṥ','Ṧ'=>'Ṧ','ṧ'=>'ṧ','Ṩ'=>'Ṩ','ṩ'=>'ṩ','Ṫ'=>'Ṫ','ṫ'=>'ṫ','Ṭ'=>'Ṭ','ṭ'=>'ṭ','Ṯ'=>'Ṯ','ṯ'=>'ṯ','Ṱ'=>'Ṱ','ṱ'=>'ṱ','Ṳ'=>'Ṳ','ṳ'=>'ṳ','Ṵ'=>'Ṵ','ṵ'=>'ṵ','Ṷ'=>'Ṷ','ṷ'=>'ṷ','Ṹ'=>'Ṹ','ṹ'=>'ṹ','Ṻ'=>'Ṻ','ṻ'=>'ṻ','Ṽ'=>'Ṽ','ṽ'=>'ṽ','Ṿ'=>'Ṿ','ṿ'=>'ṿ','Ẁ'=>'Ẁ','ẁ'=>'ẁ','Ẃ'=>'Ẃ','ẃ'=>'ẃ','Ẅ'=>'Ẅ','ẅ'=>'ẅ','Ẇ'=>'Ẇ','ẇ'=>'ẇ','Ẉ'=>'Ẉ','ẉ'=>'ẉ','Ẋ'=>'Ẋ','ẋ'=>'ẋ','Ẍ'=>'Ẍ','ẍ'=>'ẍ','Ẏ'=>'Ẏ','ẏ'=>'ẏ','Ẑ'=>'Ẑ','ẑ'=>'ẑ','Ẓ'=>'Ẓ','ẓ'=>'ẓ','Ẕ'=>'Ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẚ'=>'aʾ','ẛ'=>'ṡ','Ạ'=>'Ạ','ạ'=>'ạ','Ả'=>'Ả','ả'=>'ả','Ấ'=>'Ấ','ấ'=>'ấ','Ầ'=>'Ầ','ầ'=>'ầ','Ẩ'=>'Ẩ','ẩ'=>'ẩ','Ẫ'=>'Ẫ','ẫ'=>'ẫ','Ậ'=>'Ậ','ậ'=>'ậ','Ắ'=>'Ắ','ắ'=>'ắ','Ằ'=>'Ằ','ằ'=>'ằ','Ẳ'=>'Ẳ','ẳ'=>'ẳ','Ẵ'=>'Ẵ','ẵ'=>'ẵ','Ặ'=>'Ặ','ặ'=>'ặ','Ẹ'=>'Ẹ','ẹ'=>'ẹ','Ẻ'=>'Ẻ','ẻ'=>'ẻ','Ẽ'=>'Ẽ','ẽ'=>'ẽ','Ế'=>'Ế','ế'=>'ế','Ề'=>'Ề','ề'=>'ề','Ể'=>'Ể','ể'=>'ể','Ễ'=>'Ễ','ễ'=>'ễ','Ệ'=>'Ệ','ệ'=>'ệ','Ỉ'=>'Ỉ','ỉ'=>'ỉ','Ị'=>'Ị','ị'=>'ị','Ọ'=>'Ọ','ọ'=>'ọ','Ỏ'=>'Ỏ','ỏ'=>'ỏ','Ố'=>'Ố','ố'=>'ố','Ồ'=>'Ồ','ồ'=>'ồ','Ổ'=>'Ổ','ổ'=>'ổ','Ỗ'=>'Ỗ','ỗ'=>'ỗ','Ộ'=>'Ộ','ộ'=>'ộ','Ớ'=>'Ớ','ớ'=>'ớ','Ờ'=>'Ờ','ờ'=>'ờ','Ở'=>'Ở','ở'=>'ở','Ỡ'=>'Ỡ','ỡ'=>'ỡ','Ợ'=>'Ợ','ợ'=>'ợ','Ụ'=>'Ụ','ụ'=>'ụ','Ủ'=>'Ủ','ủ'=>'ủ','Ứ'=>'Ứ','ứ'=>'ứ','Ừ'=>'Ừ','ừ'=>'ừ','Ử'=>'Ử','ử'=>'ử','Ữ'=>'Ữ','ữ'=>'ữ','Ự'=>'Ự','ự'=>'ự','Ỳ'=>'Ỳ','ỳ'=>'ỳ','Ỵ'=>'Ỵ','ỵ'=>'ỵ','Ỷ'=>'Ỷ','ỷ'=>'ỷ','Ỹ'=>'Ỹ','ỹ'=>'ỹ','ἀ'=>'ἀ','ἁ'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἄ','ἅ'=>'ἅ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'Ἀ','Ἁ'=>'Ἁ','Ἂ'=>'Ἂ','Ἃ'=>'Ἃ','Ἄ'=>'Ἄ','Ἅ'=>'Ἅ','Ἆ'=>'Ἆ','Ἇ'=>'Ἇ','ἐ'=>'ἐ','ἑ'=>'ἑ','ἒ'=>'ἒ','ἓ'=>'ἓ','ἔ'=>'ἔ','ἕ'=>'ἕ','Ἐ'=>'Ἐ','Ἑ'=>'Ἑ','Ἒ'=>'Ἒ','Ἓ'=>'Ἓ','Ἔ'=>'Ἔ','Ἕ'=>'Ἕ','ἠ'=>'ἠ','ἡ'=>'ἡ','ἢ'=>'ἢ','ἣ'=>'ἣ','ἤ'=>'ἤ','ἥ'=>'ἥ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'Ἠ','Ἡ'=>'Ἡ','Ἢ'=>'Ἢ','Ἣ'=>'Ἣ','Ἤ'=>'Ἤ','Ἥ'=>'Ἥ','Ἦ'=>'Ἦ','Ἧ'=>'Ἧ','ἰ'=>'ἰ','ἱ'=>'ἱ','ἲ'=>'ἲ','ἳ'=>'ἳ','ἴ'=>'ἴ','ἵ'=>'ἵ','ἶ'=>'ἶ','ἷ'=>'ἷ','Ἰ'=>'Ἰ','Ἱ'=>'Ἱ','Ἲ'=>'Ἲ','Ἳ'=>'Ἳ','Ἴ'=>'Ἴ','Ἵ'=>'Ἵ','Ἶ'=>'Ἶ','Ἷ'=>'Ἷ','ὀ'=>'ὀ','ὁ'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὄ','ὅ'=>'ὅ','Ὀ'=>'Ὀ','Ὁ'=>'Ὁ','Ὂ'=>'Ὂ','Ὃ'=>'Ὃ','Ὄ'=>'Ὄ','Ὅ'=>'Ὅ','ὐ'=>'ὐ','ὑ'=>'ὑ','ὒ'=>'ὒ','ὓ'=>'ὓ','ὔ'=>'ὔ','ὕ'=>'ὕ','ὖ'=>'ὖ','ὗ'=>'ὗ','Ὑ'=>'Ὑ','Ὓ'=>'Ὓ','Ὕ'=>'Ὕ','Ὗ'=>'Ὗ','ὠ'=>'ὠ','ὡ'=>'ὡ','ὢ'=>'ὢ','ὣ'=>'ὣ','ὤ'=>'ὤ','ὥ'=>'ὥ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'Ὠ','Ὡ'=>'Ὡ','Ὢ'=>'Ὢ','Ὣ'=>'Ὣ','Ὤ'=>'Ὤ','Ὥ'=>'Ὥ','Ὦ'=>'Ὦ','Ὧ'=>'Ὧ','ὰ'=>'ὰ','ά'=>'ά','ὲ'=>'ὲ','έ'=>'έ','ὴ'=>'ὴ','ή'=>'ή','ὶ'=>'ὶ','ί'=>'ί','ὸ'=>'ὸ','ό'=>'ό','ὺ'=>'ὺ','ύ'=>'ύ','ὼ'=>'ὼ','ώ'=>'ώ','ᾀ'=>'ᾀ','ᾁ'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ᾄ','ᾅ'=>'ᾅ','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾈ','ᾉ'=>'ᾉ','ᾊ'=>'ᾊ','ᾋ'=>'ᾋ','ᾌ'=>'ᾌ','ᾍ'=>'ᾍ','ᾎ'=>'ᾎ','ᾏ'=>'ᾏ','ᾐ'=>'ᾐ','ᾑ'=>'ᾑ','ᾒ'=>'ᾒ','ᾓ'=>'ᾓ','ᾔ'=>'ᾔ','ᾕ'=>'ᾕ','ᾖ'=>'ᾖ','ᾗ'=>'ᾗ','ᾘ'=>'ᾘ','ᾙ'=>'ᾙ','ᾚ'=>'ᾚ','ᾛ'=>'ᾛ','ᾜ'=>'ᾜ','ᾝ'=>'ᾝ','ᾞ'=>'ᾞ','ᾟ'=>'ᾟ','ᾠ'=>'ᾠ','ᾡ'=>'ᾡ','ᾢ'=>'ᾢ','ᾣ'=>'ᾣ','ᾤ'=>'ᾤ','ᾥ'=>'ᾥ','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾨ','ᾩ'=>'ᾩ','ᾪ'=>'ᾪ','ᾫ'=>'ᾫ','ᾬ'=>'ᾬ','ᾭ'=>'ᾭ','ᾮ'=>'ᾮ','ᾯ'=>'ᾯ','ᾰ'=>'ᾰ','ᾱ'=>'ᾱ','ᾲ'=>'ᾲ','ᾳ'=>'ᾳ','ᾴ'=>'ᾴ','ᾶ'=>'ᾶ','ᾷ'=>'ᾷ','Ᾰ'=>'Ᾰ','Ᾱ'=>'Ᾱ','Ὰ'=>'Ὰ','Ά'=>'Ά','ᾼ'=>'ᾼ','᾽'=>' ̓','ι'=>'ι','᾿'=>' ̓','῀'=>' ͂','῁'=>' ̈͂','ῂ'=>'ῂ','ῃ'=>'ῃ','ῄ'=>'ῄ','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'Ὲ','Έ'=>'Έ','Ὴ'=>'Ὴ','Ή'=>'Ή','ῌ'=>'ῌ','῍'=>' ̓̀','῎'=>' ̓́','῏'=>' ̓͂','ῐ'=>'ῐ','ῑ'=>'ῑ','ῒ'=>'ῒ','ΐ'=>'ΐ','ῖ'=>'ῖ','ῗ'=>'ῗ','Ῐ'=>'Ῐ','Ῑ'=>'Ῑ','Ὶ'=>'Ὶ','Ί'=>'Ί','῝'=>' ̔̀','῞'=>' ̔́','῟'=>' ̔͂','ῠ'=>'ῠ','ῡ'=>'ῡ','ῢ'=>'ῢ','ΰ'=>'ΰ','ῤ'=>'ῤ','ῥ'=>'ῥ','ῦ'=>'ῦ','ῧ'=>'ῧ','Ῠ'=>'Ῠ','Ῡ'=>'Ῡ','Ὺ'=>'Ὺ','Ύ'=>'Ύ','Ῥ'=>'Ῥ','῭'=>' ̈̀','΅'=>' ̈́','`'=>'`','ῲ'=>'ῲ','ῳ'=>'ῳ','ῴ'=>'ῴ','ῶ'=>'ῶ','ῷ'=>'ῷ','Ὸ'=>'Ὸ','Ό'=>'Ό','Ὼ'=>'Ὼ','Ώ'=>'Ώ','ῼ'=>'ῼ','´'=>' ́','῾'=>' ̔',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ','‑'=>'‐','‗'=>' ̳','․'=>'.','‥'=>'..','…'=>'...',' '=>' ','″'=>'′′','‴'=>'′′′','‶'=>'‵‵','‷'=>'‵‵‵','‼'=>'!!','‾'=>' ̅','⁇'=>'??','⁈'=>'?!','⁉'=>'!?','⁗'=>'′′′′',' '=>' ','⁰'=>'0','ⁱ'=>'i','⁴'=>'4','⁵'=>'5','⁶'=>'6','⁷'=>'7','⁸'=>'8','⁹'=>'9','⁺'=>'+','⁻'=>'−','⁼'=>'=','⁽'=>'(','⁾'=>')','ⁿ'=>'n','₀'=>'0','₁'=>'1','₂'=>'2','₃'=>'3','₄'=>'4','₅'=>'5','₆'=>'6','₇'=>'7','₈'=>'8','₉'=>'9','₊'=>'+','₋'=>'−','₌'=>'=','₍'=>'(','₎'=>')','ₐ'=>'a','ₑ'=>'e','ₒ'=>'o','ₓ'=>'x','ₔ'=>'ə','₨'=>'Rs','℀'=>'a/c','℁'=>'a/s','ℂ'=>'C','℃'=>'°C','℅'=>'c/o','℆'=>'c/u','ℇ'=>'Ɛ','℉'=>'°F','ℊ'=>'g','ℋ'=>'H','ℌ'=>'H','ℍ'=>'H','ℎ'=>'h','ℏ'=>'ħ','ℐ'=>'I','ℑ'=>'I','ℒ'=>'L','ℓ'=>'l','ℕ'=>'N','№'=>'No','ℙ'=>'P','ℚ'=>'Q','ℛ'=>'R','ℜ'=>'R','ℝ'=>'R','℠'=>'SM','℡'=>'TEL','™'=>'TM','ℤ'=>'Z','Ω'=>'Ω','ℨ'=>'Z','K'=>'K','Å'=>'Å','ℬ'=>'B','ℭ'=>'C','ℯ'=>'e','ℰ'=>'E','ℱ'=>'F','ℳ'=>'M','ℴ'=>'o','ℵ'=>'א','ℶ'=>'ב','ℷ'=>'ג','ℸ'=>'ד','ℹ'=>'i','℻'=>'FAX','ℼ'=>'π','ℽ'=>'γ','ℾ'=>'Γ','ℿ'=>'Π','⅀'=>'∑','ⅅ'=>'D','ⅆ'=>'d','ⅇ'=>'e','ⅈ'=>'i','ⅉ'=>'j','⅓'=>'1⁄3','⅔'=>'2⁄3','⅕'=>'1⁄5','⅖'=>'2⁄5','⅗'=>'3⁄5','⅘'=>'4⁄5','⅙'=>'1⁄6','⅚'=>'5⁄6','⅛'=>'1⁄8','⅜'=>'3⁄8','⅝'=>'5⁄8','⅞'=>'7⁄8','⅟'=>'1⁄','Ⅰ'=>'I','Ⅱ'=>'II','Ⅲ'=>'III','Ⅳ'=>'IV','Ⅴ'=>'V','Ⅵ'=>'VI','Ⅶ'=>'VII','Ⅷ'=>'VIII','Ⅸ'=>'IX','Ⅹ'=>'X','Ⅺ'=>'XI','Ⅻ'=>'XII','Ⅼ'=>'L','Ⅽ'=>'C','Ⅾ'=>'D','Ⅿ'=>'M','ⅰ'=>'i','ⅱ'=>'ii','ⅲ'=>'iii','ⅳ'=>'iv','ⅴ'=>'v','ⅵ'=>'vi','ⅶ'=>'vii','ⅷ'=>'viii','ⅸ'=>'ix','ⅹ'=>'x','ⅺ'=>'xi','ⅻ'=>'xii','ⅼ'=>'l','ⅽ'=>'c','ⅾ'=>'d','ⅿ'=>'m','↚'=>'↚','↛'=>'↛','↮'=>'↮','⇍'=>'⇍','⇎'=>'⇎','⇏'=>'⇏','∄'=>'∄','∉'=>'∉','∌'=>'∌','∤'=>'∤','∦'=>'∦','∬'=>'∫∫','∭'=>'∫∫∫','∯'=>'∮∮','∰'=>'∮∮∮','≁'=>'≁','≄'=>'≄','≇'=>'≇','≉'=>'≉','≠'=>'≠','≢'=>'≢','≭'=>'≭','≮'=>'≮','≯'=>'≯','≰'=>'≰','≱'=>'≱','≴'=>'≴','≵'=>'≵','≸'=>'≸','≹'=>'≹','⊀'=>'⊀','⊁'=>'⊁','⊄'=>'⊄','⊅'=>'⊅','⊈'=>'⊈','⊉'=>'⊉','⊬'=>'⊬','⊭'=>'⊭','⊮'=>'⊮','⊯'=>'⊯','⋠'=>'⋠','⋡'=>'⋡','⋢'=>'⋢','⋣'=>'⋣','⋪'=>'⋪','⋫'=>'⋫','⋬'=>'⋬','⋭'=>'⋭','〈'=>'〈','〉'=>'〉','①'=>'1','②'=>'2','③'=>'3','④'=>'4','⑤'=>'5','⑥'=>'6','⑦'=>'7','⑧'=>'8','⑨'=>'9','⑩'=>'10','⑪'=>'11','⑫'=>'12','⑬'=>'13','⑭'=>'14','⑮'=>'15','⑯'=>'16','⑰'=>'17','⑱'=>'18','⑲'=>'19','⑳'=>'20','⑴'=>'(1)','⑵'=>'(2)','⑶'=>'(3)','⑷'=>'(4)','⑸'=>'(5)','⑹'=>'(6)','⑺'=>'(7)','⑻'=>'(8)','⑼'=>'(9)','⑽'=>'(10)','⑾'=>'(11)','⑿'=>'(12)','⒀'=>'(13)','⒁'=>'(14)','⒂'=>'(15)','⒃'=>'(16)','⒄'=>'(17)','⒅'=>'(18)','⒆'=>'(19)','⒇'=>'(20)','⒈'=>'1.','⒉'=>'2.','⒊'=>'3.','⒋'=>'4.','⒌'=>'5.','⒍'=>'6.','⒎'=>'7.','⒏'=>'8.','⒐'=>'9.','⒑'=>'10.','⒒'=>'11.','⒓'=>'12.','⒔'=>'13.','⒕'=>'14.','⒖'=>'15.','⒗'=>'16.','⒘'=>'17.','⒙'=>'18.','⒚'=>'19.','⒛'=>'20.','⒜'=>'(a)','⒝'=>'(b)','⒞'=>'(c)','⒟'=>'(d)','⒠'=>'(e)','⒡'=>'(f)','⒢'=>'(g)','⒣'=>'(h)','⒤'=>'(i)','⒥'=>'(j)','⒦'=>'(k)','⒧'=>'(l)','⒨'=>'(m)','⒩'=>'(n)','⒪'=>'(o)','⒫'=>'(p)','⒬'=>'(q)','⒭'=>'(r)','⒮'=>'(s)','⒯'=>'(t)','⒰'=>'(u)','⒱'=>'(v)','⒲'=>'(w)','⒳'=>'(x)','⒴'=>'(y)','⒵'=>'(z)','Ⓐ'=>'A','Ⓑ'=>'B','Ⓒ'=>'C','Ⓓ'=>'D','Ⓔ'=>'E','Ⓕ'=>'F','Ⓖ'=>'G','Ⓗ'=>'H','Ⓘ'=>'I','Ⓙ'=>'J','Ⓚ'=>'K','Ⓛ'=>'L','Ⓜ'=>'M','Ⓝ'=>'N','Ⓞ'=>'O','Ⓟ'=>'P','Ⓠ'=>'Q','Ⓡ'=>'R','Ⓢ'=>'S','Ⓣ'=>'T','Ⓤ'=>'U','Ⓥ'=>'V','Ⓦ'=>'W','Ⓧ'=>'X','Ⓨ'=>'Y','Ⓩ'=>'Z','ⓐ'=>'a','ⓑ'=>'b','ⓒ'=>'c','ⓓ'=>'d','ⓔ'=>'e','ⓕ'=>'f','ⓖ'=>'g','ⓗ'=>'h','ⓘ'=>'i','ⓙ'=>'j','ⓚ'=>'k','ⓛ'=>'l','ⓜ'=>'m','ⓝ'=>'n','ⓞ'=>'o','ⓟ'=>'p','ⓠ'=>'q','ⓡ'=>'r','ⓢ'=>'s','ⓣ'=>'t','ⓤ'=>'u','ⓥ'=>'v','ⓦ'=>'w','ⓧ'=>'x','ⓨ'=>'y','ⓩ'=>'z','⓪'=>'0','⨌'=>'∫∫∫∫','⩴'=>'::=','⩵'=>'==','⩶'=>'===','⫝̸'=>'⫝̸','ⵯ'=>'ⵡ','⺟'=>'母','⻳'=>'龟','⼀'=>'一','⼁'=>'丨','⼂'=>'丶','⼃'=>'丿','⼄'=>'乙','⼅'=>'亅','⼆'=>'二','⼇'=>'亠','⼈'=>'人','⼉'=>'儿','⼊'=>'入','⼋'=>'八','⼌'=>'冂','⼍'=>'冖','⼎'=>'冫','⼏'=>'几','⼐'=>'凵','⼑'=>'刀','⼒'=>'力','⼓'=>'勹','⼔'=>'匕','⼕'=>'匚','⼖'=>'匸','⼗'=>'十','⼘'=>'卜','⼙'=>'卩','⼚'=>'厂','⼛'=>'厶','⼜'=>'又','⼝'=>'口','⼞'=>'囗','⼟'=>'土','⼠'=>'士','⼡'=>'夂','⼢'=>'夊','⼣'=>'夕','⼤'=>'大','⼥'=>'女','⼦'=>'子','⼧'=>'宀','⼨'=>'寸','⼩'=>'小','⼪'=>'尢','⼫'=>'尸','⼬'=>'屮','⼭'=>'山','⼮'=>'巛','⼯'=>'工','⼰'=>'己','⼱'=>'巾','⼲'=>'干','⼳'=>'幺','⼴'=>'广','⼵'=>'廴','⼶'=>'廾','⼷'=>'弋','⼸'=>'弓','⼹'=>'彐','⼺'=>'彡','⼻'=>'彳','⼼'=>'心','⼽'=>'戈','⼾'=>'戶','⼿'=>'手','⽀'=>'支','⽁'=>'攴','⽂'=>'文','⽃'=>'斗','⽄'=>'斤','⽅'=>'方','⽆'=>'无','⽇'=>'日','⽈'=>'曰','⽉'=>'月','⽊'=>'木','⽋'=>'欠','⽌'=>'止','⽍'=>'歹','⽎'=>'殳','⽏'=>'毋','⽐'=>'比','⽑'=>'毛','⽒'=>'氏','⽓'=>'气','⽔'=>'水','⽕'=>'火','⽖'=>'爪','⽗'=>'父','⽘'=>'爻','⽙'=>'爿','⽚'=>'片','⽛'=>'牙','⽜'=>'牛','⽝'=>'犬','⽞'=>'玄','⽟'=>'玉','⽠'=>'瓜','⽡'=>'瓦','⽢'=>'甘','⽣'=>'生','⽤'=>'用','⽥'=>'田','⽦'=>'疋','⽧'=>'疒','⽨'=>'癶','⽩'=>'白','⽪'=>'皮','⽫'=>'皿','⽬'=>'目','⽭'=>'矛','⽮'=>'矢','⽯'=>'石','⽰'=>'示','⽱'=>'禸','⽲'=>'禾','⽳'=>'穴','⽴'=>'立','⽵'=>'竹','⽶'=>'米','⽷'=>'糸','⽸'=>'缶','⽹'=>'网','⽺'=>'羊','⽻'=>'羽','⽼'=>'老','⽽'=>'而','⽾'=>'耒','⽿'=>'耳','⾀'=>'聿','⾁'=>'肉','⾂'=>'臣','⾃'=>'自','⾄'=>'至','⾅'=>'臼','⾆'=>'舌','⾇'=>'舛','⾈'=>'舟','⾉'=>'艮','⾊'=>'色','⾋'=>'艸','⾌'=>'虍','⾍'=>'虫','⾎'=>'血','⾏'=>'行','⾐'=>'衣','⾑'=>'襾','⾒'=>'見','⾓'=>'角','⾔'=>'言','⾕'=>'谷','⾖'=>'豆','⾗'=>'豕','⾘'=>'豸','⾙'=>'貝','⾚'=>'赤','⾛'=>'走','⾜'=>'足','⾝'=>'身','⾞'=>'車','⾟'=>'辛','⾠'=>'辰','⾡'=>'辵','⾢'=>'邑','⾣'=>'酉','⾤'=>'釆','⾥'=>'里','⾦'=>'金','⾧'=>'長','⾨'=>'門','⾩'=>'阜','⾪'=>'隶','⾫'=>'隹','⾬'=>'雨','⾭'=>'靑','⾮'=>'非','⾯'=>'面','⾰'=>'革','⾱'=>'韋','⾲'=>'韭','⾳'=>'音','⾴'=>'頁','⾵'=>'風','⾶'=>'飛','⾷'=>'食','⾸'=>'首','⾹'=>'香','⾺'=>'馬','⾻'=>'骨','⾼'=>'高','⾽'=>'髟','⾾'=>'鬥','⾿'=>'鬯','⿀'=>'鬲','⿁'=>'鬼','⿂'=>'魚','⿃'=>'鳥','⿄'=>'鹵','⿅'=>'鹿','⿆'=>'麥','⿇'=>'麻','⿈'=>'黃','⿉'=>'黍','⿊'=>'黑','⿋'=>'黹','⿌'=>'黽','⿍'=>'鼎','⿎'=>'鼓','⿏'=>'鼠','⿐'=>'鼻','⿑'=>'齊','⿒'=>'齒','⿓'=>'龍','⿔'=>'龜','⿕'=>'龠',' '=>' ','〶'=>'〒','〸'=>'十','〹'=>'卄','〺'=>'卅','が'=>'が','ぎ'=>'ぎ','ぐ'=>'ぐ','げ'=>'げ','ご'=>'ご','ざ'=>'ざ','じ'=>'じ','ず'=>'ず','ぜ'=>'ぜ','ぞ'=>'ぞ','だ'=>'だ','ぢ'=>'ぢ','づ'=>'づ','で'=>'で','ど'=>'ど','ば'=>'ば','ぱ'=>'ぱ','び'=>'び','ぴ'=>'ぴ','ぶ'=>'ぶ','ぷ'=>'ぷ','べ'=>'べ','ぺ'=>'ぺ','ぼ'=>'ぼ','ぽ'=>'ぽ','ゔ'=>'ゔ','゛'=>' ゙','゜'=>' ゚','ゞ'=>'ゞ','ゟ'=>'より','ガ'=>'ガ','ギ'=>'ギ','グ'=>'グ','ゲ'=>'ゲ','ゴ'=>'ゴ','ザ'=>'ザ','ジ'=>'ジ','ズ'=>'ズ','ゼ'=>'ゼ','ゾ'=>'ゾ','ダ'=>'ダ','ヂ'=>'ヂ','ヅ'=>'ヅ','デ'=>'デ','ド'=>'ド','バ'=>'バ','パ'=>'パ','ビ'=>'ビ','ピ'=>'ピ','ブ'=>'ブ','プ'=>'プ','ベ'=>'ベ','ペ'=>'ペ','ボ'=>'ボ','ポ'=>'ポ','ヴ'=>'ヴ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ヾ'=>'ヾ','ヿ'=>'コト','ㄱ'=>'ᄀ','ㄲ'=>'ᄁ','ㄳ'=>'ᆪ','ㄴ'=>'ᄂ','ㄵ'=>'ᆬ','ㄶ'=>'ᆭ','ㄷ'=>'ᄃ','ㄸ'=>'ᄄ','ㄹ'=>'ᄅ','ㄺ'=>'ᆰ','ㄻ'=>'ᆱ','ㄼ'=>'ᆲ','ㄽ'=>'ᆳ','ㄾ'=>'ᆴ','ㄿ'=>'ᆵ','ㅀ'=>'ᄚ','ㅁ'=>'ᄆ','ㅂ'=>'ᄇ','ㅃ'=>'ᄈ','ㅄ'=>'ᄡ','ㅅ'=>'ᄉ','ㅆ'=>'ᄊ','ㅇ'=>'ᄋ','ㅈ'=>'ᄌ','ㅉ'=>'ᄍ','ㅊ'=>'ᄎ','ㅋ'=>'ᄏ','ㅌ'=>'ᄐ','ㅍ'=>'ᄑ','ㅎ'=>'ᄒ','ㅏ'=>'ᅡ','ㅐ'=>'ᅢ','ㅑ'=>'ᅣ','ㅒ'=>'ᅤ','ㅓ'=>'ᅥ','ㅔ'=>'ᅦ','ㅕ'=>'ᅧ','ㅖ'=>'ᅨ','ㅗ'=>'ᅩ','ㅘ'=>'ᅪ','ㅙ'=>'ᅫ','ㅚ'=>'ᅬ','ㅛ'=>'ᅭ','ㅜ'=>'ᅮ','ㅝ'=>'ᅯ','ㅞ'=>'ᅰ','ㅟ'=>'ᅱ','ㅠ'=>'ᅲ','ㅡ'=>'ᅳ','ㅢ'=>'ᅴ','ㅣ'=>'ᅵ','ㅤ'=>'ᅠ','ㅥ'=>'ᄔ','ㅦ'=>'ᄕ','ㅧ'=>'ᇇ','ㅨ'=>'ᇈ','ㅩ'=>'ᇌ','ㅪ'=>'ᇎ','ㅫ'=>'ᇓ','ㅬ'=>'ᇗ','ㅭ'=>'ᇙ','ㅮ'=>'ᄜ','ㅯ'=>'ᇝ','ㅰ'=>'ᇟ','ㅱ'=>'ᄝ','ㅲ'=>'ᄞ','ㅳ'=>'ᄠ','ㅴ'=>'ᄢ','ㅵ'=>'ᄣ','ㅶ'=>'ᄧ','ㅷ'=>'ᄩ','ㅸ'=>'ᄫ','ㅹ'=>'ᄬ','ㅺ'=>'ᄭ','ㅻ'=>'ᄮ','ㅼ'=>'ᄯ','ㅽ'=>'ᄲ','ㅾ'=>'ᄶ','ㅿ'=>'ᅀ','ㆀ'=>'ᅇ','ㆁ'=>'ᅌ','ㆂ'=>'ᇱ','ㆃ'=>'ᇲ','ㆄ'=>'ᅗ','ㆅ'=>'ᅘ','ㆆ'=>'ᅙ','ㆇ'=>'ᆄ','ㆈ'=>'ᆅ','ㆉ'=>'ᆈ','ㆊ'=>'ᆑ','ㆋ'=>'ᆒ','ㆌ'=>'ᆔ','ㆍ'=>'ᆞ','ㆎ'=>'ᆡ','㆒'=>'一','㆓'=>'二','㆔'=>'三','㆕'=>'四','㆖'=>'上','㆗'=>'中','㆘'=>'下','㆙'=>'甲','㆚'=>'乙','㆛'=>'丙','㆜'=>'丁','㆝'=>'天','㆞'=>'地','㆟'=>'人','㈀'=>'(ᄀ)','㈁'=>'(ᄂ)','㈂'=>'(ᄃ)','㈃'=>'(ᄅ)','㈄'=>'(ᄆ)','㈅'=>'(ᄇ)','㈆'=>'(ᄉ)','㈇'=>'(ᄋ)','㈈'=>'(ᄌ)','㈉'=>'(ᄎ)','㈊'=>'(ᄏ)','㈋'=>'(ᄐ)','㈌'=>'(ᄑ)','㈍'=>'(ᄒ)','㈎'=>'(가)','㈏'=>'(나)','㈐'=>'(다)','㈑'=>'(라)','㈒'=>'(마)','㈓'=>'(바)','㈔'=>'(사)','㈕'=>'(아)','㈖'=>'(자)','㈗'=>'(차)','㈘'=>'(카)','㈙'=>'(타)','㈚'=>'(파)','㈛'=>'(하)','㈜'=>'(주)','㈝'=>'(오전)','㈞'=>'(오후)','㈠'=>'(一)','㈡'=>'(二)','㈢'=>'(三)','㈣'=>'(四)','㈤'=>'(五)','㈥'=>'(六)','㈦'=>'(七)','㈧'=>'(八)','㈨'=>'(九)','㈩'=>'(十)','㈪'=>'(月)','㈫'=>'(火)','㈬'=>'(水)','㈭'=>'(木)','㈮'=>'(金)','㈯'=>'(土)','㈰'=>'(日)','㈱'=>'(株)','㈲'=>'(有)','㈳'=>'(社)','㈴'=>'(名)','㈵'=>'(特)','㈶'=>'(財)','㈷'=>'(祝)','㈸'=>'(労)','㈹'=>'(代)','㈺'=>'(呼)','㈻'=>'(学)','㈼'=>'(監)','㈽'=>'(企)','㈾'=>'(資)','㈿'=>'(協)','㉀'=>'(祭)','㉁'=>'(休)','㉂'=>'(自)','㉃'=>'(至)','㉐'=>'PTE','㉑'=>'21','㉒'=>'22','㉓'=>'23','㉔'=>'24','㉕'=>'25','㉖'=>'26','㉗'=>'27','㉘'=>'28','㉙'=>'29','㉚'=>'30','㉛'=>'31','㉜'=>'32','㉝'=>'33','㉞'=>'34','㉟'=>'35','㉠'=>'ᄀ','㉡'=>'ᄂ','㉢'=>'ᄃ','㉣'=>'ᄅ','㉤'=>'ᄆ','㉥'=>'ᄇ','㉦'=>'ᄉ','㉧'=>'ᄋ','㉨'=>'ᄌ','㉩'=>'ᄎ','㉪'=>'ᄏ','㉫'=>'ᄐ','㉬'=>'ᄑ','㉭'=>'ᄒ','㉮'=>'가','㉯'=>'나','㉰'=>'다','㉱'=>'라','㉲'=>'마','㉳'=>'바','㉴'=>'사','㉵'=>'아','㉶'=>'자','㉷'=>'차','㉸'=>'카','㉹'=>'타','㉺'=>'파','㉻'=>'하','㉼'=>'참고','㉽'=>'주의','㉾'=>'우','㊀'=>'一','㊁'=>'二','㊂'=>'三','㊃'=>'四','㊄'=>'五','㊅'=>'六','㊆'=>'七','㊇'=>'八','㊈'=>'九','㊉'=>'十','㊊'=>'月','㊋'=>'火','㊌'=>'水','㊍'=>'木','㊎'=>'金','㊏'=>'土','㊐'=>'日','㊑'=>'株','㊒'=>'有','㊓'=>'社','㊔'=>'名','㊕'=>'特','㊖'=>'財','㊗'=>'祝','㊘'=>'労','㊙'=>'秘','㊚'=>'男','㊛'=>'女','㊜'=>'適','㊝'=>'優','㊞'=>'印','㊟'=>'注','㊠'=>'項','㊡'=>'休','㊢'=>'写','㊣'=>'正','㊤'=>'上','㊥'=>'中','㊦'=>'下','㊧'=>'左','㊨'=>'右','㊩'=>'医','㊪'=>'宗','㊫'=>'学','㊬'=>'監','㊭'=>'企','㊮'=>'資','㊯'=>'協','㊰'=>'夜','㊱'=>'36','㊲'=>'37','㊳'=>'38','㊴'=>'39','㊵'=>'40','㊶'=>'41','㊷'=>'42','㊸'=>'43','㊹'=>'44','㊺'=>'45','㊻'=>'46','㊼'=>'47','㊽'=>'48','㊾'=>'49','㊿'=>'50','㋀'=>'1月','㋁'=>'2月','㋂'=>'3月','㋃'=>'4月','㋄'=>'5月','㋅'=>'6月','㋆'=>'7月','㋇'=>'8月','㋈'=>'9月','㋉'=>'10月','㋊'=>'11月','㋋'=>'12月','㋌'=>'Hg','㋍'=>'erg','㋎'=>'eV','㋏'=>'LTD','㋐'=>'ア','㋑'=>'イ','㋒'=>'ウ','㋓'=>'エ','㋔'=>'オ','㋕'=>'カ','㋖'=>'キ','㋗'=>'ク','㋘'=>'ケ','㋙'=>'コ','㋚'=>'サ','㋛'=>'シ','㋜'=>'ス','㋝'=>'セ','㋞'=>'ソ','㋟'=>'タ','㋠'=>'チ','㋡'=>'ツ','㋢'=>'テ','㋣'=>'ト','㋤'=>'ナ','㋥'=>'ニ','㋦'=>'ヌ','㋧'=>'ネ','㋨'=>'ノ','㋩'=>'ハ','㋪'=>'ヒ','㋫'=>'フ','㋬'=>'ヘ','㋭'=>'ホ','㋮'=>'マ','㋯'=>'ミ','㋰'=>'ム','㋱'=>'メ','㋲'=>'モ','㋳'=>'ヤ','㋴'=>'ユ','㋵'=>'ヨ','㋶'=>'ラ','㋷'=>'リ','㋸'=>'ル','㋹'=>'レ','㋺'=>'ロ','㋻'=>'ワ','㋼'=>'ヰ','㋽'=>'ヱ','㋾'=>'ヲ','㌀'=>'アパート','㌁'=>'アルファ','㌂'=>'アンペア','㌃'=>'アール','㌄'=>'イニング','㌅'=>'インチ','㌆'=>'ウォン','㌇'=>'エスクード','㌈'=>'エーカー','㌉'=>'オンス','㌊'=>'オーム','㌋'=>'カイリ','㌌'=>'カラット','㌍'=>'カロリー','㌎'=>'ガロン','㌏'=>'ガンマ','㌐'=>'ギガ','㌑'=>'ギニー','㌒'=>'キュリー','㌓'=>'ギルダー','㌔'=>'キロ','㌕'=>'キログラム','㌖'=>'キロメートル','㌗'=>'キロワット','㌘'=>'グラム','㌙'=>'グラムトン','㌚'=>'クルゼイロ','㌛'=>'クローネ','㌜'=>'ケース','㌝'=>'コルナ','㌞'=>'コーポ','㌟'=>'サイクル','㌠'=>'サンチーム','㌡'=>'シリング','㌢'=>'センチ','㌣'=>'セント','㌤'=>'ダース','㌥'=>'デシ','㌦'=>'ドル','㌧'=>'トン','㌨'=>'ナノ','㌩'=>'ノット','㌪'=>'ハイツ','㌫'=>'パーセント','㌬'=>'パーツ','㌭'=>'バーレル','㌮'=>'ピアストル','㌯'=>'ピクル','㌰'=>'ピコ','㌱'=>'ビル','㌲'=>'ファラッド','㌳'=>'フィート','㌴'=>'ブッシェル','㌵'=>'フラン','㌶'=>'ヘクタール','㌷'=>'ペソ','㌸'=>'ペニヒ','㌹'=>'ヘルツ','㌺'=>'ペンス','㌻'=>'ページ','㌼'=>'ベータ','㌽'=>'ポイント','㌾'=>'ボルト','㌿'=>'ホン','㍀'=>'ポンド','㍁'=>'ホール','㍂'=>'ホーン','㍃'=>'マイクロ','㍄'=>'マイル','㍅'=>'マッハ','㍆'=>'マルク','㍇'=>'マンション','㍈'=>'ミクロン','㍉'=>'ミリ','㍊'=>'ミリバール','㍋'=>'メガ','㍌'=>'メガトン','㍍'=>'メートル','㍎'=>'ヤード','㍏'=>'ヤール','㍐'=>'ユアン','㍑'=>'リットル','㍒'=>'リラ','㍓'=>'ルピー','㍔'=>'ルーブル','㍕'=>'レム','㍖'=>'レントゲン','㍗'=>'ワット','㍘'=>'0点','㍙'=>'1点','㍚'=>'2点','㍛'=>'3点','㍜'=>'4点','㍝'=>'5点','㍞'=>'6点','㍟'=>'7点','㍠'=>'8点','㍡'=>'9点','㍢'=>'10点','㍣'=>'11点','㍤'=>'12点','㍥'=>'13点','㍦'=>'14点','㍧'=>'15点','㍨'=>'16点','㍩'=>'17点','㍪'=>'18点','㍫'=>'19点','㍬'=>'20点','㍭'=>'21点','㍮'=>'22点','㍯'=>'23点','㍰'=>'24点','㍱'=>'hPa','㍲'=>'da','㍳'=>'AU','㍴'=>'bar','㍵'=>'oV','㍶'=>'pc','㍷'=>'dm','㍸'=>'dm2','㍹'=>'dm3','㍺'=>'IU','㍻'=>'平成','㍼'=>'昭和','㍽'=>'大正','㍾'=>'明治','㍿'=>'株式会社','㎀'=>'pA','㎁'=>'nA','㎂'=>'μA','㎃'=>'mA','㎄'=>'kA','㎅'=>'KB','㎆'=>'MB','㎇'=>'GB','㎈'=>'cal','㎉'=>'kcal','㎊'=>'pF','㎋'=>'nF','㎌'=>'μF','㎍'=>'μg','㎎'=>'mg','㎏'=>'kg','㎐'=>'Hz','㎑'=>'kHz','㎒'=>'MHz','㎓'=>'GHz','㎔'=>'THz','㎕'=>'μl','㎖'=>'ml','㎗'=>'dl','㎘'=>'kl','㎙'=>'fm','㎚'=>'nm','㎛'=>'μm','㎜'=>'mm','㎝'=>'cm','㎞'=>'km','㎟'=>'mm2','㎠'=>'cm2','㎡'=>'m2','㎢'=>'km2','㎣'=>'mm3','㎤'=>'cm3','㎥'=>'m3','㎦'=>'km3','㎧'=>'m∕s','㎨'=>'m∕s2','㎩'=>'Pa','㎪'=>'kPa','㎫'=>'MPa','㎬'=>'GPa','㎭'=>'rad','㎮'=>'rad∕s','㎯'=>'rad∕s2','㎰'=>'ps','㎱'=>'ns','㎲'=>'μs','㎳'=>'ms','㎴'=>'pV','㎵'=>'nV','㎶'=>'μV','㎷'=>'mV','㎸'=>'kV','㎹'=>'MV','㎺'=>'pW','㎻'=>'nW','㎼'=>'μW','㎽'=>'mW','㎾'=>'kW','㎿'=>'MW','㏀'=>'kΩ','㏁'=>'MΩ','㏂'=>'a.m.','㏃'=>'Bq','㏄'=>'cc','㏅'=>'cd','㏆'=>'C∕kg','㏇'=>'Co.','㏈'=>'dB','㏉'=>'Gy','㏊'=>'ha','㏋'=>'HP','㏌'=>'in','㏍'=>'KK','㏎'=>'KM','㏏'=>'kt','㏐'=>'lm','㏑'=>'ln','㏒'=>'log','㏓'=>'lx','㏔'=>'mb','㏕'=>'mil','㏖'=>'mol','㏗'=>'PH','㏘'=>'p.m.','㏙'=>'PPM','㏚'=>'PR','㏛'=>'sr','㏜'=>'Sv','㏝'=>'Wb','㏞'=>'V∕m','㏟'=>'A∕m','㏠'=>'1日','㏡'=>'2日','㏢'=>'3日','㏣'=>'4日','㏤'=>'5日','㏥'=>'6日','㏦'=>'7日','㏧'=>'8日','㏨'=>'9日','㏩'=>'10日','㏪'=>'11日','㏫'=>'12日','㏬'=>'13日','㏭'=>'14日','㏮'=>'15日','㏯'=>'16日','㏰'=>'17日','㏱'=>'18日','㏲'=>'19日','㏳'=>'20日','㏴'=>'21日','㏵'=>'22日','㏶'=>'23日','㏷'=>'24日','㏸'=>'25日','㏹'=>'26日','㏺'=>'27日','㏻'=>'28日','㏼'=>'29日','㏽'=>'30日','㏾'=>'31日','㏿'=>'gal','豈'=>'豈','更'=>'更','車'=>'車','賈'=>'賈','滑'=>'滑','串'=>'串','句'=>'句','龜'=>'龜','龜'=>'龜','契'=>'契','金'=>'金','喇'=>'喇','奈'=>'奈','懶'=>'懶','癩'=>'癩','羅'=>'羅','蘿'=>'蘿','螺'=>'螺','裸'=>'裸','邏'=>'邏','樂'=>'樂','洛'=>'洛','烙'=>'烙','珞'=>'珞','落'=>'落','酪'=>'酪','駱'=>'駱','亂'=>'亂','卵'=>'卵','欄'=>'欄','爛'=>'爛','蘭'=>'蘭','鸞'=>'鸞','嵐'=>'嵐','濫'=>'濫','藍'=>'藍','襤'=>'襤','拉'=>'拉','臘'=>'臘','蠟'=>'蠟','廊'=>'廊','朗'=>'朗','浪'=>'浪','狼'=>'狼','郎'=>'郎','來'=>'來','冷'=>'冷','勞'=>'勞','擄'=>'擄','櫓'=>'櫓','爐'=>'爐','盧'=>'盧','老'=>'老','蘆'=>'蘆','虜'=>'虜','路'=>'路','露'=>'露','魯'=>'魯','鷺'=>'鷺','碌'=>'碌','祿'=>'祿','綠'=>'綠','菉'=>'菉','錄'=>'錄','鹿'=>'鹿','論'=>'論','壟'=>'壟','弄'=>'弄','籠'=>'籠','聾'=>'聾','牢'=>'牢','磊'=>'磊','賂'=>'賂','雷'=>'雷','壘'=>'壘','屢'=>'屢','樓'=>'樓','淚'=>'淚','漏'=>'漏','累'=>'累','縷'=>'縷','陋'=>'陋','勒'=>'勒','肋'=>'肋','凜'=>'凜','凌'=>'凌','稜'=>'稜','綾'=>'綾','菱'=>'菱','陵'=>'陵','讀'=>'讀','拏'=>'拏','樂'=>'樂','諾'=>'諾','丹'=>'丹','寧'=>'寧','怒'=>'怒','率'=>'率','異'=>'異','北'=>'北','磻'=>'磻','便'=>'便','復'=>'復','不'=>'不','泌'=>'泌','數'=>'數','索'=>'索','參'=>'參','塞'=>'塞','省'=>'省','葉'=>'葉','說'=>'說','殺'=>'殺','辰'=>'辰','沈'=>'沈','拾'=>'拾','若'=>'若','掠'=>'掠','略'=>'略','亮'=>'亮','兩'=>'兩','凉'=>'凉','梁'=>'梁','糧'=>'糧','良'=>'良','諒'=>'諒','量'=>'量','勵'=>'勵','呂'=>'呂','女'=>'女','廬'=>'廬','旅'=>'旅','濾'=>'濾','礪'=>'礪','閭'=>'閭','驪'=>'驪','麗'=>'麗','黎'=>'黎','力'=>'力','曆'=>'曆','歷'=>'歷','轢'=>'轢','年'=>'年','憐'=>'憐','戀'=>'戀','撚'=>'撚','漣'=>'漣','煉'=>'煉','璉'=>'璉','秊'=>'秊','練'=>'練','聯'=>'聯','輦'=>'輦','蓮'=>'蓮','連'=>'連','鍊'=>'鍊','列'=>'列','劣'=>'劣','咽'=>'咽','烈'=>'烈','裂'=>'裂','說'=>'說','廉'=>'廉','念'=>'念','捻'=>'捻','殮'=>'殮','簾'=>'簾','獵'=>'獵','令'=>'令','囹'=>'囹','寧'=>'寧','嶺'=>'嶺','怜'=>'怜','玲'=>'玲','瑩'=>'瑩','羚'=>'羚','聆'=>'聆','鈴'=>'鈴','零'=>'零','靈'=>'靈','領'=>'領','例'=>'例','禮'=>'禮','醴'=>'醴','隸'=>'隸','惡'=>'惡','了'=>'了','僚'=>'僚','寮'=>'寮','尿'=>'尿','料'=>'料','樂'=>'樂','燎'=>'燎','療'=>'療','蓼'=>'蓼','遼'=>'遼','龍'=>'龍','暈'=>'暈','阮'=>'阮','劉'=>'劉','杻'=>'杻','柳'=>'柳','流'=>'流','溜'=>'溜','琉'=>'琉','留'=>'留','硫'=>'硫','紐'=>'紐','類'=>'類','六'=>'六','戮'=>'戮','陸'=>'陸','倫'=>'倫','崙'=>'崙','淪'=>'淪','輪'=>'輪','律'=>'律','慄'=>'慄','栗'=>'栗','率'=>'率','隆'=>'隆','利'=>'利','吏'=>'吏','履'=>'履','易'=>'易','李'=>'李','梨'=>'梨','泥'=>'泥','理'=>'理','痢'=>'痢','罹'=>'罹','裏'=>'裏','裡'=>'裡','里'=>'里','離'=>'離','匿'=>'匿','溺'=>'溺','吝'=>'吝','燐'=>'燐','璘'=>'璘','藺'=>'藺','隣'=>'隣','鱗'=>'鱗','麟'=>'麟','林'=>'林','淋'=>'淋','臨'=>'臨','立'=>'立','笠'=>'笠','粒'=>'粒','狀'=>'狀','炙'=>'炙','識'=>'識','什'=>'什','茶'=>'茶','刺'=>'刺','切'=>'切','度'=>'度','拓'=>'拓','糖'=>'糖','宅'=>'宅','洞'=>'洞','暴'=>'暴','輻'=>'輻','行'=>'行','降'=>'降','見'=>'見','廓'=>'廓','兀'=>'兀','嗀'=>'嗀','塚'=>'塚','晴'=>'晴','凞'=>'凞','猪'=>'猪','益'=>'益','礼'=>'礼','神'=>'神','祥'=>'祥','福'=>'福','靖'=>'靖','精'=>'精','羽'=>'羽','蘒'=>'蘒','諸'=>'諸','逸'=>'逸','都'=>'都','飯'=>'飯','飼'=>'飼','館'=>'館','鶴'=>'鶴','侮'=>'侮','僧'=>'僧','免'=>'免','勉'=>'勉','勤'=>'勤','卑'=>'卑','喝'=>'喝','嘆'=>'嘆','器'=>'器','塀'=>'塀','墨'=>'墨','層'=>'層','屮'=>'屮','悔'=>'悔','慨'=>'慨','憎'=>'憎','懲'=>'懲','敏'=>'敏','既'=>'既','暑'=>'暑','梅'=>'梅','海'=>'海','渚'=>'渚','漢'=>'漢','煮'=>'煮','爫'=>'爫','琢'=>'琢','碑'=>'碑','社'=>'社','祉'=>'祉','祈'=>'祈','祐'=>'祐','祖'=>'祖','祝'=>'祝','禍'=>'禍','禎'=>'禎','穀'=>'穀','突'=>'突','節'=>'節','練'=>'練','縉'=>'縉','繁'=>'繁','署'=>'署','者'=>'者','臭'=>'臭','艹'=>'艹','艹'=>'艹','著'=>'著','褐'=>'褐','視'=>'視','謁'=>'謁','謹'=>'謹','賓'=>'賓','贈'=>'贈','辶'=>'辶','逸'=>'逸','難'=>'難','響'=>'響','頻'=>'頻','並'=>'並','况'=>'况','全'=>'全','侀'=>'侀','充'=>'充','冀'=>'冀','勇'=>'勇','勺'=>'勺','喝'=>'喝','啕'=>'啕','喙'=>'喙','嗢'=>'嗢','塚'=>'塚','墳'=>'墳','奄'=>'奄','奔'=>'奔','婢'=>'婢','嬨'=>'嬨','廒'=>'廒','廙'=>'廙','彩'=>'彩','徭'=>'徭','惘'=>'惘','慎'=>'慎','愈'=>'愈','憎'=>'憎','慠'=>'慠','懲'=>'懲','戴'=>'戴','揄'=>'揄','搜'=>'搜','摒'=>'摒','敖'=>'敖','晴'=>'晴','朗'=>'朗','望'=>'望','杖'=>'杖','歹'=>'歹','殺'=>'殺','流'=>'流','滛'=>'滛','滋'=>'滋','漢'=>'漢','瀞'=>'瀞','煮'=>'煮','瞧'=>'瞧','爵'=>'爵','犯'=>'犯','猪'=>'猪','瑱'=>'瑱','甆'=>'甆','画'=>'画','瘝'=>'瘝','瘟'=>'瘟','益'=>'益','盛'=>'盛','直'=>'直','睊'=>'睊','着'=>'着','磌'=>'磌','窱'=>'窱','節'=>'節','类'=>'类','絛'=>'絛','練'=>'練','缾'=>'缾','者'=>'者','荒'=>'荒','華'=>'華','蝹'=>'蝹','襁'=>'襁','覆'=>'覆','視'=>'視','調'=>'調','諸'=>'諸','請'=>'請','謁'=>'謁','諾'=>'諾','諭'=>'諭','謹'=>'謹','變'=>'變','贈'=>'贈','輸'=>'輸','遲'=>'遲','醙'=>'醙','鉶'=>'鉶','陼'=>'陼','難'=>'難','靖'=>'靖','韛'=>'韛','響'=>'響','頋'=>'頋','頻'=>'頻','鬒'=>'鬒','龜'=>'龜','𢡊'=>'𢡊','𢡄'=>'𢡄','𣏕'=>'𣏕','㮝'=>'㮝','䀘'=>'䀘','䀹'=>'䀹','𥉉'=>'𥉉','𥳐'=>'𥳐','𧻓'=>'𧻓','齃'=>'齃','龎'=>'龎','ff'=>'ff','fi'=>'fi','fl'=>'fl','ffi'=>'ffi','ffl'=>'ffl','ſt'=>'st','st'=>'st','ﬓ'=>'մն','ﬔ'=>'մե','ﬕ'=>'մի','ﬖ'=>'վն','ﬗ'=>'մխ','יִ'=>'יִ','ײַ'=>'ײַ','ﬠ'=>'ע','ﬡ'=>'א','ﬢ'=>'ד','ﬣ'=>'ה','ﬤ'=>'כ','ﬥ'=>'ל','ﬦ'=>'ם','ﬧ'=>'ר','ﬨ'=>'ת','﬩'=>'+','שׁ'=>'שׁ','שׂ'=>'שׂ','שּׁ'=>'שּׁ','שּׂ'=>'שּׂ','אַ'=>'אַ','אָ'=>'אָ','אּ'=>'אּ','בּ'=>'בּ','גּ'=>'גּ','דּ'=>'דּ','הּ'=>'הּ','וּ'=>'וּ','זּ'=>'זּ','טּ'=>'טּ','יּ'=>'יּ','ךּ'=>'ךּ','כּ'=>'כּ','לּ'=>'לּ','מּ'=>'מּ','נּ'=>'נּ','סּ'=>'סּ','ףּ'=>'ףּ','פּ'=>'פּ','צּ'=>'צּ','קּ'=>'קּ','רּ'=>'רּ','שּ'=>'שּ','תּ'=>'תּ','וֹ'=>'וֹ','בֿ'=>'בֿ','כֿ'=>'כֿ','פֿ'=>'פֿ','ﭏ'=>'אל','ﭐ'=>'ٱ','ﭑ'=>'ٱ','ﭒ'=>'ٻ','ﭓ'=>'ٻ','ﭔ'=>'ٻ','ﭕ'=>'ٻ','ﭖ'=>'پ','ﭗ'=>'پ','ﭘ'=>'پ','ﭙ'=>'پ','ﭚ'=>'ڀ','ﭛ'=>'ڀ','ﭜ'=>'ڀ','ﭝ'=>'ڀ','ﭞ'=>'ٺ','ﭟ'=>'ٺ','ﭠ'=>'ٺ','ﭡ'=>'ٺ','ﭢ'=>'ٿ','ﭣ'=>'ٿ','ﭤ'=>'ٿ','ﭥ'=>'ٿ','ﭦ'=>'ٹ','ﭧ'=>'ٹ','ﭨ'=>'ٹ','ﭩ'=>'ٹ','ﭪ'=>'ڤ','ﭫ'=>'ڤ','ﭬ'=>'ڤ','ﭭ'=>'ڤ','ﭮ'=>'ڦ','ﭯ'=>'ڦ','ﭰ'=>'ڦ','ﭱ'=>'ڦ','ﭲ'=>'ڄ','ﭳ'=>'ڄ','ﭴ'=>'ڄ','ﭵ'=>'ڄ','ﭶ'=>'ڃ','ﭷ'=>'ڃ','ﭸ'=>'ڃ','ﭹ'=>'ڃ','ﭺ'=>'چ','ﭻ'=>'چ','ﭼ'=>'چ','ﭽ'=>'چ','ﭾ'=>'ڇ','ﭿ'=>'ڇ','ﮀ'=>'ڇ','ﮁ'=>'ڇ','ﮂ'=>'ڍ','ﮃ'=>'ڍ','ﮄ'=>'ڌ','ﮅ'=>'ڌ','ﮆ'=>'ڎ','ﮇ'=>'ڎ','ﮈ'=>'ڈ','ﮉ'=>'ڈ','ﮊ'=>'ژ','ﮋ'=>'ژ','ﮌ'=>'ڑ','ﮍ'=>'ڑ','ﮎ'=>'ک','ﮏ'=>'ک','ﮐ'=>'ک','ﮑ'=>'ک','ﮒ'=>'گ','ﮓ'=>'گ','ﮔ'=>'گ','ﮕ'=>'گ','ﮖ'=>'ڳ','ﮗ'=>'ڳ','ﮘ'=>'ڳ','ﮙ'=>'ڳ','ﮚ'=>'ڱ','ﮛ'=>'ڱ','ﮜ'=>'ڱ','ﮝ'=>'ڱ','ﮞ'=>'ں','ﮟ'=>'ں','ﮠ'=>'ڻ','ﮡ'=>'ڻ','ﮢ'=>'ڻ','ﮣ'=>'ڻ','ﮤ'=>'ۀ','ﮥ'=>'ۀ','ﮦ'=>'ہ','ﮧ'=>'ہ','ﮨ'=>'ہ','ﮩ'=>'ہ','ﮪ'=>'ھ','ﮫ'=>'ھ','ﮬ'=>'ھ','ﮭ'=>'ھ','ﮮ'=>'ے','ﮯ'=>'ے','ﮰ'=>'ۓ','ﮱ'=>'ۓ','ﯓ'=>'ڭ','ﯔ'=>'ڭ','ﯕ'=>'ڭ','ﯖ'=>'ڭ','ﯗ'=>'ۇ','ﯘ'=>'ۇ','ﯙ'=>'ۆ','ﯚ'=>'ۆ','ﯛ'=>'ۈ','ﯜ'=>'ۈ','ﯝ'=>'ۇٴ','ﯞ'=>'ۋ','ﯟ'=>'ۋ','ﯠ'=>'ۅ','ﯡ'=>'ۅ','ﯢ'=>'ۉ','ﯣ'=>'ۉ','ﯤ'=>'ې','ﯥ'=>'ې','ﯦ'=>'ې','ﯧ'=>'ې','ﯨ'=>'ى','ﯩ'=>'ى','ﯪ'=>'ئا','ﯫ'=>'ئا','ﯬ'=>'ئە','ﯭ'=>'ئە','ﯮ'=>'ئو','ﯯ'=>'ئو','ﯰ'=>'ئۇ','ﯱ'=>'ئۇ','ﯲ'=>'ئۆ','ﯳ'=>'ئۆ','ﯴ'=>'ئۈ','ﯵ'=>'ئۈ','ﯶ'=>'ئې','ﯷ'=>'ئې','ﯸ'=>'ئې','ﯹ'=>'ئى','ﯺ'=>'ئى','ﯻ'=>'ئى','ﯼ'=>'ی','ﯽ'=>'ی','ﯾ'=>'ی','ﯿ'=>'ی','ﰀ'=>'ئج','ﰁ'=>'ئح','ﰂ'=>'ئم','ﰃ'=>'ئى','ﰄ'=>'ئي','ﰅ'=>'بج','ﰆ'=>'بح','ﰇ'=>'بخ','ﰈ'=>'بم','ﰉ'=>'بى','ﰊ'=>'بي','ﰋ'=>'تج','ﰌ'=>'تح','ﰍ'=>'تخ','ﰎ'=>'تم','ﰏ'=>'تى','ﰐ'=>'تي','ﰑ'=>'ثج','ﰒ'=>'ثم','ﰓ'=>'ثى','ﰔ'=>'ثي','ﰕ'=>'جح','ﰖ'=>'جم','ﰗ'=>'حج','ﰘ'=>'حم','ﰙ'=>'خج','ﰚ'=>'خح','ﰛ'=>'خم','ﰜ'=>'سج','ﰝ'=>'سح','ﰞ'=>'سخ','ﰟ'=>'سم','ﰠ'=>'صح','ﰡ'=>'صم','ﰢ'=>'ضج','ﰣ'=>'ضح','ﰤ'=>'ضخ','ﰥ'=>'ضم','ﰦ'=>'طح','ﰧ'=>'طم','ﰨ'=>'ظم','ﰩ'=>'عج','ﰪ'=>'عم','ﰫ'=>'غج','ﰬ'=>'غم','ﰭ'=>'فج','ﰮ'=>'فح','ﰯ'=>'فخ','ﰰ'=>'فم','ﰱ'=>'فى','ﰲ'=>'في','ﰳ'=>'قح','ﰴ'=>'قم','ﰵ'=>'قى','ﰶ'=>'قي','ﰷ'=>'كا','ﰸ'=>'كج','ﰹ'=>'كح','ﰺ'=>'كخ','ﰻ'=>'كل','ﰼ'=>'كم','ﰽ'=>'كى','ﰾ'=>'كي','ﰿ'=>'لج','ﱀ'=>'لح','ﱁ'=>'لخ','ﱂ'=>'لم','ﱃ'=>'لى','ﱄ'=>'لي','ﱅ'=>'مج','ﱆ'=>'مح','ﱇ'=>'مخ','ﱈ'=>'مم','ﱉ'=>'مى','ﱊ'=>'مي','ﱋ'=>'نج','ﱌ'=>'نح','ﱍ'=>'نخ','ﱎ'=>'نم','ﱏ'=>'نى','ﱐ'=>'ني','ﱑ'=>'هج','ﱒ'=>'هم','ﱓ'=>'هى','ﱔ'=>'هي','ﱕ'=>'يج','ﱖ'=>'يح','ﱗ'=>'يخ','ﱘ'=>'يم','ﱙ'=>'يى','ﱚ'=>'يي','ﱛ'=>'ذٰ','ﱜ'=>'رٰ','ﱝ'=>'ىٰ','ﱞ'=>' ٌّ','ﱟ'=>' ٍّ','ﱠ'=>' َّ','ﱡ'=>' ُّ','ﱢ'=>' ِّ','ﱣ'=>' ّٰ','ﱤ'=>'ئر','ﱥ'=>'ئز','ﱦ'=>'ئم','ﱧ'=>'ئن','ﱨ'=>'ئى','ﱩ'=>'ئي','ﱪ'=>'بر','ﱫ'=>'بز','ﱬ'=>'بم','ﱭ'=>'بن','ﱮ'=>'بى','ﱯ'=>'بي','ﱰ'=>'تر','ﱱ'=>'تز','ﱲ'=>'تم','ﱳ'=>'تن','ﱴ'=>'تى','ﱵ'=>'تي','ﱶ'=>'ثر','ﱷ'=>'ثز','ﱸ'=>'ثم','ﱹ'=>'ثن','ﱺ'=>'ثى','ﱻ'=>'ثي','ﱼ'=>'فى','ﱽ'=>'في','ﱾ'=>'قى','ﱿ'=>'قي','ﲀ'=>'كا','ﲁ'=>'كل','ﲂ'=>'كم','ﲃ'=>'كى','ﲄ'=>'كي','ﲅ'=>'لم','ﲆ'=>'لى','ﲇ'=>'لي','ﲈ'=>'ما','ﲉ'=>'مم','ﲊ'=>'نر','ﲋ'=>'نز','ﲌ'=>'نم','ﲍ'=>'نن','ﲎ'=>'نى','ﲏ'=>'ني','ﲐ'=>'ىٰ','ﲑ'=>'ير','ﲒ'=>'يز','ﲓ'=>'يم','ﲔ'=>'ين','ﲕ'=>'يى','ﲖ'=>'يي','ﲗ'=>'ئج','ﲘ'=>'ئح','ﲙ'=>'ئخ','ﲚ'=>'ئم','ﲛ'=>'ئه','ﲜ'=>'بج','ﲝ'=>'بح','ﲞ'=>'بخ','ﲟ'=>'بم','ﲠ'=>'به','ﲡ'=>'تج','ﲢ'=>'تح','ﲣ'=>'تخ','ﲤ'=>'تم','ﲥ'=>'ته','ﲦ'=>'ثم','ﲧ'=>'جح','ﲨ'=>'جم','ﲩ'=>'حج','ﲪ'=>'حم','ﲫ'=>'خج','ﲬ'=>'خم','ﲭ'=>'سج','ﲮ'=>'سح','ﲯ'=>'سخ','ﲰ'=>'سم','ﲱ'=>'صح','ﲲ'=>'صخ','ﲳ'=>'صم','ﲴ'=>'ضج','ﲵ'=>'ضح','ﲶ'=>'ضخ','ﲷ'=>'ضم','ﲸ'=>'طح','ﲹ'=>'ظم','ﲺ'=>'عج','ﲻ'=>'عم','ﲼ'=>'غج','ﲽ'=>'غم','ﲾ'=>'فج','ﲿ'=>'فح','ﳀ'=>'فخ','ﳁ'=>'فم','ﳂ'=>'قح','ﳃ'=>'قم','ﳄ'=>'كج','ﳅ'=>'كح','ﳆ'=>'كخ','ﳇ'=>'كل','ﳈ'=>'كم','ﳉ'=>'لج','ﳊ'=>'لح','ﳋ'=>'لخ','ﳌ'=>'لم','ﳍ'=>'له','ﳎ'=>'مج','ﳏ'=>'مح','ﳐ'=>'مخ','ﳑ'=>'مم','ﳒ'=>'نج','ﳓ'=>'نح','ﳔ'=>'نخ','ﳕ'=>'نم','ﳖ'=>'نه','ﳗ'=>'هج','ﳘ'=>'هم','ﳙ'=>'هٰ','ﳚ'=>'يج','ﳛ'=>'يح','ﳜ'=>'يخ','ﳝ'=>'يم','ﳞ'=>'يه','ﳟ'=>'ئم','ﳠ'=>'ئه','ﳡ'=>'بم','ﳢ'=>'به','ﳣ'=>'تم','ﳤ'=>'ته','ﳥ'=>'ثم','ﳦ'=>'ثه','ﳧ'=>'سم','ﳨ'=>'سه','ﳩ'=>'شم','ﳪ'=>'شه','ﳫ'=>'كل','ﳬ'=>'كم','ﳭ'=>'لم','ﳮ'=>'نم','ﳯ'=>'نه','ﳰ'=>'يم','ﳱ'=>'يه','ﳲ'=>'ـَّ','ﳳ'=>'ـُّ','ﳴ'=>'ـِّ','ﳵ'=>'طى','ﳶ'=>'طي','ﳷ'=>'عى','ﳸ'=>'عي','ﳹ'=>'غى','ﳺ'=>'غي','ﳻ'=>'سى','ﳼ'=>'سي','ﳽ'=>'شى','ﳾ'=>'شي','ﳿ'=>'حى','ﴀ'=>'حي','ﴁ'=>'جى','ﴂ'=>'جي','ﴃ'=>'خى','ﴄ'=>'خي','ﴅ'=>'صى','ﴆ'=>'صي','ﴇ'=>'ضى','ﴈ'=>'ضي','ﴉ'=>'شج','ﴊ'=>'شح','ﴋ'=>'شخ','ﴌ'=>'شم','ﴍ'=>'شر','ﴎ'=>'سر','ﴏ'=>'صر','ﴐ'=>'ضر','ﴑ'=>'طى','ﴒ'=>'طي','ﴓ'=>'عى','ﴔ'=>'عي','ﴕ'=>'غى','ﴖ'=>'غي','ﴗ'=>'سى','ﴘ'=>'سي','ﴙ'=>'شى','ﴚ'=>'شي','ﴛ'=>'حى','ﴜ'=>'حي','ﴝ'=>'جى','ﴞ'=>'جي','ﴟ'=>'خى','ﴠ'=>'خي','ﴡ'=>'صى','ﴢ'=>'صي','ﴣ'=>'ضى','ﴤ'=>'ضي','ﴥ'=>'شج','ﴦ'=>'شح','ﴧ'=>'شخ','ﴨ'=>'شم','ﴩ'=>'شر','ﴪ'=>'سر','ﴫ'=>'صر','ﴬ'=>'ضر','ﴭ'=>'شج','ﴮ'=>'شح','ﴯ'=>'شخ','ﴰ'=>'شم','ﴱ'=>'سه','ﴲ'=>'شه','ﴳ'=>'طم','ﴴ'=>'سج','ﴵ'=>'سح','ﴶ'=>'سخ','ﴷ'=>'شج','ﴸ'=>'شح','ﴹ'=>'شخ','ﴺ'=>'طم','ﴻ'=>'ظم','ﴼ'=>'اً','ﴽ'=>'اً','ﵐ'=>'تجم','ﵑ'=>'تحج','ﵒ'=>'تحج','ﵓ'=>'تحم','ﵔ'=>'تخم','ﵕ'=>'تمج','ﵖ'=>'تمح','ﵗ'=>'تمخ','ﵘ'=>'جمح','ﵙ'=>'جمح','ﵚ'=>'حمي','ﵛ'=>'حمى','ﵜ'=>'سحج','ﵝ'=>'سجح','ﵞ'=>'سجى','ﵟ'=>'سمح','ﵠ'=>'سمح','ﵡ'=>'سمج','ﵢ'=>'سمم','ﵣ'=>'سمم','ﵤ'=>'صحح','ﵥ'=>'صحح','ﵦ'=>'صمم','ﵧ'=>'شحم','ﵨ'=>'شحم','ﵩ'=>'شجي','ﵪ'=>'شمخ','ﵫ'=>'شمخ','ﵬ'=>'شمم','ﵭ'=>'شمم','ﵮ'=>'ضحى','ﵯ'=>'ضخم','ﵰ'=>'ضخم','ﵱ'=>'طمح','ﵲ'=>'طمح','ﵳ'=>'طمم','ﵴ'=>'طمي','ﵵ'=>'عجم','ﵶ'=>'عمم','ﵷ'=>'عمم','ﵸ'=>'عمى','ﵹ'=>'غمم','ﵺ'=>'غمي','ﵻ'=>'غمى','ﵼ'=>'فخم','ﵽ'=>'فخم','ﵾ'=>'قمح','ﵿ'=>'قمم','ﶀ'=>'لحم','ﶁ'=>'لحي','ﶂ'=>'لحى','ﶃ'=>'لجج','ﶄ'=>'لجج','ﶅ'=>'لخم','ﶆ'=>'لخم','ﶇ'=>'لمح','ﶈ'=>'لمح','ﶉ'=>'محج','ﶊ'=>'محم','ﶋ'=>'محي','ﶌ'=>'مجح','ﶍ'=>'مجم','ﶎ'=>'مخج','ﶏ'=>'مخم','ﶒ'=>'مجخ','ﶓ'=>'همج','ﶔ'=>'همم','ﶕ'=>'نحم','ﶖ'=>'نحى','ﶗ'=>'نجم','ﶘ'=>'نجم','ﶙ'=>'نجى','ﶚ'=>'نمي','ﶛ'=>'نمى','ﶜ'=>'يمم','ﶝ'=>'يمم','ﶞ'=>'بخي','ﶟ'=>'تجي','ﶠ'=>'تجى','ﶡ'=>'تخي','ﶢ'=>'تخى','ﶣ'=>'تمي','ﶤ'=>'تمى','ﶥ'=>'جمي','ﶦ'=>'جحى','ﶧ'=>'جمى','ﶨ'=>'سخى','ﶩ'=>'صحي','ﶪ'=>'شحي','ﶫ'=>'ضحي','ﶬ'=>'لجي','ﶭ'=>'لمي','ﶮ'=>'يحي','ﶯ'=>'يجي','ﶰ'=>'يمي','ﶱ'=>'ممي','ﶲ'=>'قمي','ﶳ'=>'نحي','ﶴ'=>'قمح','ﶵ'=>'لحم','ﶶ'=>'عمي','ﶷ'=>'كمي','ﶸ'=>'نجح','ﶹ'=>'مخي','ﶺ'=>'لجم','ﶻ'=>'كمم','ﶼ'=>'لجم','ﶽ'=>'نجح','ﶾ'=>'جحي','ﶿ'=>'حجي','ﷀ'=>'مجي','ﷁ'=>'فمي','ﷂ'=>'بحي','ﷃ'=>'كمم','ﷄ'=>'عجم','ﷅ'=>'صمم','ﷆ'=>'سخي','ﷇ'=>'نجي','ﷰ'=>'صلے','ﷱ'=>'قلے','ﷲ'=>'الله','ﷳ'=>'اكبر','ﷴ'=>'محمد','ﷵ'=>'صلعم','ﷶ'=>'رسول','ﷷ'=>'عليه','ﷸ'=>'وسلم','ﷹ'=>'صلى','ﷺ'=>'صلى الله عليه وسلم','ﷻ'=>'جل جلاله','﷼'=>'ریال','︐'=>',','︑'=>'、','︒'=>'。','︓'=>':','︔'=>';','︕'=>'!','︖'=>'?','︗'=>'〖','︘'=>'〗','︙'=>'...','︰'=>'..','︱'=>'—','︲'=>'–','︳'=>'_','︴'=>'_','︵'=>'(','︶'=>')','︷'=>'{','︸'=>'}','︹'=>'〔','︺'=>'〕','︻'=>'【','︼'=>'】','︽'=>'《','︾'=>'》','︿'=>'〈','﹀'=>'〉','﹁'=>'「','﹂'=>'」','﹃'=>'『','﹄'=>'』','﹇'=>'[','﹈'=>']','﹉'=>' ̅','﹊'=>' ̅','﹋'=>' ̅','﹌'=>' ̅','﹍'=>'_','﹎'=>'_','﹏'=>'_','﹐'=>',','﹑'=>'、','﹒'=>'.','﹔'=>';','﹕'=>':','﹖'=>'?','﹗'=>'!','﹘'=>'—','﹙'=>'(','﹚'=>')','﹛'=>'{','﹜'=>'}','﹝'=>'〔','﹞'=>'〕','﹟'=>'#','﹠'=>'&','﹡'=>'*','﹢'=>'+','﹣'=>'-','﹤'=>'<','﹥'=>'>','﹦'=>'=','﹨'=>'\\','﹩'=>'$','﹪'=>'%','﹫'=>'@','ﹰ'=>' ً','ﹱ'=>'ـً','ﹲ'=>' ٌ','ﹴ'=>' ٍ','ﹶ'=>' َ','ﹷ'=>'ـَ','ﹸ'=>' ُ','ﹹ'=>'ـُ','ﹺ'=>' ِ','ﹻ'=>'ـِ','ﹼ'=>' ّ','ﹽ'=>'ـّ','ﹾ'=>' ْ','ﹿ'=>'ـْ','ﺀ'=>'ء','ﺁ'=>'آ','ﺂ'=>'آ','ﺃ'=>'أ','ﺄ'=>'أ','ﺅ'=>'ؤ','ﺆ'=>'ؤ','ﺇ'=>'إ','ﺈ'=>'إ','ﺉ'=>'ئ','ﺊ'=>'ئ','ﺋ'=>'ئ','ﺌ'=>'ئ','ﺍ'=>'ا','ﺎ'=>'ا','ﺏ'=>'ب','ﺐ'=>'ب','ﺑ'=>'ب','ﺒ'=>'ب','ﺓ'=>'ة','ﺔ'=>'ة','ﺕ'=>'ت','ﺖ'=>'ت','ﺗ'=>'ت','ﺘ'=>'ت','ﺙ'=>'ث','ﺚ'=>'ث','ﺛ'=>'ث','ﺜ'=>'ث','ﺝ'=>'ج','ﺞ'=>'ج','ﺟ'=>'ج','ﺠ'=>'ج','ﺡ'=>'ح','ﺢ'=>'ح','ﺣ'=>'ح','ﺤ'=>'ح','ﺥ'=>'خ','ﺦ'=>'خ','ﺧ'=>'خ','ﺨ'=>'خ','ﺩ'=>'د','ﺪ'=>'د','ﺫ'=>'ذ','ﺬ'=>'ذ','ﺭ'=>'ر','ﺮ'=>'ر','ﺯ'=>'ز','ﺰ'=>'ز','ﺱ'=>'س','ﺲ'=>'س','ﺳ'=>'س','ﺴ'=>'س','ﺵ'=>'ش','ﺶ'=>'ش','ﺷ'=>'ش','ﺸ'=>'ش','ﺹ'=>'ص','ﺺ'=>'ص','ﺻ'=>'ص','ﺼ'=>'ص','ﺽ'=>'ض','ﺾ'=>'ض','ﺿ'=>'ض','ﻀ'=>'ض','ﻁ'=>'ط','ﻂ'=>'ط','ﻃ'=>'ط','ﻄ'=>'ط','ﻅ'=>'ظ','ﻆ'=>'ظ','ﻇ'=>'ظ','ﻈ'=>'ظ','ﻉ'=>'ع','ﻊ'=>'ع','ﻋ'=>'ع','ﻌ'=>'ع','ﻍ'=>'غ','ﻎ'=>'غ','ﻏ'=>'غ','ﻐ'=>'غ','ﻑ'=>'ف','ﻒ'=>'ف','ﻓ'=>'ف','ﻔ'=>'ف','ﻕ'=>'ق','ﻖ'=>'ق','ﻗ'=>'ق','ﻘ'=>'ق','ﻙ'=>'ك','ﻚ'=>'ك','ﻛ'=>'ك','ﻜ'=>'ك','ﻝ'=>'ل','ﻞ'=>'ل','ﻟ'=>'ل','ﻠ'=>'ل','ﻡ'=>'م','ﻢ'=>'م','ﻣ'=>'م','ﻤ'=>'م','ﻥ'=>'ن','ﻦ'=>'ن','ﻧ'=>'ن','ﻨ'=>'ن','ﻩ'=>'ه','ﻪ'=>'ه','ﻫ'=>'ه','ﻬ'=>'ه','ﻭ'=>'و','ﻮ'=>'و','ﻯ'=>'ى','ﻰ'=>'ى','ﻱ'=>'ي','ﻲ'=>'ي','ﻳ'=>'ي','ﻴ'=>'ي','ﻵ'=>'لآ','ﻶ'=>'لآ','ﻷ'=>'لأ','ﻸ'=>'لأ','ﻹ'=>'لإ','ﻺ'=>'لإ','ﻻ'=>'لا','ﻼ'=>'لا','!'=>'!','"'=>'"','#'=>'#','$'=>'$','%'=>'%','&'=>'&','''=>'\'','('=>'(',')'=>')','*'=>'*','+'=>'+',','=>',','-'=>'-','.'=>'.','/'=>'/','0'=>'0','1'=>'1','2'=>'2','3'=>'3','4'=>'4','5'=>'5','6'=>'6','7'=>'7','8'=>'8','9'=>'9',':'=>':',';'=>';','<'=>'<','='=>'=','>'=>'>','?'=>'?','@'=>'@','A'=>'A','B'=>'B','C'=>'C','D'=>'D','E'=>'E','F'=>'F','G'=>'G','H'=>'H','I'=>'I','J'=>'J','K'=>'K','L'=>'L','M'=>'M','N'=>'N','O'=>'O','P'=>'P','Q'=>'Q','R'=>'R','S'=>'S','T'=>'T','U'=>'U','V'=>'V','W'=>'W','X'=>'X','Y'=>'Y','Z'=>'Z','['=>'[','\'=>'\\',']'=>']','^'=>'^','_'=>'_','`'=>'`','a'=>'a','b'=>'b','c'=>'c','d'=>'d','e'=>'e','f'=>'f','g'=>'g','h'=>'h','i'=>'i','j'=>'j','k'=>'k','l'=>'l','m'=>'m','n'=>'n','o'=>'o','p'=>'p','q'=>'q','r'=>'r','s'=>'s','t'=>'t','u'=>'u','v'=>'v','w'=>'w','x'=>'x','y'=>'y','z'=>'z','{'=>'{','|'=>'|','}'=>'}','~'=>'~','⦅'=>'⦅','⦆'=>'⦆','。'=>'。','「'=>'「','」'=>'」','、'=>'、','・'=>'・','ヲ'=>'ヲ','ァ'=>'ァ','ィ'=>'ィ','ゥ'=>'ゥ','ェ'=>'ェ','ォ'=>'ォ','ャ'=>'ャ','ュ'=>'ュ','ョ'=>'ョ','ッ'=>'ッ','ー'=>'ー','ア'=>'ア','イ'=>'イ','ウ'=>'ウ','エ'=>'エ','オ'=>'オ','カ'=>'カ','キ'=>'キ','ク'=>'ク','ケ'=>'ケ','コ'=>'コ','サ'=>'サ','シ'=>'シ','ス'=>'ス','セ'=>'セ','ソ'=>'ソ','タ'=>'タ','チ'=>'チ','ツ'=>'ツ','テ'=>'テ','ト'=>'ト','ナ'=>'ナ','ニ'=>'ニ','ヌ'=>'ヌ','ネ'=>'ネ','ノ'=>'ノ','ハ'=>'ハ','ヒ'=>'ヒ','フ'=>'フ','ヘ'=>'ヘ','ホ'=>'ホ','マ'=>'マ','ミ'=>'ミ','ム'=>'ム','メ'=>'メ','モ'=>'モ','ヤ'=>'ヤ','ユ'=>'ユ','ヨ'=>'ヨ','ラ'=>'ラ','リ'=>'リ','ル'=>'ル','レ'=>'レ','ロ'=>'ロ','ワ'=>'ワ','ン'=>'ン','゙'=>'゙','゚'=>'゚','ᅠ'=>'ᅠ','ᄀ'=>'ᄀ','ᄁ'=>'ᄁ','ᆪ'=>'ᆪ','ᄂ'=>'ᄂ','ᆬ'=>'ᆬ','ᆭ'=>'ᆭ','ᄃ'=>'ᄃ','ᄄ'=>'ᄄ','ᄅ'=>'ᄅ','ᆰ'=>'ᆰ','ᆱ'=>'ᆱ','ᆲ'=>'ᆲ','ᆳ'=>'ᆳ','ᆴ'=>'ᆴ','ᆵ'=>'ᆵ','ᄚ'=>'ᄚ','ᄆ'=>'ᄆ','ᄇ'=>'ᄇ','ᄈ'=>'ᄈ','ᄡ'=>'ᄡ','ᄉ'=>'ᄉ','ᄊ'=>'ᄊ','ᄋ'=>'ᄋ','ᄌ'=>'ᄌ','ᄍ'=>'ᄍ','ᄎ'=>'ᄎ','ᄏ'=>'ᄏ','ᄐ'=>'ᄐ','ᄑ'=>'ᄑ','ᄒ'=>'ᄒ','ᅡ'=>'ᅡ','ᅢ'=>'ᅢ','ᅣ'=>'ᅣ','ᅤ'=>'ᅤ','ᅥ'=>'ᅥ','ᅦ'=>'ᅦ','ᅧ'=>'ᅧ','ᅨ'=>'ᅨ','ᅩ'=>'ᅩ','ᅪ'=>'ᅪ','ᅫ'=>'ᅫ','ᅬ'=>'ᅬ','ᅭ'=>'ᅭ','ᅮ'=>'ᅮ','ᅯ'=>'ᅯ','ᅰ'=>'ᅰ','ᅱ'=>'ᅱ','ᅲ'=>'ᅲ','ᅳ'=>'ᅳ','ᅴ'=>'ᅴ','ᅵ'=>'ᅵ','¢'=>'¢','£'=>'£','¬'=>'¬',' ̄'=>' ̄','¦'=>'¦','¥'=>'¥','₩'=>'₩','│'=>'│','←'=>'←','↑'=>'↑','→'=>'→','↓'=>'↓','■'=>'■','○'=>'○','𝅗𝅥'=>'𝅗𝅥','𝅘𝅥'=>'𝅘𝅥','𝅘𝅥𝅮'=>'𝅘𝅥𝅮','𝅘𝅥𝅯'=>'𝅘𝅥𝅯','𝅘𝅥𝅰'=>'𝅘𝅥𝅰','𝅘𝅥𝅱'=>'𝅘𝅥𝅱','𝅘𝅥𝅲'=>'𝅘𝅥𝅲','𝆹𝅥'=>'𝆹𝅥','𝆺𝅥'=>'𝆺𝅥','𝆹𝅥𝅮'=>'𝆹𝅥𝅮','𝆺𝅥𝅮'=>'𝆺𝅥𝅮','𝆹𝅥𝅯'=>'𝆹𝅥𝅯','𝆺𝅥𝅯'=>'𝆺𝅥𝅯','𝐀'=>'A','𝐁'=>'B','𝐂'=>'C','𝐃'=>'D','𝐄'=>'E','𝐅'=>'F','𝐆'=>'G','𝐇'=>'H','𝐈'=>'I','𝐉'=>'J','𝐊'=>'K','𝐋'=>'L','𝐌'=>'M','𝐍'=>'N','𝐎'=>'O','𝐏'=>'P','𝐐'=>'Q','𝐑'=>'R','𝐒'=>'S','𝐓'=>'T','𝐔'=>'U','𝐕'=>'V','𝐖'=>'W','𝐗'=>'X','𝐘'=>'Y','𝐙'=>'Z','𝐚'=>'a','𝐛'=>'b','𝐜'=>'c','𝐝'=>'d','𝐞'=>'e','𝐟'=>'f','𝐠'=>'g','𝐡'=>'h','𝐢'=>'i','𝐣'=>'j','𝐤'=>'k','𝐥'=>'l','𝐦'=>'m','𝐧'=>'n','𝐨'=>'o','𝐩'=>'p','𝐪'=>'q','𝐫'=>'r','𝐬'=>'s','𝐭'=>'t','𝐮'=>'u','𝐯'=>'v','𝐰'=>'w','𝐱'=>'x','𝐲'=>'y','𝐳'=>'z','𝐴'=>'A','𝐵'=>'B','𝐶'=>'C','𝐷'=>'D','𝐸'=>'E','𝐹'=>'F','𝐺'=>'G','𝐻'=>'H','𝐼'=>'I','𝐽'=>'J','𝐾'=>'K','𝐿'=>'L','𝑀'=>'M','𝑁'=>'N','𝑂'=>'O','𝑃'=>'P','𝑄'=>'Q','𝑅'=>'R','𝑆'=>'S','𝑇'=>'T','𝑈'=>'U','𝑉'=>'V','𝑊'=>'W','𝑋'=>'X','𝑌'=>'Y','𝑍'=>'Z','𝑎'=>'a','𝑏'=>'b','𝑐'=>'c','𝑑'=>'d','𝑒'=>'e','𝑓'=>'f','𝑔'=>'g','𝑖'=>'i','𝑗'=>'j','𝑘'=>'k','𝑙'=>'l','𝑚'=>'m','𝑛'=>'n','𝑜'=>'o','𝑝'=>'p','𝑞'=>'q','𝑟'=>'r','𝑠'=>'s','𝑡'=>'t','𝑢'=>'u','𝑣'=>'v','𝑤'=>'w','𝑥'=>'x','𝑦'=>'y','𝑧'=>'z','𝑨'=>'A','𝑩'=>'B','𝑪'=>'C','𝑫'=>'D','𝑬'=>'E','𝑭'=>'F','𝑮'=>'G','𝑯'=>'H','𝑰'=>'I','𝑱'=>'J','𝑲'=>'K','𝑳'=>'L','𝑴'=>'M','𝑵'=>'N','𝑶'=>'O','𝑷'=>'P','𝑸'=>'Q','𝑹'=>'R','𝑺'=>'S','𝑻'=>'T','𝑼'=>'U','𝑽'=>'V','𝑾'=>'W','𝑿'=>'X','𝒀'=>'Y','𝒁'=>'Z','𝒂'=>'a','𝒃'=>'b','𝒄'=>'c','𝒅'=>'d','𝒆'=>'e','𝒇'=>'f','𝒈'=>'g','𝒉'=>'h','𝒊'=>'i','𝒋'=>'j','𝒌'=>'k','𝒍'=>'l','𝒎'=>'m','𝒏'=>'n','𝒐'=>'o','𝒑'=>'p','𝒒'=>'q','𝒓'=>'r','𝒔'=>'s','𝒕'=>'t','𝒖'=>'u','𝒗'=>'v','𝒘'=>'w','𝒙'=>'x','𝒚'=>'y','𝒛'=>'z','𝒜'=>'A','𝒞'=>'C','𝒟'=>'D','𝒢'=>'G','𝒥'=>'J','𝒦'=>'K','𝒩'=>'N','𝒪'=>'O','𝒫'=>'P','𝒬'=>'Q','𝒮'=>'S','𝒯'=>'T','𝒰'=>'U','𝒱'=>'V','𝒲'=>'W','𝒳'=>'X','𝒴'=>'Y','𝒵'=>'Z','𝒶'=>'a','𝒷'=>'b','𝒸'=>'c','𝒹'=>'d','𝒻'=>'f','𝒽'=>'h','𝒾'=>'i','𝒿'=>'j','𝓀'=>'k','𝓁'=>'l','𝓂'=>'m','𝓃'=>'n','𝓅'=>'p','𝓆'=>'q','𝓇'=>'r','𝓈'=>'s','𝓉'=>'t','𝓊'=>'u','𝓋'=>'v','𝓌'=>'w','𝓍'=>'x','𝓎'=>'y','𝓏'=>'z','𝓐'=>'A','𝓑'=>'B','𝓒'=>'C','𝓓'=>'D','𝓔'=>'E','𝓕'=>'F','𝓖'=>'G','𝓗'=>'H','𝓘'=>'I','𝓙'=>'J','𝓚'=>'K','𝓛'=>'L','𝓜'=>'M','𝓝'=>'N','𝓞'=>'O','𝓟'=>'P','𝓠'=>'Q','𝓡'=>'R','𝓢'=>'S','𝓣'=>'T','𝓤'=>'U','𝓥'=>'V','𝓦'=>'W','𝓧'=>'X','𝓨'=>'Y','𝓩'=>'Z','𝓪'=>'a','𝓫'=>'b','𝓬'=>'c','𝓭'=>'d','𝓮'=>'e','𝓯'=>'f','𝓰'=>'g','𝓱'=>'h','𝓲'=>'i','𝓳'=>'j','𝓴'=>'k','𝓵'=>'l','𝓶'=>'m','𝓷'=>'n','𝓸'=>'o','𝓹'=>'p','𝓺'=>'q','𝓻'=>'r','𝓼'=>'s','𝓽'=>'t','𝓾'=>'u','𝓿'=>'v','𝔀'=>'w','𝔁'=>'x','𝔂'=>'y','𝔃'=>'z','𝔄'=>'A','𝔅'=>'B','𝔇'=>'D','𝔈'=>'E','𝔉'=>'F','𝔊'=>'G','𝔍'=>'J','𝔎'=>'K','𝔏'=>'L','𝔐'=>'M','𝔑'=>'N','𝔒'=>'O','𝔓'=>'P','𝔔'=>'Q','𝔖'=>'S','𝔗'=>'T','𝔘'=>'U','𝔙'=>'V','𝔚'=>'W','𝔛'=>'X','𝔜'=>'Y','𝔞'=>'a','𝔟'=>'b','𝔠'=>'c','𝔡'=>'d','𝔢'=>'e','𝔣'=>'f','𝔤'=>'g','𝔥'=>'h','𝔦'=>'i','𝔧'=>'j','𝔨'=>'k','𝔩'=>'l','𝔪'=>'m','𝔫'=>'n','𝔬'=>'o','𝔭'=>'p','𝔮'=>'q','𝔯'=>'r','𝔰'=>'s','𝔱'=>'t','𝔲'=>'u','𝔳'=>'v','𝔴'=>'w','𝔵'=>'x','𝔶'=>'y','𝔷'=>'z','𝔸'=>'A','𝔹'=>'B','𝔻'=>'D','𝔼'=>'E','𝔽'=>'F','𝔾'=>'G','𝕀'=>'I','𝕁'=>'J','𝕂'=>'K','𝕃'=>'L','𝕄'=>'M','𝕆'=>'O','𝕊'=>'S','𝕋'=>'T','𝕌'=>'U','𝕍'=>'V','𝕎'=>'W','𝕏'=>'X','𝕐'=>'Y','𝕒'=>'a','𝕓'=>'b','𝕔'=>'c','𝕕'=>'d','𝕖'=>'e','𝕗'=>'f','𝕘'=>'g','𝕙'=>'h','𝕚'=>'i','𝕛'=>'j','𝕜'=>'k','𝕝'=>'l','𝕞'=>'m','𝕟'=>'n','𝕠'=>'o','𝕡'=>'p','𝕢'=>'q','𝕣'=>'r','𝕤'=>'s','𝕥'=>'t','𝕦'=>'u','𝕧'=>'v','𝕨'=>'w','𝕩'=>'x','𝕪'=>'y','𝕫'=>'z','𝕬'=>'A','𝕭'=>'B','𝕮'=>'C','𝕯'=>'D','𝕰'=>'E','𝕱'=>'F','𝕲'=>'G','𝕳'=>'H','𝕴'=>'I','𝕵'=>'J','𝕶'=>'K','𝕷'=>'L','𝕸'=>'M','𝕹'=>'N','𝕺'=>'O','𝕻'=>'P','𝕼'=>'Q','𝕽'=>'R','𝕾'=>'S','𝕿'=>'T','𝖀'=>'U','𝖁'=>'V','𝖂'=>'W','𝖃'=>'X','𝖄'=>'Y','𝖅'=>'Z','𝖆'=>'a','𝖇'=>'b','𝖈'=>'c','𝖉'=>'d','𝖊'=>'e','𝖋'=>'f','𝖌'=>'g','𝖍'=>'h','𝖎'=>'i','𝖏'=>'j','𝖐'=>'k','𝖑'=>'l','𝖒'=>'m','𝖓'=>'n','𝖔'=>'o','𝖕'=>'p','𝖖'=>'q','𝖗'=>'r','𝖘'=>'s','𝖙'=>'t','𝖚'=>'u','𝖛'=>'v','𝖜'=>'w','𝖝'=>'x','𝖞'=>'y','𝖟'=>'z','𝖠'=>'A','𝖡'=>'B','𝖢'=>'C','𝖣'=>'D','𝖤'=>'E','𝖥'=>'F','𝖦'=>'G','𝖧'=>'H','𝖨'=>'I','𝖩'=>'J','𝖪'=>'K','𝖫'=>'L','𝖬'=>'M','𝖭'=>'N','𝖮'=>'O','𝖯'=>'P','𝖰'=>'Q','𝖱'=>'R','𝖲'=>'S','𝖳'=>'T','𝖴'=>'U','𝖵'=>'V','𝖶'=>'W','𝖷'=>'X','𝖸'=>'Y','𝖹'=>'Z','𝖺'=>'a','𝖻'=>'b','𝖼'=>'c','𝖽'=>'d','𝖾'=>'e','𝖿'=>'f','𝗀'=>'g','𝗁'=>'h','𝗂'=>'i','𝗃'=>'j','𝗄'=>'k','𝗅'=>'l','𝗆'=>'m','𝗇'=>'n','𝗈'=>'o','𝗉'=>'p','𝗊'=>'q','𝗋'=>'r','𝗌'=>'s','𝗍'=>'t','𝗎'=>'u','𝗏'=>'v','𝗐'=>'w','𝗑'=>'x','𝗒'=>'y','𝗓'=>'z','𝗔'=>'A','𝗕'=>'B','𝗖'=>'C','𝗗'=>'D','𝗘'=>'E','𝗙'=>'F','𝗚'=>'G','𝗛'=>'H','𝗜'=>'I','𝗝'=>'J','𝗞'=>'K','𝗟'=>'L','𝗠'=>'M','𝗡'=>'N','𝗢'=>'O','𝗣'=>'P','𝗤'=>'Q','𝗥'=>'R','𝗦'=>'S','𝗧'=>'T','𝗨'=>'U','𝗩'=>'V','𝗪'=>'W','𝗫'=>'X','𝗬'=>'Y','𝗭'=>'Z','𝗮'=>'a','𝗯'=>'b','𝗰'=>'c','𝗱'=>'d','𝗲'=>'e','𝗳'=>'f','𝗴'=>'g','𝗵'=>'h','𝗶'=>'i','𝗷'=>'j','𝗸'=>'k','𝗹'=>'l','𝗺'=>'m','𝗻'=>'n','𝗼'=>'o','𝗽'=>'p','𝗾'=>'q','𝗿'=>'r','𝘀'=>'s','𝘁'=>'t','𝘂'=>'u','𝘃'=>'v','𝘄'=>'w','𝘅'=>'x','𝘆'=>'y','𝘇'=>'z','𝘈'=>'A','𝘉'=>'B','𝘊'=>'C','𝘋'=>'D','𝘌'=>'E','𝘍'=>'F','𝘎'=>'G','𝘏'=>'H','𝘐'=>'I','𝘑'=>'J','𝘒'=>'K','𝘓'=>'L','𝘔'=>'M','𝘕'=>'N','𝘖'=>'O','𝘗'=>'P','𝘘'=>'Q','𝘙'=>'R','𝘚'=>'S','𝘛'=>'T','𝘜'=>'U','𝘝'=>'V','𝘞'=>'W','𝘟'=>'X','𝘠'=>'Y','𝘡'=>'Z','𝘢'=>'a','𝘣'=>'b','𝘤'=>'c','𝘥'=>'d','𝘦'=>'e','𝘧'=>'f','𝘨'=>'g','𝘩'=>'h','𝘪'=>'i','𝘫'=>'j','𝘬'=>'k','𝘭'=>'l','𝘮'=>'m','𝘯'=>'n','𝘰'=>'o','𝘱'=>'p','𝘲'=>'q','𝘳'=>'r','𝘴'=>'s','𝘵'=>'t','𝘶'=>'u','𝘷'=>'v','𝘸'=>'w','𝘹'=>'x','𝘺'=>'y','𝘻'=>'z','𝘼'=>'A','𝘽'=>'B','𝘾'=>'C','𝘿'=>'D','𝙀'=>'E','𝙁'=>'F','𝙂'=>'G','𝙃'=>'H','𝙄'=>'I','𝙅'=>'J','𝙆'=>'K','𝙇'=>'L','𝙈'=>'M','𝙉'=>'N','𝙊'=>'O','𝙋'=>'P','𝙌'=>'Q','𝙍'=>'R','𝙎'=>'S','𝙏'=>'T','𝙐'=>'U','𝙑'=>'V','𝙒'=>'W','𝙓'=>'X','𝙔'=>'Y','𝙕'=>'Z','𝙖'=>'a','𝙗'=>'b','𝙘'=>'c','𝙙'=>'d','𝙚'=>'e','𝙛'=>'f','𝙜'=>'g','𝙝'=>'h','𝙞'=>'i','𝙟'=>'j','𝙠'=>'k','𝙡'=>'l','𝙢'=>'m','𝙣'=>'n','𝙤'=>'o','𝙥'=>'p','𝙦'=>'q','𝙧'=>'r','𝙨'=>'s','𝙩'=>'t','𝙪'=>'u','𝙫'=>'v','𝙬'=>'w','𝙭'=>'x','𝙮'=>'y','𝙯'=>'z','𝙰'=>'A','𝙱'=>'B','𝙲'=>'C','𝙳'=>'D','𝙴'=>'E','𝙵'=>'F','𝙶'=>'G','𝙷'=>'H','𝙸'=>'I','𝙹'=>'J','𝙺'=>'K','𝙻'=>'L','𝙼'=>'M','𝙽'=>'N','𝙾'=>'O','𝙿'=>'P','𝚀'=>'Q','𝚁'=>'R','𝚂'=>'S','𝚃'=>'T','𝚄'=>'U','𝚅'=>'V','𝚆'=>'W','𝚇'=>'X','𝚈'=>'Y','𝚉'=>'Z','𝚊'=>'a','𝚋'=>'b','𝚌'=>'c','𝚍'=>'d','𝚎'=>'e','𝚏'=>'f','𝚐'=>'g','𝚑'=>'h','𝚒'=>'i','𝚓'=>'j','𝚔'=>'k','𝚕'=>'l','𝚖'=>'m','𝚗'=>'n','𝚘'=>'o','𝚙'=>'p','𝚚'=>'q','𝚛'=>'r','𝚜'=>'s','𝚝'=>'t','𝚞'=>'u','𝚟'=>'v','𝚠'=>'w','𝚡'=>'x','𝚢'=>'y','𝚣'=>'z','𝚤'=>'ı','𝚥'=>'ȷ','𝚨'=>'Α','𝚩'=>'Β','𝚪'=>'Γ','𝚫'=>'Δ','𝚬'=>'Ε','𝚭'=>'Ζ','𝚮'=>'Η','𝚯'=>'Θ','𝚰'=>'Ι','𝚱'=>'Κ','𝚲'=>'Λ','𝚳'=>'Μ','𝚴'=>'Ν','𝚵'=>'Ξ','𝚶'=>'Ο','𝚷'=>'Π','𝚸'=>'Ρ','𝚹'=>'Θ','𝚺'=>'Σ','𝚻'=>'Τ','𝚼'=>'Υ','𝚽'=>'Φ','𝚾'=>'Χ','𝚿'=>'Ψ','𝛀'=>'Ω','𝛁'=>'∇','𝛂'=>'α','𝛃'=>'β','𝛄'=>'γ','𝛅'=>'δ','𝛆'=>'ε','𝛇'=>'ζ','𝛈'=>'η','𝛉'=>'θ','𝛊'=>'ι','𝛋'=>'κ','𝛌'=>'λ','𝛍'=>'μ','𝛎'=>'ν','𝛏'=>'ξ','𝛐'=>'ο','𝛑'=>'π','𝛒'=>'ρ','𝛓'=>'ς','𝛔'=>'σ','𝛕'=>'τ','𝛖'=>'υ','𝛗'=>'φ','𝛘'=>'χ','𝛙'=>'ψ','𝛚'=>'ω','𝛛'=>'∂','𝛜'=>'ε','𝛝'=>'θ','𝛞'=>'κ','𝛟'=>'φ','𝛠'=>'ρ','𝛡'=>'π','𝛢'=>'Α','𝛣'=>'Β','𝛤'=>'Γ','𝛥'=>'Δ','𝛦'=>'Ε','𝛧'=>'Ζ','𝛨'=>'Η','𝛩'=>'Θ','𝛪'=>'Ι','𝛫'=>'Κ','𝛬'=>'Λ','𝛭'=>'Μ','𝛮'=>'Ν','𝛯'=>'Ξ','𝛰'=>'Ο','𝛱'=>'Π','𝛲'=>'Ρ','𝛳'=>'Θ','𝛴'=>'Σ','𝛵'=>'Τ','𝛶'=>'Υ','𝛷'=>'Φ','𝛸'=>'Χ','𝛹'=>'Ψ','𝛺'=>'Ω','𝛻'=>'∇','𝛼'=>'α','𝛽'=>'β','𝛾'=>'γ','𝛿'=>'δ','𝜀'=>'ε','𝜁'=>'ζ','𝜂'=>'η','𝜃'=>'θ','𝜄'=>'ι','𝜅'=>'κ','𝜆'=>'λ','𝜇'=>'μ','𝜈'=>'ν','𝜉'=>'ξ','𝜊'=>'ο','𝜋'=>'π','𝜌'=>'ρ','𝜍'=>'ς','𝜎'=>'σ','𝜏'=>'τ','𝜐'=>'υ','𝜑'=>'φ','𝜒'=>'χ','𝜓'=>'ψ','𝜔'=>'ω','𝜕'=>'∂','𝜖'=>'ε','𝜗'=>'θ','𝜘'=>'κ','𝜙'=>'φ','𝜚'=>'ρ','𝜛'=>'π','𝜜'=>'Α','𝜝'=>'Β','𝜞'=>'Γ','𝜟'=>'Δ','𝜠'=>'Ε','𝜡'=>'Ζ','𝜢'=>'Η','𝜣'=>'Θ','𝜤'=>'Ι','𝜥'=>'Κ','𝜦'=>'Λ','𝜧'=>'Μ','𝜨'=>'Ν','𝜩'=>'Ξ','𝜪'=>'Ο','𝜫'=>'Π','𝜬'=>'Ρ','𝜭'=>'Θ','𝜮'=>'Σ','𝜯'=>'Τ','𝜰'=>'Υ','𝜱'=>'Φ','𝜲'=>'Χ','𝜳'=>'Ψ','𝜴'=>'Ω','𝜵'=>'∇','𝜶'=>'α','𝜷'=>'β','𝜸'=>'γ','𝜹'=>'δ','𝜺'=>'ε','𝜻'=>'ζ','𝜼'=>'η','𝜽'=>'θ','𝜾'=>'ι','𝜿'=>'κ','𝝀'=>'λ','𝝁'=>'μ','𝝂'=>'ν','𝝃'=>'ξ','𝝄'=>'ο','𝝅'=>'π','𝝆'=>'ρ','𝝇'=>'ς','𝝈'=>'σ','𝝉'=>'τ','𝝊'=>'υ','𝝋'=>'φ','𝝌'=>'χ','𝝍'=>'ψ','𝝎'=>'ω','𝝏'=>'∂','𝝐'=>'ε','𝝑'=>'θ','𝝒'=>'κ','𝝓'=>'φ','𝝔'=>'ρ','𝝕'=>'π','𝝖'=>'Α','𝝗'=>'Β','𝝘'=>'Γ','𝝙'=>'Δ','𝝚'=>'Ε','𝝛'=>'Ζ','𝝜'=>'Η','𝝝'=>'Θ','𝝞'=>'Ι','𝝟'=>'Κ','𝝠'=>'Λ','𝝡'=>'Μ','𝝢'=>'Ν','𝝣'=>'Ξ','𝝤'=>'Ο','𝝥'=>'Π','𝝦'=>'Ρ','𝝧'=>'Θ','𝝨'=>'Σ','𝝩'=>'Τ','𝝪'=>'Υ','𝝫'=>'Φ','𝝬'=>'Χ','𝝭'=>'Ψ','𝝮'=>'Ω','𝝯'=>'∇','𝝰'=>'α','𝝱'=>'β','𝝲'=>'γ','𝝳'=>'δ','𝝴'=>'ε','𝝵'=>'ζ','𝝶'=>'η','𝝷'=>'θ','𝝸'=>'ι','𝝹'=>'κ','𝝺'=>'λ','𝝻'=>'μ','𝝼'=>'ν','𝝽'=>'ξ','𝝾'=>'ο','𝝿'=>'π','𝞀'=>'ρ','𝞁'=>'ς','𝞂'=>'σ','𝞃'=>'τ','𝞄'=>'υ','𝞅'=>'φ','𝞆'=>'χ','𝞇'=>'ψ','𝞈'=>'ω','𝞉'=>'∂','𝞊'=>'ε','𝞋'=>'θ','𝞌'=>'κ','𝞍'=>'φ','𝞎'=>'ρ','𝞏'=>'π','𝞐'=>'Α','𝞑'=>'Β','𝞒'=>'Γ','𝞓'=>'Δ','𝞔'=>'Ε','𝞕'=>'Ζ','𝞖'=>'Η','𝞗'=>'Θ','𝞘'=>'Ι','𝞙'=>'Κ','𝞚'=>'Λ','𝞛'=>'Μ','𝞜'=>'Ν','𝞝'=>'Ξ','𝞞'=>'Ο','𝞟'=>'Π','𝞠'=>'Ρ','𝞡'=>'Θ','𝞢'=>'Σ','𝞣'=>'Τ','𝞤'=>'Υ','𝞥'=>'Φ','𝞦'=>'Χ','𝞧'=>'Ψ','𝞨'=>'Ω','𝞩'=>'∇','𝞪'=>'α','𝞫'=>'β','𝞬'=>'γ','𝞭'=>'δ','𝞮'=>'ε','𝞯'=>'ζ','𝞰'=>'η','𝞱'=>'θ','𝞲'=>'ι','𝞳'=>'κ','𝞴'=>'λ','𝞵'=>'μ','𝞶'=>'ν','𝞷'=>'ξ','𝞸'=>'ο','𝞹'=>'π','𝞺'=>'ρ','𝞻'=>'ς','𝞼'=>'σ','𝞽'=>'τ','𝞾'=>'υ','𝞿'=>'φ','𝟀'=>'χ','𝟁'=>'ψ','𝟂'=>'ω','𝟃'=>'∂','𝟄'=>'ε','𝟅'=>'θ','𝟆'=>'κ','𝟇'=>'φ','𝟈'=>'ρ','𝟉'=>'π','𝟊'=>'Ϝ','𝟋'=>'ϝ','𝟎'=>'0','𝟏'=>'1','𝟐'=>'2','𝟑'=>'3','𝟒'=>'4','𝟓'=>'5','𝟔'=>'6','𝟕'=>'7','𝟖'=>'8','𝟗'=>'9','𝟘'=>'0','𝟙'=>'1','𝟚'=>'2','𝟛'=>'3','𝟜'=>'4','𝟝'=>'5','𝟞'=>'6','𝟟'=>'7','𝟠'=>'8','𝟡'=>'9','𝟢'=>'0','𝟣'=>'1','𝟤'=>'2','𝟥'=>'3','𝟦'=>'4','𝟧'=>'5','𝟨'=>'6','𝟩'=>'7','𝟪'=>'8','𝟫'=>'9','𝟬'=>'0','𝟭'=>'1','𝟮'=>'2','𝟯'=>'3','𝟰'=>'4','𝟱'=>'5','𝟲'=>'6','𝟳'=>'7','𝟴'=>'8','𝟵'=>'9','𝟶'=>'0','𝟷'=>'1','𝟸'=>'2','𝟹'=>'3','𝟺'=>'4','𝟻'=>'5','𝟼'=>'6','𝟽'=>'7','𝟾'=>'8','𝟿'=>'9','丽'=>'丽','丸'=>'丸','乁'=>'乁','𠄢'=>'𠄢','你'=>'你','侮'=>'侮','侻'=>'侻','倂'=>'倂','偺'=>'偺','備'=>'備','僧'=>'僧','像'=>'像','㒞'=>'㒞','𠘺'=>'𠘺','免'=>'免','兔'=>'兔','兤'=>'兤','具'=>'具','𠔜'=>'𠔜','㒹'=>'㒹','內'=>'內','再'=>'再','𠕋'=>'𠕋','冗'=>'冗','冤'=>'冤','仌'=>'仌','冬'=>'冬','况'=>'况','𩇟'=>'𩇟','凵'=>'凵','刃'=>'刃','㓟'=>'㓟','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','㔕'=>'㔕','勇'=>'勇','勉'=>'勉','勤'=>'勤','勺'=>'勺','包'=>'包','匆'=>'匆','北'=>'北','卉'=>'卉','卑'=>'卑','博'=>'博','即'=>'即','卽'=>'卽','卿'=>'卿','卿'=>'卿','卿'=>'卿','𠨬'=>'𠨬','灰'=>'灰','及'=>'及','叟'=>'叟','𠭣'=>'𠭣','叫'=>'叫','叱'=>'叱','吆'=>'吆','咞'=>'咞','吸'=>'吸','呈'=>'呈','周'=>'周','咢'=>'咢','哶'=>'哶','唐'=>'唐','啓'=>'啓','啣'=>'啣','善'=>'善','善'=>'善','喙'=>'喙','喫'=>'喫','喳'=>'喳','嗂'=>'嗂','圖'=>'圖','嘆'=>'嘆','圗'=>'圗','噑'=>'噑','噴'=>'噴','切'=>'切','壮'=>'壮','城'=>'城','埴'=>'埴','堍'=>'堍','型'=>'型','堲'=>'堲','報'=>'報','墬'=>'墬','𡓤'=>'𡓤','売'=>'売','壷'=>'壷','夆'=>'夆','多'=>'多','夢'=>'夢','奢'=>'奢','𡚨'=>'𡚨','𡛪'=>'𡛪','姬'=>'姬','娛'=>'娛','娧'=>'娧','姘'=>'姘','婦'=>'婦','㛮'=>'㛮','㛼'=>'㛼','嬈'=>'嬈','嬾'=>'嬾','嬾'=>'嬾','𡧈'=>'𡧈','寃'=>'寃','寘'=>'寘','寧'=>'寧','寳'=>'寳','𡬘'=>'𡬘','寿'=>'寿','将'=>'将','当'=>'当','尢'=>'尢','㞁'=>'㞁','屠'=>'屠','屮'=>'屮','峀'=>'峀','岍'=>'岍','𡷤'=>'𡷤','嵃'=>'嵃','𡷦'=>'𡷦','嵮'=>'嵮','嵫'=>'嵫','嵼'=>'嵼','巡'=>'巡','巢'=>'巢','㠯'=>'㠯','巽'=>'巽','帨'=>'帨','帽'=>'帽','幩'=>'幩','㡢'=>'㡢','𢆃'=>'𢆃','㡼'=>'㡼','庰'=>'庰','庳'=>'庳','庶'=>'庶','廊'=>'廊','𪎒'=>'𪎒','廾'=>'廾','𢌱'=>'𢌱','𢌱'=>'𢌱','舁'=>'舁','弢'=>'弢','弢'=>'弢','㣇'=>'㣇','𣊸'=>'𣊸','𦇚'=>'𦇚','形'=>'形','彫'=>'彫','㣣'=>'㣣','徚'=>'徚','忍'=>'忍','志'=>'志','忹'=>'忹','悁'=>'悁','㤺'=>'㤺','㤜'=>'㤜','悔'=>'悔','𢛔'=>'𢛔','惇'=>'惇','慈'=>'慈','慌'=>'慌','慎'=>'慎','慌'=>'慌','慺'=>'慺','憎'=>'憎','憲'=>'憲','憤'=>'憤','憯'=>'憯','懞'=>'懞','懲'=>'懲','懶'=>'懶','成'=>'成','戛'=>'戛','扝'=>'扝','抱'=>'抱','拔'=>'拔','捐'=>'捐','𢬌'=>'𢬌','挽'=>'挽','拼'=>'拼','捨'=>'捨','掃'=>'掃','揤'=>'揤','𢯱'=>'𢯱','搢'=>'搢','揅'=>'揅','掩'=>'掩','㨮'=>'㨮','摩'=>'摩','摾'=>'摾','撝'=>'撝','摷'=>'摷','㩬'=>'㩬','敏'=>'敏','敬'=>'敬','𣀊'=>'𣀊','旣'=>'旣','書'=>'書','晉'=>'晉','㬙'=>'㬙','暑'=>'暑','㬈'=>'㬈','㫤'=>'㫤','冒'=>'冒','冕'=>'冕','最'=>'最','暜'=>'暜','肭'=>'肭','䏙'=>'䏙','朗'=>'朗','望'=>'望','朡'=>'朡','杞'=>'杞','杓'=>'杓','𣏃'=>'𣏃','㭉'=>'㭉','柺'=>'柺','枅'=>'枅','桒'=>'桒','梅'=>'梅','𣑭'=>'𣑭','梎'=>'梎','栟'=>'栟','椔'=>'椔','㮝'=>'㮝','楂'=>'楂','榣'=>'榣','槪'=>'槪','檨'=>'檨','𣚣'=>'𣚣','櫛'=>'櫛','㰘'=>'㰘','次'=>'次','𣢧'=>'𣢧','歔'=>'歔','㱎'=>'㱎','歲'=>'歲','殟'=>'殟','殺'=>'殺','殻'=>'殻','𣪍'=>'𣪍','𡴋'=>'𡴋','𣫺'=>'𣫺','汎'=>'汎','𣲼'=>'𣲼','沿'=>'沿','泍'=>'泍','汧'=>'汧','洖'=>'洖','派'=>'派','海'=>'海','流'=>'流','浩'=>'浩','浸'=>'浸','涅'=>'涅','𣴞'=>'𣴞','洴'=>'洴','港'=>'港','湮'=>'湮','㴳'=>'㴳','滋'=>'滋','滇'=>'滇','𣻑'=>'𣻑','淹'=>'淹','潮'=>'潮','𣽞'=>'𣽞','𣾎'=>'𣾎','濆'=>'濆','瀹'=>'瀹','瀞'=>'瀞','瀛'=>'瀛','㶖'=>'㶖','灊'=>'灊','災'=>'災','灷'=>'灷','炭'=>'炭','𠔥'=>'𠔥','煅'=>'煅','𤉣'=>'𤉣','熜'=>'熜','𤎫'=>'𤎫','爨'=>'爨','爵'=>'爵','牐'=>'牐','𤘈'=>'𤘈','犀'=>'犀','犕'=>'犕','𤜵'=>'𤜵','𤠔'=>'𤠔','獺'=>'獺','王'=>'王','㺬'=>'㺬','玥'=>'玥','㺸'=>'㺸','㺸'=>'㺸','瑇'=>'瑇','瑜'=>'瑜','瑱'=>'瑱','璅'=>'璅','瓊'=>'瓊','㼛'=>'㼛','甤'=>'甤','𤰶'=>'𤰶','甾'=>'甾','𤲒'=>'𤲒','異'=>'異','𢆟'=>'𢆟','瘐'=>'瘐','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'𥁄','㿼'=>'㿼','䀈'=>'䀈','直'=>'直','𥃳'=>'𥃳','𥃲'=>'𥃲','𥄙'=>'𥄙','𥄳'=>'𥄳','眞'=>'眞','真'=>'真','真'=>'真','睊'=>'睊','䀹'=>'䀹','瞋'=>'瞋','䁆'=>'䁆','䂖'=>'䂖','𥐝'=>'𥐝','硎'=>'硎','碌'=>'碌','磌'=>'磌','䃣'=>'䃣','𥘦'=>'𥘦','祖'=>'祖','𥚚'=>'𥚚','𥛅'=>'𥛅','福'=>'福','秫'=>'秫','䄯'=>'䄯','穀'=>'穀','穊'=>'穊','穏'=>'穏','𥥼'=>'𥥼','𥪧'=>'𥪧','𥪧'=>'𥪧','竮'=>'竮','䈂'=>'䈂','𥮫'=>'𥮫','篆'=>'篆','築'=>'築','䈧'=>'䈧','𥲀'=>'𥲀','糒'=>'糒','䊠'=>'䊠','糨'=>'糨','糣'=>'糣','紀'=>'紀','𥾆'=>'𥾆','絣'=>'絣','䌁'=>'䌁','緇'=>'緇','縂'=>'縂','繅'=>'繅','䌴'=>'䌴','𦈨'=>'𦈨','𦉇'=>'𦉇','䍙'=>'䍙','𦋙'=>'𦋙','罺'=>'罺','𦌾'=>'𦌾','羕'=>'羕','翺'=>'翺','者'=>'者','𦓚'=>'𦓚','𦔣'=>'𦔣','聠'=>'聠','𦖨'=>'𦖨','聰'=>'聰','𣍟'=>'𣍟','䏕'=>'䏕','育'=>'育','脃'=>'脃','䐋'=>'䐋','脾'=>'脾','媵'=>'媵','𦞧'=>'𦞧','𦞵'=>'𦞵','𣎓'=>'𣎓','𣎜'=>'𣎜','舁'=>'舁','舄'=>'舄','辞'=>'辞','䑫'=>'䑫','芑'=>'芑','芋'=>'芋','芝'=>'芝','劳'=>'劳','花'=>'花','芳'=>'芳','芽'=>'芽','苦'=>'苦','𦬼'=>'𦬼','若'=>'若','茝'=>'茝','荣'=>'荣','莭'=>'莭','茣'=>'茣','莽'=>'莽','菧'=>'菧','著'=>'著','荓'=>'荓','菊'=>'菊','菌'=>'菌','菜'=>'菜','𦰶'=>'𦰶','𦵫'=>'𦵫','𦳕'=>'𦳕','䔫'=>'䔫','蓱'=>'蓱','蓳'=>'蓳','蔖'=>'蔖','𧏊'=>'𧏊','蕤'=>'蕤','𦼬'=>'𦼬','䕝'=>'䕝','䕡'=>'䕡','𦾱'=>'𦾱','𧃒'=>'𧃒','䕫'=>'䕫','虐'=>'虐','虜'=>'虜','虧'=>'虧','虩'=>'虩','蚩'=>'蚩','蚈'=>'蚈','蜎'=>'蜎','蛢'=>'蛢','蝹'=>'蝹','蜨'=>'蜨','蝫'=>'蝫','螆'=>'螆','䗗'=>'䗗','蟡'=>'蟡','蠁'=>'蠁','䗹'=>'䗹','衠'=>'衠','衣'=>'衣','𧙧'=>'𧙧','裗'=>'裗','裞'=>'裞','䘵'=>'䘵','裺'=>'裺','㒻'=>'㒻','𧢮'=>'𧢮','𧥦'=>'𧥦','䚾'=>'䚾','䛇'=>'䛇','誠'=>'誠','諭'=>'諭','變'=>'變','豕'=>'豕','𧲨'=>'𧲨','貫'=>'貫','賁'=>'賁','贛'=>'贛','起'=>'起','𧼯'=>'𧼯','𠠄'=>'𠠄','跋'=>'跋','趼'=>'趼','跰'=>'跰','𠣞'=>'𠣞','軔'=>'軔','輸'=>'輸','𨗒'=>'𨗒','𨗭'=>'𨗭','邔'=>'邔','郱'=>'郱','鄑'=>'鄑','𨜮'=>'𨜮','鄛'=>'鄛','鈸'=>'鈸','鋗'=>'鋗','鋘'=>'鋘','鉼'=>'鉼','鏹'=>'鏹','鐕'=>'鐕','𨯺'=>'𨯺','開'=>'開','䦕'=>'䦕','閷'=>'閷','𨵷'=>'𨵷','䧦'=>'䧦','雃'=>'雃','嶲'=>'嶲','霣'=>'霣','𩅅'=>'𩅅','𩈚'=>'𩈚','䩮'=>'䩮','䩶'=>'䩶','韠'=>'韠','𩐊'=>'𩐊','䪲'=>'䪲','𩒖'=>'𩒖','頋'=>'頋','頋'=>'頋','頩'=>'頩','𩖶'=>'𩖶','飢'=>'飢','䬳'=>'䬳','餩'=>'餩','馧'=>'馧','駂'=>'駂','駾'=>'駾','䯎'=>'䯎','𩬰'=>'𩬰','鬒'=>'鬒','鱀'=>'鱀','鳽'=>'鳽','䳎'=>'䳎','䳭'=>'䳭','鵧'=>'鵧','𪃎'=>'𪃎','䳸'=>'䳸','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','麻'=>'麻','䵖'=>'䵖','黹'=>'黹','黾'=>'黾','鼅'=>'鼅','鼏'=>'鼏','鼖'=>'鼖','鼻'=>'鼻','𪘀'=>'𪘀'); diff --git a/phpBB/includes/utf/data/utf_nfc_qc.php b/phpBB/includes/utf/data/utf_nfc_qc.php index 03031f8b6d..ff56357ea6 100644 --- a/phpBB/includes/utf/data/utf_nfc_qc.php +++ b/phpBB/includes/utf/data/utf_nfc_qc.php @@ -1,2 +1,2 @@ <?php -$GLOBALS['utf_nfc_qc']=array('̀'=>1,'́'=>1,'̓'=>1,'̈́'=>1,'ʹ'=>1,';'=>1,'·'=>1,'क़'=>1,'ख़'=>1,'ग़'=>1,'ज़'=>1,'ड़'=>1,'ढ़'=>1,'फ़'=>1,'य़'=>1,'ড়'=>1,'ঢ়'=>1,'য়'=>1,'ਲ਼'=>1,'ਸ਼'=>1,'ਖ਼'=>1,'ਗ਼'=>1,'ਜ਼'=>1,'ਫ਼'=>1,'ଡ଼'=>1,'ଢ଼'=>1,'གྷ'=>1,'ཌྷ'=>1,'དྷ'=>1,'བྷ'=>1,'ཛྷ'=>1,'ཀྵ'=>1,'ཱི'=>1,'ཱུ'=>1,'ྲྀ'=>1,'ླྀ'=>1,'ཱྀ'=>1,'ྒྷ'=>1,'ྜྷ'=>1,'ྡྷ'=>1,'ྦྷ'=>1,'ྫྷ'=>1,'ྐྵ'=>1,'ά'=>1,'έ'=>1,'ή'=>1,'ί'=>1,'ό'=>1,'ύ'=>1,'ώ'=>1,'Ά'=>1,'ι'=>1,'Έ'=>1,'Ή'=>1,'ΐ'=>1,'Ί'=>1,'ΰ'=>1,'Ύ'=>1,'΅'=>1,'`'=>1,'Ό'=>1,'Ώ'=>1,'´'=>1,' '=>1,' '=>1,'Ω'=>1,'K'=>1,'Å'=>1,'〈'=>1,'〉'=>1,'⫝̸'=>1,'豈'=>1,'更'=>1,'車'=>1,'賈'=>1,'滑'=>1,'串'=>1,'句'=>1,'龜'=>1,'龜'=>1,'契'=>1,'金'=>1,'喇'=>1,'奈'=>1,'懶'=>1,'癩'=>1,'羅'=>1,'蘿'=>1,'螺'=>1,'裸'=>1,'邏'=>1,'樂'=>1,'洛'=>1,'烙'=>1,'珞'=>1,'落'=>1,'酪'=>1,'駱'=>1,'亂'=>1,'卵'=>1,'欄'=>1,'爛'=>1,'蘭'=>1,'鸞'=>1,'嵐'=>1,'濫'=>1,'藍'=>1,'襤'=>1,'拉'=>1,'臘'=>1,'蠟'=>1,'廊'=>1,'朗'=>1,'浪'=>1,'狼'=>1,'郎'=>1,'來'=>1,'冷'=>1,'勞'=>1,'擄'=>1,'櫓'=>1,'爐'=>1,'盧'=>1,'老'=>1,'蘆'=>1,'虜'=>1,'路'=>1,'露'=>1,'魯'=>1,'鷺'=>1,'碌'=>1,'祿'=>1,'綠'=>1,'菉'=>1,'錄'=>1,'鹿'=>1,'論'=>1,'壟'=>1,'弄'=>1,'籠'=>1,'聾'=>1,'牢'=>1,'磊'=>1,'賂'=>1,'雷'=>1,'壘'=>1,'屢'=>1,'樓'=>1,'淚'=>1,'漏'=>1,'累'=>1,'縷'=>1,'陋'=>1,'勒'=>1,'肋'=>1,'凜'=>1,'凌'=>1,'稜'=>1,'綾'=>1,'菱'=>1,'陵'=>1,'讀'=>1,'拏'=>1,'樂'=>1,'諾'=>1,'丹'=>1,'寧'=>1,'怒'=>1,'率'=>1,'異'=>1,'北'=>1,'磻'=>1,'便'=>1,'復'=>1,'不'=>1,'泌'=>1,'數'=>1,'索'=>1,'參'=>1,'塞'=>1,'省'=>1,'葉'=>1,'說'=>1,'殺'=>1,'辰'=>1,'沈'=>1,'拾'=>1,'若'=>1,'掠'=>1,'略'=>1,'亮'=>1,'兩'=>1,'凉'=>1,'梁'=>1,'糧'=>1,'良'=>1,'諒'=>1,'量'=>1,'勵'=>1,'呂'=>1,'女'=>1,'廬'=>1,'旅'=>1,'濾'=>1,'礪'=>1,'閭'=>1,'驪'=>1,'麗'=>1,'黎'=>1,'力'=>1,'曆'=>1,'歷'=>1,'轢'=>1,'年'=>1,'憐'=>1,'戀'=>1,'撚'=>1,'漣'=>1,'煉'=>1,'璉'=>1,'秊'=>1,'練'=>1,'聯'=>1,'輦'=>1,'蓮'=>1,'連'=>1,'鍊'=>1,'列'=>1,'劣'=>1,'咽'=>1,'烈'=>1,'裂'=>1,'說'=>1,'廉'=>1,'念'=>1,'捻'=>1,'殮'=>1,'簾'=>1,'獵'=>1,'令'=>1,'囹'=>1,'寧'=>1,'嶺'=>1,'怜'=>1,'玲'=>1,'瑩'=>1,'羚'=>1,'聆'=>1,'鈴'=>1,'零'=>1,'靈'=>1,'領'=>1,'例'=>1,'禮'=>1,'醴'=>1,'隸'=>1,'惡'=>1,'了'=>1,'僚'=>1,'寮'=>1,'尿'=>1,'料'=>1,'樂'=>1,'燎'=>1,'療'=>1,'蓼'=>1,'遼'=>1,'龍'=>1,'暈'=>1,'阮'=>1,'劉'=>1,'杻'=>1,'柳'=>1,'流'=>1,'溜'=>1,'琉'=>1,'留'=>1,'硫'=>1,'紐'=>1,'類'=>1,'六'=>1,'戮'=>1,'陸'=>1,'倫'=>1,'崙'=>1,'淪'=>1,'輪'=>1,'律'=>1,'慄'=>1,'栗'=>1,'率'=>1,'隆'=>1,'利'=>1,'吏'=>1,'履'=>1,'易'=>1,'李'=>1,'梨'=>1,'泥'=>1,'理'=>1,'痢'=>1,'罹'=>1,'裏'=>1,'裡'=>1,'里'=>1,'離'=>1,'匿'=>1,'溺'=>1,'吝'=>1,'燐'=>1,'璘'=>1,'藺'=>1,'隣'=>1,'鱗'=>1,'麟'=>1,'林'=>1,'淋'=>1,'臨'=>1,'立'=>1,'笠'=>1,'粒'=>1,'狀'=>1,'炙'=>1,'識'=>1,'什'=>1,'茶'=>1,'刺'=>1,'切'=>1,'度'=>1,'拓'=>1,'糖'=>1,'宅'=>1,'洞'=>1,'暴'=>1,'輻'=>1,'行'=>1,'降'=>1,'見'=>1,'廓'=>1,'兀'=>1,'嗀'=>1,'塚'=>1,'晴'=>1,'凞'=>1,'猪'=>1,'益'=>1,'礼'=>1,'神'=>1,'祥'=>1,'福'=>1,'靖'=>1,'精'=>1,'羽'=>1,'蘒'=>1,'諸'=>1,'逸'=>1,'都'=>1,'飯'=>1,'飼'=>1,'館'=>1,'鶴'=>1,'侮'=>1,'僧'=>1,'免'=>1,'勉'=>1,'勤'=>1,'卑'=>1,'喝'=>1,'嘆'=>1,'器'=>1,'塀'=>1,'墨'=>1,'層'=>1,'屮'=>1,'悔'=>1,'慨'=>1,'憎'=>1,'懲'=>1,'敏'=>1,'既'=>1,'暑'=>1,'梅'=>1,'海'=>1,'渚'=>1,'漢'=>1,'煮'=>1,'爫'=>1,'琢'=>1,'碑'=>1,'社'=>1,'祉'=>1,'祈'=>1,'祐'=>1,'祖'=>1,'祝'=>1,'禍'=>1,'禎'=>1,'穀'=>1,'突'=>1,'節'=>1,'練'=>1,'縉'=>1,'繁'=>1,'署'=>1,'者'=>1,'臭'=>1,'艹'=>1,'艹'=>1,'著'=>1,'褐'=>1,'視'=>1,'謁'=>1,'謹'=>1,'賓'=>1,'贈'=>1,'辶'=>1,'逸'=>1,'難'=>1,'響'=>1,'頻'=>1,'並'=>1,'况'=>1,'全'=>1,'侀'=>1,'充'=>1,'冀'=>1,'勇'=>1,'勺'=>1,'喝'=>1,'啕'=>1,'喙'=>1,'嗢'=>1,'塚'=>1,'墳'=>1,'奄'=>1,'奔'=>1,'婢'=>1,'嬨'=>1,'廒'=>1,'廙'=>1,'彩'=>1,'徭'=>1,'惘'=>1,'慎'=>1,'愈'=>1,'憎'=>1,'慠'=>1,'懲'=>1,'戴'=>1,'揄'=>1,'搜'=>1,'摒'=>1,'敖'=>1,'晴'=>1,'朗'=>1,'望'=>1,'杖'=>1,'歹'=>1,'殺'=>1,'流'=>1,'滛'=>1,'滋'=>1,'漢'=>1,'瀞'=>1,'煮'=>1,'瞧'=>1,'爵'=>1,'犯'=>1,'猪'=>1,'瑱'=>1,'甆'=>1,'画'=>1,'瘝'=>1,'瘟'=>1,'益'=>1,'盛'=>1,'直'=>1,'睊'=>1,'着'=>1,'磌'=>1,'窱'=>1,'節'=>1,'类'=>1,'絛'=>1,'練'=>1,'缾'=>1,'者'=>1,'荒'=>1,'華'=>1,'蝹'=>1,'襁'=>1,'覆'=>1,'視'=>1,'調'=>1,'諸'=>1,'請'=>1,'謁'=>1,'諾'=>1,'諭'=>1,'謹'=>1,'變'=>1,'贈'=>1,'輸'=>1,'遲'=>1,'醙'=>1,'鉶'=>1,'陼'=>1,'難'=>1,'靖'=>1,'韛'=>1,'響'=>1,'頋'=>1,'頻'=>1,'鬒'=>1,'龜'=>1,'𢡊'=>1,'𢡄'=>1,'𣏕'=>1,'㮝'=>1,'䀘'=>1,'䀹'=>1,'𥉉'=>1,'𥳐'=>1,'𧻓'=>1,'齃'=>1,'龎'=>1,'יִ'=>1,'ײַ'=>1,'שׁ'=>1,'שׂ'=>1,'שּׁ'=>1,'שּׂ'=>1,'אַ'=>1,'אָ'=>1,'אּ'=>1,'בּ'=>1,'גּ'=>1,'דּ'=>1,'הּ'=>1,'וּ'=>1,'זּ'=>1,'טּ'=>1,'יּ'=>1,'ךּ'=>1,'כּ'=>1,'לּ'=>1,'מּ'=>1,'נּ'=>1,'סּ'=>1,'ףּ'=>1,'פּ'=>1,'צּ'=>1,'קּ'=>1,'רּ'=>1,'שּ'=>1,'תּ'=>1,'וֹ'=>1,'בֿ'=>1,'כֿ'=>1,'פֿ'=>1,'𝅗𝅥'=>1,'𝅘𝅥'=>1,'𝅘𝅥𝅮'=>1,'𝅘𝅥𝅯'=>1,'𝅘𝅥𝅰'=>1,'𝅘𝅥𝅱'=>1,'𝅘𝅥𝅲'=>1,'𝆹𝅥'=>1,'𝆺𝅥'=>1,'𝆹𝅥𝅮'=>1,'𝆺𝅥𝅮'=>1,'𝆹𝅥𝅯'=>1,'𝆺𝅥𝅯'=>1,'丽'=>1,'丸'=>1,'乁'=>1,'𠄢'=>1,'你'=>1,'侮'=>1,'侻'=>1,'倂'=>1,'偺'=>1,'備'=>1,'僧'=>1,'像'=>1,'㒞'=>1,'𠘺'=>1,'免'=>1,'兔'=>1,'兤'=>1,'具'=>1,'𠔜'=>1,'㒹'=>1,'內'=>1,'再'=>1,'𠕋'=>1,'冗'=>1,'冤'=>1,'仌'=>1,'冬'=>1,'况'=>1,'𩇟'=>1,'凵'=>1,'刃'=>1,'㓟'=>1,'刻'=>1,'剆'=>1,'割'=>1,'剷'=>1,'㔕'=>1,'勇'=>1,'勉'=>1,'勤'=>1,'勺'=>1,'包'=>1,'匆'=>1,'北'=>1,'卉'=>1,'卑'=>1,'博'=>1,'即'=>1,'卽'=>1,'卿'=>1,'卿'=>1,'卿'=>1,'𠨬'=>1,'灰'=>1,'及'=>1,'叟'=>1,'𠭣'=>1,'叫'=>1,'叱'=>1,'吆'=>1,'咞'=>1,'吸'=>1,'呈'=>1,'周'=>1,'咢'=>1,'哶'=>1,'唐'=>1,'啓'=>1,'啣'=>1,'善'=>1,'善'=>1,'喙'=>1,'喫'=>1,'喳'=>1,'嗂'=>1,'圖'=>1,'嘆'=>1,'圗'=>1,'噑'=>1,'噴'=>1,'切'=>1,'壮'=>1,'城'=>1,'埴'=>1,'堍'=>1,'型'=>1,'堲'=>1,'報'=>1,'墬'=>1,'𡓤'=>1,'売'=>1,'壷'=>1,'夆'=>1,'多'=>1,'夢'=>1,'奢'=>1,'𡚨'=>1,'𡛪'=>1,'姬'=>1,'娛'=>1,'娧'=>1,'姘'=>1,'婦'=>1,'㛮'=>1,'㛼'=>1,'嬈'=>1,'嬾'=>1,'嬾'=>1,'𡧈'=>1,'寃'=>1,'寘'=>1,'寧'=>1,'寳'=>1,'𡬘'=>1,'寿'=>1,'将'=>1,'当'=>1,'尢'=>1,'㞁'=>1,'屠'=>1,'屮'=>1,'峀'=>1,'岍'=>1,'𡷤'=>1,'嵃'=>1,'𡷦'=>1,'嵮'=>1,'嵫'=>1,'嵼'=>1,'巡'=>1,'巢'=>1,'㠯'=>1,'巽'=>1,'帨'=>1,'帽'=>1,'幩'=>1,'㡢'=>1,'𢆃'=>1,'㡼'=>1,'庰'=>1,'庳'=>1,'庶'=>1,'廊'=>1,'𪎒'=>1,'廾'=>1,'𢌱'=>1,'𢌱'=>1,'舁'=>1,'弢'=>1,'弢'=>1,'㣇'=>1,'𣊸'=>1,'𦇚'=>1,'形'=>1,'彫'=>1,'㣣'=>1,'徚'=>1,'忍'=>1,'志'=>1,'忹'=>1,'悁'=>1,'㤺'=>1,'㤜'=>1,'悔'=>1,'𢛔'=>1,'惇'=>1,'慈'=>1,'慌'=>1,'慎'=>1,'慌'=>1,'慺'=>1,'憎'=>1,'憲'=>1,'憤'=>1,'憯'=>1,'懞'=>1,'懲'=>1,'懶'=>1,'成'=>1,'戛'=>1,'扝'=>1,'抱'=>1,'拔'=>1,'捐'=>1,'𢬌'=>1,'挽'=>1,'拼'=>1,'捨'=>1,'掃'=>1,'揤'=>1,'𢯱'=>1,'搢'=>1,'揅'=>1,'掩'=>1,'㨮'=>1,'摩'=>1,'摾'=>1,'撝'=>1,'摷'=>1,'㩬'=>1,'敏'=>1,'敬'=>1,'𣀊'=>1,'旣'=>1,'書'=>1,'晉'=>1,'㬙'=>1,'暑'=>1,'㬈'=>1,'㫤'=>1,'冒'=>1,'冕'=>1,'最'=>1,'暜'=>1,'肭'=>1,'䏙'=>1,'朗'=>1,'望'=>1,'朡'=>1,'杞'=>1,'杓'=>1,'𣏃'=>1,'㭉'=>1,'柺'=>1,'枅'=>1,'桒'=>1,'梅'=>1,'𣑭'=>1,'梎'=>1,'栟'=>1,'椔'=>1,'㮝'=>1,'楂'=>1,'榣'=>1,'槪'=>1,'檨'=>1,'𣚣'=>1,'櫛'=>1,'㰘'=>1,'次'=>1,'𣢧'=>1,'歔'=>1,'㱎'=>1,'歲'=>1,'殟'=>1,'殺'=>1,'殻'=>1,'𣪍'=>1,'𡴋'=>1,'𣫺'=>1,'汎'=>1,'𣲼'=>1,'沿'=>1,'泍'=>1,'汧'=>1,'洖'=>1,'派'=>1,'海'=>1,'流'=>1,'浩'=>1,'浸'=>1,'涅'=>1,'𣴞'=>1,'洴'=>1,'港'=>1,'湮'=>1,'㴳'=>1,'滋'=>1,'滇'=>1,'𣻑'=>1,'淹'=>1,'潮'=>1,'𣽞'=>1,'𣾎'=>1,'濆'=>1,'瀹'=>1,'瀞'=>1,'瀛'=>1,'㶖'=>1,'灊'=>1,'災'=>1,'灷'=>1,'炭'=>1,'𠔥'=>1,'煅'=>1,'𤉣'=>1,'熜'=>1,'𤎫'=>1,'爨'=>1,'爵'=>1,'牐'=>1,'𤘈'=>1,'犀'=>1,'犕'=>1,'𤜵'=>1,'𤠔'=>1,'獺'=>1,'王'=>1,'㺬'=>1,'玥'=>1,'㺸'=>1,'㺸'=>1,'瑇'=>1,'瑜'=>1,'瑱'=>1,'璅'=>1,'瓊'=>1,'㼛'=>1,'甤'=>1,'𤰶'=>1,'甾'=>1,'𤲒'=>1,'異'=>1,'𢆟'=>1,'瘐'=>1,'𤾡'=>1,'𤾸'=>1,'𥁄'=>1,'㿼'=>1,'䀈'=>1,'直'=>1,'𥃳'=>1,'𥃲'=>1,'𥄙'=>1,'𥄳'=>1,'眞'=>1,'真'=>1,'真'=>1,'睊'=>1,'䀹'=>1,'瞋'=>1,'䁆'=>1,'䂖'=>1,'𥐝'=>1,'硎'=>1,'碌'=>1,'磌'=>1,'䃣'=>1,'𥘦'=>1,'祖'=>1,'𥚚'=>1,'𥛅'=>1,'福'=>1,'秫'=>1,'䄯'=>1,'穀'=>1,'穊'=>1,'穏'=>1,'𥥼'=>1,'𥪧'=>1,'𥪧'=>1,'竮'=>1,'䈂'=>1,'𥮫'=>1,'篆'=>1,'築'=>1,'䈧'=>1,'𥲀'=>1,'糒'=>1,'䊠'=>1,'糨'=>1,'糣'=>1,'紀'=>1,'𥾆'=>1,'絣'=>1,'䌁'=>1,'緇'=>1,'縂'=>1,'繅'=>1,'䌴'=>1,'𦈨'=>1,'𦉇'=>1,'䍙'=>1,'𦋙'=>1,'罺'=>1,'𦌾'=>1,'羕'=>1,'翺'=>1,'者'=>1,'𦓚'=>1,'𦔣'=>1,'聠'=>1,'𦖨'=>1,'聰'=>1,'𣍟'=>1,'䏕'=>1,'育'=>1,'脃'=>1,'䐋'=>1,'脾'=>1,'媵'=>1,'𦞧'=>1,'𦞵'=>1,'𣎓'=>1,'𣎜'=>1,'舁'=>1,'舄'=>1,'辞'=>1,'䑫'=>1,'芑'=>1,'芋'=>1,'芝'=>1,'劳'=>1,'花'=>1,'芳'=>1,'芽'=>1,'苦'=>1,'𦬼'=>1,'若'=>1,'茝'=>1,'荣'=>1,'莭'=>1,'茣'=>1,'莽'=>1,'菧'=>1,'著'=>1,'荓'=>1,'菊'=>1,'菌'=>1,'菜'=>1,'𦰶'=>1,'𦵫'=>1,'𦳕'=>1,'䔫'=>1,'蓱'=>1,'蓳'=>1,'蔖'=>1,'𧏊'=>1,'蕤'=>1,'𦼬'=>1,'䕝'=>1,'䕡'=>1,'𦾱'=>1,'𧃒'=>1,'䕫'=>1,'虐'=>1,'虜'=>1,'虧'=>1,'虩'=>1,'蚩'=>1,'蚈'=>1,'蜎'=>1,'蛢'=>1,'蝹'=>1,'蜨'=>1,'蝫'=>1,'螆'=>1,'䗗'=>1,'蟡'=>1,'蠁'=>1,'䗹'=>1,'衠'=>1,'衣'=>1,'𧙧'=>1,'裗'=>1,'裞'=>1,'䘵'=>1,'裺'=>1,'㒻'=>1,'𧢮'=>1,'𧥦'=>1,'䚾'=>1,'䛇'=>1,'誠'=>1,'諭'=>1,'變'=>1,'豕'=>1,'𧲨'=>1,'貫'=>1,'賁'=>1,'贛'=>1,'起'=>1,'𧼯'=>1,'𠠄'=>1,'跋'=>1,'趼'=>1,'跰'=>1,'𠣞'=>1,'軔'=>1,'輸'=>1,'𨗒'=>1,'𨗭'=>1,'邔'=>1,'郱'=>1,'鄑'=>1,'𨜮'=>1,'鄛'=>1,'鈸'=>1,'鋗'=>1,'鋘'=>1,'鉼'=>1,'鏹'=>1,'鐕'=>1,'𨯺'=>1,'開'=>1,'䦕'=>1,'閷'=>1,'𨵷'=>1,'䧦'=>1,'雃'=>1,'嶲'=>1,'霣'=>1,'𩅅'=>1,'𩈚'=>1,'䩮'=>1,'䩶'=>1,'韠'=>1,'𩐊'=>1,'䪲'=>1,'𩒖'=>1,'頋'=>1,'頋'=>1,'頩'=>1,'𩖶'=>1,'飢'=>1,'䬳'=>1,'餩'=>1,'馧'=>1,'駂'=>1,'駾'=>1,'䯎'=>1,'𩬰'=>1,'鬒'=>1,'鱀'=>1,'鳽'=>1,'䳎'=>1,'䳭'=>1,'鵧'=>1,'𪃎'=>1,'䳸'=>1,'𪄅'=>1,'𪈎'=>1,'𪊑'=>1,'麻'=>1,'䵖'=>1,'黹'=>1,'黾'=>1,'鼅'=>1,'鼏'=>1,'鼖'=>1,'鼻'=>1,'𪘀'=>1,'̀'=>0,'́'=>0,'̂'=>0,'̃'=>0,'̄'=>0,'̆'=>0,'̇'=>0,'̈'=>0,'̉'=>0,'̊'=>0,'̋'=>0,'̌'=>0,'̏'=>0,'̑'=>0,'̓'=>0,'̔'=>0,'̛'=>0,'̣'=>0,'̤'=>0,'̥'=>0,'̦'=>0,'̧'=>0,'̨'=>0,'̭'=>0,'̮'=>0,'̰'=>0,'̱'=>0,'̸'=>0,'͂'=>0,'ͅ'=>0,'ٓ'=>0,'ٔ'=>0,'ٕ'=>0,'़'=>0,'া'=>0,'ৗ'=>0,'ା'=>0,'ୖ'=>0,'ୗ'=>0,'ா'=>0,'ௗ'=>0,'ౖ'=>0,'ೂ'=>0,'ೕ'=>0,'ೖ'=>0,'ാ'=>0,'ൗ'=>0,'්'=>0,'ා'=>0,'ෟ'=>0,'ီ'=>0,'ᅡ'=>0,'ᅢ'=>0,'ᅣ'=>0,'ᅤ'=>0,'ᅥ'=>0,'ᅦ'=>0,'ᅧ'=>0,'ᅨ'=>0,'ᅩ'=>0,'ᅪ'=>0,'ᅫ'=>0,'ᅬ'=>0,'ᅭ'=>0,'ᅮ'=>0,'ᅯ'=>0,'ᅰ'=>0,'ᅱ'=>0,'ᅲ'=>0,'ᅳ'=>0,'ᅴ'=>0,'ᅵ'=>0,'ᆨ'=>0,'ᆩ'=>0,'ᆪ'=>0,'ᆫ'=>0,'ᆬ'=>0,'ᆭ'=>0,'ᆮ'=>0,'ᆯ'=>0,'ᆰ'=>0,'ᆱ'=>0,'ᆲ'=>0,'ᆳ'=>0,'ᆴ'=>0,'ᆵ'=>0,'ᆶ'=>0,'ᆷ'=>0,'ᆸ'=>0,'ᆹ'=>0,'ᆺ'=>0,'ᆻ'=>0,'ᆼ'=>0,'ᆽ'=>0,'ᆾ'=>0,'ᆿ'=>0,'ᇀ'=>0,'ᇁ'=>0,'ᇂ'=>0,'ᬵ'=>0,'゙'=>0,'゚'=>0);
\ No newline at end of file +$GLOBALS['utf_nfc_qc']=array('̀'=>1,'́'=>1,'̓'=>1,'̈́'=>1,'ʹ'=>1,';'=>1,'·'=>1,'क़'=>1,'ख़'=>1,'ग़'=>1,'ज़'=>1,'ड़'=>1,'ढ़'=>1,'फ़'=>1,'य़'=>1,'ড়'=>1,'ঢ়'=>1,'য়'=>1,'ਲ਼'=>1,'ਸ਼'=>1,'ਖ਼'=>1,'ਗ਼'=>1,'ਜ਼'=>1,'ਫ਼'=>1,'ଡ଼'=>1,'ଢ଼'=>1,'གྷ'=>1,'ཌྷ'=>1,'དྷ'=>1,'བྷ'=>1,'ཛྷ'=>1,'ཀྵ'=>1,'ཱི'=>1,'ཱུ'=>1,'ྲྀ'=>1,'ླྀ'=>1,'ཱྀ'=>1,'ྒྷ'=>1,'ྜྷ'=>1,'ྡྷ'=>1,'ྦྷ'=>1,'ྫྷ'=>1,'ྐྵ'=>1,'ά'=>1,'έ'=>1,'ή'=>1,'ί'=>1,'ό'=>1,'ύ'=>1,'ώ'=>1,'Ά'=>1,'ι'=>1,'Έ'=>1,'Ή'=>1,'ΐ'=>1,'Ί'=>1,'ΰ'=>1,'Ύ'=>1,'΅'=>1,'`'=>1,'Ό'=>1,'Ώ'=>1,'´'=>1,' '=>1,' '=>1,'Ω'=>1,'K'=>1,'Å'=>1,'〈'=>1,'〉'=>1,'⫝̸'=>1,'豈'=>1,'更'=>1,'車'=>1,'賈'=>1,'滑'=>1,'串'=>1,'句'=>1,'龜'=>1,'龜'=>1,'契'=>1,'金'=>1,'喇'=>1,'奈'=>1,'懶'=>1,'癩'=>1,'羅'=>1,'蘿'=>1,'螺'=>1,'裸'=>1,'邏'=>1,'樂'=>1,'洛'=>1,'烙'=>1,'珞'=>1,'落'=>1,'酪'=>1,'駱'=>1,'亂'=>1,'卵'=>1,'欄'=>1,'爛'=>1,'蘭'=>1,'鸞'=>1,'嵐'=>1,'濫'=>1,'藍'=>1,'襤'=>1,'拉'=>1,'臘'=>1,'蠟'=>1,'廊'=>1,'朗'=>1,'浪'=>1,'狼'=>1,'郎'=>1,'來'=>1,'冷'=>1,'勞'=>1,'擄'=>1,'櫓'=>1,'爐'=>1,'盧'=>1,'老'=>1,'蘆'=>1,'虜'=>1,'路'=>1,'露'=>1,'魯'=>1,'鷺'=>1,'碌'=>1,'祿'=>1,'綠'=>1,'菉'=>1,'錄'=>1,'鹿'=>1,'論'=>1,'壟'=>1,'弄'=>1,'籠'=>1,'聾'=>1,'牢'=>1,'磊'=>1,'賂'=>1,'雷'=>1,'壘'=>1,'屢'=>1,'樓'=>1,'淚'=>1,'漏'=>1,'累'=>1,'縷'=>1,'陋'=>1,'勒'=>1,'肋'=>1,'凜'=>1,'凌'=>1,'稜'=>1,'綾'=>1,'菱'=>1,'陵'=>1,'讀'=>1,'拏'=>1,'樂'=>1,'諾'=>1,'丹'=>1,'寧'=>1,'怒'=>1,'率'=>1,'異'=>1,'北'=>1,'磻'=>1,'便'=>1,'復'=>1,'不'=>1,'泌'=>1,'數'=>1,'索'=>1,'參'=>1,'塞'=>1,'省'=>1,'葉'=>1,'說'=>1,'殺'=>1,'辰'=>1,'沈'=>1,'拾'=>1,'若'=>1,'掠'=>1,'略'=>1,'亮'=>1,'兩'=>1,'凉'=>1,'梁'=>1,'糧'=>1,'良'=>1,'諒'=>1,'量'=>1,'勵'=>1,'呂'=>1,'女'=>1,'廬'=>1,'旅'=>1,'濾'=>1,'礪'=>1,'閭'=>1,'驪'=>1,'麗'=>1,'黎'=>1,'力'=>1,'曆'=>1,'歷'=>1,'轢'=>1,'年'=>1,'憐'=>1,'戀'=>1,'撚'=>1,'漣'=>1,'煉'=>1,'璉'=>1,'秊'=>1,'練'=>1,'聯'=>1,'輦'=>1,'蓮'=>1,'連'=>1,'鍊'=>1,'列'=>1,'劣'=>1,'咽'=>1,'烈'=>1,'裂'=>1,'說'=>1,'廉'=>1,'念'=>1,'捻'=>1,'殮'=>1,'簾'=>1,'獵'=>1,'令'=>1,'囹'=>1,'寧'=>1,'嶺'=>1,'怜'=>1,'玲'=>1,'瑩'=>1,'羚'=>1,'聆'=>1,'鈴'=>1,'零'=>1,'靈'=>1,'領'=>1,'例'=>1,'禮'=>1,'醴'=>1,'隸'=>1,'惡'=>1,'了'=>1,'僚'=>1,'寮'=>1,'尿'=>1,'料'=>1,'樂'=>1,'燎'=>1,'療'=>1,'蓼'=>1,'遼'=>1,'龍'=>1,'暈'=>1,'阮'=>1,'劉'=>1,'杻'=>1,'柳'=>1,'流'=>1,'溜'=>1,'琉'=>1,'留'=>1,'硫'=>1,'紐'=>1,'類'=>1,'六'=>1,'戮'=>1,'陸'=>1,'倫'=>1,'崙'=>1,'淪'=>1,'輪'=>1,'律'=>1,'慄'=>1,'栗'=>1,'率'=>1,'隆'=>1,'利'=>1,'吏'=>1,'履'=>1,'易'=>1,'李'=>1,'梨'=>1,'泥'=>1,'理'=>1,'痢'=>1,'罹'=>1,'裏'=>1,'裡'=>1,'里'=>1,'離'=>1,'匿'=>1,'溺'=>1,'吝'=>1,'燐'=>1,'璘'=>1,'藺'=>1,'隣'=>1,'鱗'=>1,'麟'=>1,'林'=>1,'淋'=>1,'臨'=>1,'立'=>1,'笠'=>1,'粒'=>1,'狀'=>1,'炙'=>1,'識'=>1,'什'=>1,'茶'=>1,'刺'=>1,'切'=>1,'度'=>1,'拓'=>1,'糖'=>1,'宅'=>1,'洞'=>1,'暴'=>1,'輻'=>1,'行'=>1,'降'=>1,'見'=>1,'廓'=>1,'兀'=>1,'嗀'=>1,'塚'=>1,'晴'=>1,'凞'=>1,'猪'=>1,'益'=>1,'礼'=>1,'神'=>1,'祥'=>1,'福'=>1,'靖'=>1,'精'=>1,'羽'=>1,'蘒'=>1,'諸'=>1,'逸'=>1,'都'=>1,'飯'=>1,'飼'=>1,'館'=>1,'鶴'=>1,'侮'=>1,'僧'=>1,'免'=>1,'勉'=>1,'勤'=>1,'卑'=>1,'喝'=>1,'嘆'=>1,'器'=>1,'塀'=>1,'墨'=>1,'層'=>1,'屮'=>1,'悔'=>1,'慨'=>1,'憎'=>1,'懲'=>1,'敏'=>1,'既'=>1,'暑'=>1,'梅'=>1,'海'=>1,'渚'=>1,'漢'=>1,'煮'=>1,'爫'=>1,'琢'=>1,'碑'=>1,'社'=>1,'祉'=>1,'祈'=>1,'祐'=>1,'祖'=>1,'祝'=>1,'禍'=>1,'禎'=>1,'穀'=>1,'突'=>1,'節'=>1,'練'=>1,'縉'=>1,'繁'=>1,'署'=>1,'者'=>1,'臭'=>1,'艹'=>1,'艹'=>1,'著'=>1,'褐'=>1,'視'=>1,'謁'=>1,'謹'=>1,'賓'=>1,'贈'=>1,'辶'=>1,'逸'=>1,'難'=>1,'響'=>1,'頻'=>1,'並'=>1,'况'=>1,'全'=>1,'侀'=>1,'充'=>1,'冀'=>1,'勇'=>1,'勺'=>1,'喝'=>1,'啕'=>1,'喙'=>1,'嗢'=>1,'塚'=>1,'墳'=>1,'奄'=>1,'奔'=>1,'婢'=>1,'嬨'=>1,'廒'=>1,'廙'=>1,'彩'=>1,'徭'=>1,'惘'=>1,'慎'=>1,'愈'=>1,'憎'=>1,'慠'=>1,'懲'=>1,'戴'=>1,'揄'=>1,'搜'=>1,'摒'=>1,'敖'=>1,'晴'=>1,'朗'=>1,'望'=>1,'杖'=>1,'歹'=>1,'殺'=>1,'流'=>1,'滛'=>1,'滋'=>1,'漢'=>1,'瀞'=>1,'煮'=>1,'瞧'=>1,'爵'=>1,'犯'=>1,'猪'=>1,'瑱'=>1,'甆'=>1,'画'=>1,'瘝'=>1,'瘟'=>1,'益'=>1,'盛'=>1,'直'=>1,'睊'=>1,'着'=>1,'磌'=>1,'窱'=>1,'節'=>1,'类'=>1,'絛'=>1,'練'=>1,'缾'=>1,'者'=>1,'荒'=>1,'華'=>1,'蝹'=>1,'襁'=>1,'覆'=>1,'視'=>1,'調'=>1,'諸'=>1,'請'=>1,'謁'=>1,'諾'=>1,'諭'=>1,'謹'=>1,'變'=>1,'贈'=>1,'輸'=>1,'遲'=>1,'醙'=>1,'鉶'=>1,'陼'=>1,'難'=>1,'靖'=>1,'韛'=>1,'響'=>1,'頋'=>1,'頻'=>1,'鬒'=>1,'龜'=>1,'𢡊'=>1,'𢡄'=>1,'𣏕'=>1,'㮝'=>1,'䀘'=>1,'䀹'=>1,'𥉉'=>1,'𥳐'=>1,'𧻓'=>1,'齃'=>1,'龎'=>1,'יִ'=>1,'ײַ'=>1,'שׁ'=>1,'שׂ'=>1,'שּׁ'=>1,'שּׂ'=>1,'אַ'=>1,'אָ'=>1,'אּ'=>1,'בּ'=>1,'גּ'=>1,'דּ'=>1,'הּ'=>1,'וּ'=>1,'זּ'=>1,'טּ'=>1,'יּ'=>1,'ךּ'=>1,'כּ'=>1,'לּ'=>1,'מּ'=>1,'נּ'=>1,'סּ'=>1,'ףּ'=>1,'פּ'=>1,'צּ'=>1,'קּ'=>1,'רּ'=>1,'שּ'=>1,'תּ'=>1,'וֹ'=>1,'בֿ'=>1,'כֿ'=>1,'פֿ'=>1,'𝅗𝅥'=>1,'𝅘𝅥'=>1,'𝅘𝅥𝅮'=>1,'𝅘𝅥𝅯'=>1,'𝅘𝅥𝅰'=>1,'𝅘𝅥𝅱'=>1,'𝅘𝅥𝅲'=>1,'𝆹𝅥'=>1,'𝆺𝅥'=>1,'𝆹𝅥𝅮'=>1,'𝆺𝅥𝅮'=>1,'𝆹𝅥𝅯'=>1,'𝆺𝅥𝅯'=>1,'丽'=>1,'丸'=>1,'乁'=>1,'𠄢'=>1,'你'=>1,'侮'=>1,'侻'=>1,'倂'=>1,'偺'=>1,'備'=>1,'僧'=>1,'像'=>1,'㒞'=>1,'𠘺'=>1,'免'=>1,'兔'=>1,'兤'=>1,'具'=>1,'𠔜'=>1,'㒹'=>1,'內'=>1,'再'=>1,'𠕋'=>1,'冗'=>1,'冤'=>1,'仌'=>1,'冬'=>1,'况'=>1,'𩇟'=>1,'凵'=>1,'刃'=>1,'㓟'=>1,'刻'=>1,'剆'=>1,'割'=>1,'剷'=>1,'㔕'=>1,'勇'=>1,'勉'=>1,'勤'=>1,'勺'=>1,'包'=>1,'匆'=>1,'北'=>1,'卉'=>1,'卑'=>1,'博'=>1,'即'=>1,'卽'=>1,'卿'=>1,'卿'=>1,'卿'=>1,'𠨬'=>1,'灰'=>1,'及'=>1,'叟'=>1,'𠭣'=>1,'叫'=>1,'叱'=>1,'吆'=>1,'咞'=>1,'吸'=>1,'呈'=>1,'周'=>1,'咢'=>1,'哶'=>1,'唐'=>1,'啓'=>1,'啣'=>1,'善'=>1,'善'=>1,'喙'=>1,'喫'=>1,'喳'=>1,'嗂'=>1,'圖'=>1,'嘆'=>1,'圗'=>1,'噑'=>1,'噴'=>1,'切'=>1,'壮'=>1,'城'=>1,'埴'=>1,'堍'=>1,'型'=>1,'堲'=>1,'報'=>1,'墬'=>1,'𡓤'=>1,'売'=>1,'壷'=>1,'夆'=>1,'多'=>1,'夢'=>1,'奢'=>1,'𡚨'=>1,'𡛪'=>1,'姬'=>1,'娛'=>1,'娧'=>1,'姘'=>1,'婦'=>1,'㛮'=>1,'㛼'=>1,'嬈'=>1,'嬾'=>1,'嬾'=>1,'𡧈'=>1,'寃'=>1,'寘'=>1,'寧'=>1,'寳'=>1,'𡬘'=>1,'寿'=>1,'将'=>1,'当'=>1,'尢'=>1,'㞁'=>1,'屠'=>1,'屮'=>1,'峀'=>1,'岍'=>1,'𡷤'=>1,'嵃'=>1,'𡷦'=>1,'嵮'=>1,'嵫'=>1,'嵼'=>1,'巡'=>1,'巢'=>1,'㠯'=>1,'巽'=>1,'帨'=>1,'帽'=>1,'幩'=>1,'㡢'=>1,'𢆃'=>1,'㡼'=>1,'庰'=>1,'庳'=>1,'庶'=>1,'廊'=>1,'𪎒'=>1,'廾'=>1,'𢌱'=>1,'𢌱'=>1,'舁'=>1,'弢'=>1,'弢'=>1,'㣇'=>1,'𣊸'=>1,'𦇚'=>1,'形'=>1,'彫'=>1,'㣣'=>1,'徚'=>1,'忍'=>1,'志'=>1,'忹'=>1,'悁'=>1,'㤺'=>1,'㤜'=>1,'悔'=>1,'𢛔'=>1,'惇'=>1,'慈'=>1,'慌'=>1,'慎'=>1,'慌'=>1,'慺'=>1,'憎'=>1,'憲'=>1,'憤'=>1,'憯'=>1,'懞'=>1,'懲'=>1,'懶'=>1,'成'=>1,'戛'=>1,'扝'=>1,'抱'=>1,'拔'=>1,'捐'=>1,'𢬌'=>1,'挽'=>1,'拼'=>1,'捨'=>1,'掃'=>1,'揤'=>1,'𢯱'=>1,'搢'=>1,'揅'=>1,'掩'=>1,'㨮'=>1,'摩'=>1,'摾'=>1,'撝'=>1,'摷'=>1,'㩬'=>1,'敏'=>1,'敬'=>1,'𣀊'=>1,'旣'=>1,'書'=>1,'晉'=>1,'㬙'=>1,'暑'=>1,'㬈'=>1,'㫤'=>1,'冒'=>1,'冕'=>1,'最'=>1,'暜'=>1,'肭'=>1,'䏙'=>1,'朗'=>1,'望'=>1,'朡'=>1,'杞'=>1,'杓'=>1,'𣏃'=>1,'㭉'=>1,'柺'=>1,'枅'=>1,'桒'=>1,'梅'=>1,'𣑭'=>1,'梎'=>1,'栟'=>1,'椔'=>1,'㮝'=>1,'楂'=>1,'榣'=>1,'槪'=>1,'檨'=>1,'𣚣'=>1,'櫛'=>1,'㰘'=>1,'次'=>1,'𣢧'=>1,'歔'=>1,'㱎'=>1,'歲'=>1,'殟'=>1,'殺'=>1,'殻'=>1,'𣪍'=>1,'𡴋'=>1,'𣫺'=>1,'汎'=>1,'𣲼'=>1,'沿'=>1,'泍'=>1,'汧'=>1,'洖'=>1,'派'=>1,'海'=>1,'流'=>1,'浩'=>1,'浸'=>1,'涅'=>1,'𣴞'=>1,'洴'=>1,'港'=>1,'湮'=>1,'㴳'=>1,'滋'=>1,'滇'=>1,'𣻑'=>1,'淹'=>1,'潮'=>1,'𣽞'=>1,'𣾎'=>1,'濆'=>1,'瀹'=>1,'瀞'=>1,'瀛'=>1,'㶖'=>1,'灊'=>1,'災'=>1,'灷'=>1,'炭'=>1,'𠔥'=>1,'煅'=>1,'𤉣'=>1,'熜'=>1,'𤎫'=>1,'爨'=>1,'爵'=>1,'牐'=>1,'𤘈'=>1,'犀'=>1,'犕'=>1,'𤜵'=>1,'𤠔'=>1,'獺'=>1,'王'=>1,'㺬'=>1,'玥'=>1,'㺸'=>1,'㺸'=>1,'瑇'=>1,'瑜'=>1,'瑱'=>1,'璅'=>1,'瓊'=>1,'㼛'=>1,'甤'=>1,'𤰶'=>1,'甾'=>1,'𤲒'=>1,'異'=>1,'𢆟'=>1,'瘐'=>1,'𤾡'=>1,'𤾸'=>1,'𥁄'=>1,'㿼'=>1,'䀈'=>1,'直'=>1,'𥃳'=>1,'𥃲'=>1,'𥄙'=>1,'𥄳'=>1,'眞'=>1,'真'=>1,'真'=>1,'睊'=>1,'䀹'=>1,'瞋'=>1,'䁆'=>1,'䂖'=>1,'𥐝'=>1,'硎'=>1,'碌'=>1,'磌'=>1,'䃣'=>1,'𥘦'=>1,'祖'=>1,'𥚚'=>1,'𥛅'=>1,'福'=>1,'秫'=>1,'䄯'=>1,'穀'=>1,'穊'=>1,'穏'=>1,'𥥼'=>1,'𥪧'=>1,'𥪧'=>1,'竮'=>1,'䈂'=>1,'𥮫'=>1,'篆'=>1,'築'=>1,'䈧'=>1,'𥲀'=>1,'糒'=>1,'䊠'=>1,'糨'=>1,'糣'=>1,'紀'=>1,'𥾆'=>1,'絣'=>1,'䌁'=>1,'緇'=>1,'縂'=>1,'繅'=>1,'䌴'=>1,'𦈨'=>1,'𦉇'=>1,'䍙'=>1,'𦋙'=>1,'罺'=>1,'𦌾'=>1,'羕'=>1,'翺'=>1,'者'=>1,'𦓚'=>1,'𦔣'=>1,'聠'=>1,'𦖨'=>1,'聰'=>1,'𣍟'=>1,'䏕'=>1,'育'=>1,'脃'=>1,'䐋'=>1,'脾'=>1,'媵'=>1,'𦞧'=>1,'𦞵'=>1,'𣎓'=>1,'𣎜'=>1,'舁'=>1,'舄'=>1,'辞'=>1,'䑫'=>1,'芑'=>1,'芋'=>1,'芝'=>1,'劳'=>1,'花'=>1,'芳'=>1,'芽'=>1,'苦'=>1,'𦬼'=>1,'若'=>1,'茝'=>1,'荣'=>1,'莭'=>1,'茣'=>1,'莽'=>1,'菧'=>1,'著'=>1,'荓'=>1,'菊'=>1,'菌'=>1,'菜'=>1,'𦰶'=>1,'𦵫'=>1,'𦳕'=>1,'䔫'=>1,'蓱'=>1,'蓳'=>1,'蔖'=>1,'𧏊'=>1,'蕤'=>1,'𦼬'=>1,'䕝'=>1,'䕡'=>1,'𦾱'=>1,'𧃒'=>1,'䕫'=>1,'虐'=>1,'虜'=>1,'虧'=>1,'虩'=>1,'蚩'=>1,'蚈'=>1,'蜎'=>1,'蛢'=>1,'蝹'=>1,'蜨'=>1,'蝫'=>1,'螆'=>1,'䗗'=>1,'蟡'=>1,'蠁'=>1,'䗹'=>1,'衠'=>1,'衣'=>1,'𧙧'=>1,'裗'=>1,'裞'=>1,'䘵'=>1,'裺'=>1,'㒻'=>1,'𧢮'=>1,'𧥦'=>1,'䚾'=>1,'䛇'=>1,'誠'=>1,'諭'=>1,'變'=>1,'豕'=>1,'𧲨'=>1,'貫'=>1,'賁'=>1,'贛'=>1,'起'=>1,'𧼯'=>1,'𠠄'=>1,'跋'=>1,'趼'=>1,'跰'=>1,'𠣞'=>1,'軔'=>1,'輸'=>1,'𨗒'=>1,'𨗭'=>1,'邔'=>1,'郱'=>1,'鄑'=>1,'𨜮'=>1,'鄛'=>1,'鈸'=>1,'鋗'=>1,'鋘'=>1,'鉼'=>1,'鏹'=>1,'鐕'=>1,'𨯺'=>1,'開'=>1,'䦕'=>1,'閷'=>1,'𨵷'=>1,'䧦'=>1,'雃'=>1,'嶲'=>1,'霣'=>1,'𩅅'=>1,'𩈚'=>1,'䩮'=>1,'䩶'=>1,'韠'=>1,'𩐊'=>1,'䪲'=>1,'𩒖'=>1,'頋'=>1,'頋'=>1,'頩'=>1,'𩖶'=>1,'飢'=>1,'䬳'=>1,'餩'=>1,'馧'=>1,'駂'=>1,'駾'=>1,'䯎'=>1,'𩬰'=>1,'鬒'=>1,'鱀'=>1,'鳽'=>1,'䳎'=>1,'䳭'=>1,'鵧'=>1,'𪃎'=>1,'䳸'=>1,'𪄅'=>1,'𪈎'=>1,'𪊑'=>1,'麻'=>1,'䵖'=>1,'黹'=>1,'黾'=>1,'鼅'=>1,'鼏'=>1,'鼖'=>1,'鼻'=>1,'𪘀'=>1,'̀'=>0,'́'=>0,'̂'=>0,'̃'=>0,'̄'=>0,'̆'=>0,'̇'=>0,'̈'=>0,'̉'=>0,'̊'=>0,'̋'=>0,'̌'=>0,'̏'=>0,'̑'=>0,'̓'=>0,'̔'=>0,'̛'=>0,'̣'=>0,'̤'=>0,'̥'=>0,'̦'=>0,'̧'=>0,'̨'=>0,'̭'=>0,'̮'=>0,'̰'=>0,'̱'=>0,'̸'=>0,'͂'=>0,'ͅ'=>0,'ٓ'=>0,'ٔ'=>0,'ٕ'=>0,'़'=>0,'া'=>0,'ৗ'=>0,'ା'=>0,'ୖ'=>0,'ୗ'=>0,'ா'=>0,'ௗ'=>0,'ౖ'=>0,'ೂ'=>0,'ೕ'=>0,'ೖ'=>0,'ാ'=>0,'ൗ'=>0,'්'=>0,'ා'=>0,'ෟ'=>0,'ီ'=>0,'ᅡ'=>0,'ᅢ'=>0,'ᅣ'=>0,'ᅤ'=>0,'ᅥ'=>0,'ᅦ'=>0,'ᅧ'=>0,'ᅨ'=>0,'ᅩ'=>0,'ᅪ'=>0,'ᅫ'=>0,'ᅬ'=>0,'ᅭ'=>0,'ᅮ'=>0,'ᅯ'=>0,'ᅰ'=>0,'ᅱ'=>0,'ᅲ'=>0,'ᅳ'=>0,'ᅴ'=>0,'ᅵ'=>0,'ᆨ'=>0,'ᆩ'=>0,'ᆪ'=>0,'ᆫ'=>0,'ᆬ'=>0,'ᆭ'=>0,'ᆮ'=>0,'ᆯ'=>0,'ᆰ'=>0,'ᆱ'=>0,'ᆲ'=>0,'ᆳ'=>0,'ᆴ'=>0,'ᆵ'=>0,'ᆶ'=>0,'ᆷ'=>0,'ᆸ'=>0,'ᆹ'=>0,'ᆺ'=>0,'ᆻ'=>0,'ᆼ'=>0,'ᆽ'=>0,'ᆾ'=>0,'ᆿ'=>0,'ᇀ'=>0,'ᇁ'=>0,'ᇂ'=>0,'ᬵ'=>0,'゙'=>0,'゚'=>0); diff --git a/phpBB/includes/utf/data/utf_nfkc_qc.php b/phpBB/includes/utf/data/utf_nfkc_qc.php index da9a8a0e89..181a07b351 100644 --- a/phpBB/includes/utf/data/utf_nfkc_qc.php +++ b/phpBB/includes/utf/data/utf_nfkc_qc.php @@ -1,2 +1,2 @@ <?php -$GLOBALS['utf_nfkc_qc']=array(' '=>1,'¨'=>1,'ª'=>1,'¯'=>1,'²'=>1,'³'=>1,'´'=>1,'µ'=>1,'¸'=>1,'¹'=>1,'º'=>1,'¼'=>1,'½'=>1,'¾'=>1,'IJ'=>1,'ij'=>1,'Ŀ'=>1,'ŀ'=>1,'ʼn'=>1,'ſ'=>1,'DŽ'=>1,'Dž'=>1,'dž'=>1,'LJ'=>1,'Lj'=>1,'lj'=>1,'NJ'=>1,'Nj'=>1,'nj'=>1,'DZ'=>1,'Dz'=>1,'dz'=>1,'ʰ'=>1,'ʱ'=>1,'ʲ'=>1,'ʳ'=>1,'ʴ'=>1,'ʵ'=>1,'ʶ'=>1,'ʷ'=>1,'ʸ'=>1,'˘'=>1,'˙'=>1,'˚'=>1,'˛'=>1,'˜'=>1,'˝'=>1,'ˠ'=>1,'ˡ'=>1,'ˢ'=>1,'ˣ'=>1,'ˤ'=>1,'̀'=>1,'́'=>1,'̓'=>1,'̈́'=>1,'ʹ'=>1,'ͺ'=>1,';'=>1,'΄'=>1,'΅'=>1,'·'=>1,'ϐ'=>1,'ϑ'=>1,'ϒ'=>1,'ϓ'=>1,'ϔ'=>1,'ϕ'=>1,'ϖ'=>1,'ϰ'=>1,'ϱ'=>1,'ϲ'=>1,'ϴ'=>1,'ϵ'=>1,'Ϲ'=>1,'և'=>1,'ٵ'=>1,'ٶ'=>1,'ٷ'=>1,'ٸ'=>1,'क़'=>1,'ख़'=>1,'ग़'=>1,'ज़'=>1,'ड़'=>1,'ढ़'=>1,'फ़'=>1,'य़'=>1,'ড়'=>1,'ঢ়'=>1,'য়'=>1,'ਲ਼'=>1,'ਸ਼'=>1,'ਖ਼'=>1,'ਗ਼'=>1,'ਜ਼'=>1,'ਫ਼'=>1,'ଡ଼'=>1,'ଢ଼'=>1,'ำ'=>1,'ຳ'=>1,'ໜ'=>1,'ໝ'=>1,'༌'=>1,'གྷ'=>1,'ཌྷ'=>1,'དྷ'=>1,'བྷ'=>1,'ཛྷ'=>1,'ཀྵ'=>1,'ཱི'=>1,'ཱུ'=>1,'ྲྀ'=>1,'ཷ'=>1,'ླྀ'=>1,'ཹ'=>1,'ཱྀ'=>1,'ྒྷ'=>1,'ྜྷ'=>1,'ྡྷ'=>1,'ྦྷ'=>1,'ྫྷ'=>1,'ྐྵ'=>1,'ჼ'=>1,'ᴬ'=>1,'ᴭ'=>1,'ᴮ'=>1,'ᴰ'=>1,'ᴱ'=>1,'ᴲ'=>1,'ᴳ'=>1,'ᴴ'=>1,'ᴵ'=>1,'ᴶ'=>1,'ᴷ'=>1,'ᴸ'=>1,'ᴹ'=>1,'ᴺ'=>1,'ᴼ'=>1,'ᴽ'=>1,'ᴾ'=>1,'ᴿ'=>1,'ᵀ'=>1,'ᵁ'=>1,'ᵂ'=>1,'ᵃ'=>1,'ᵄ'=>1,'ᵅ'=>1,'ᵆ'=>1,'ᵇ'=>1,'ᵈ'=>1,'ᵉ'=>1,'ᵊ'=>1,'ᵋ'=>1,'ᵌ'=>1,'ᵍ'=>1,'ᵏ'=>1,'ᵐ'=>1,'ᵑ'=>1,'ᵒ'=>1,'ᵓ'=>1,'ᵔ'=>1,'ᵕ'=>1,'ᵖ'=>1,'ᵗ'=>1,'ᵘ'=>1,'ᵙ'=>1,'ᵚ'=>1,'ᵛ'=>1,'ᵜ'=>1,'ᵝ'=>1,'ᵞ'=>1,'ᵟ'=>1,'ᵠ'=>1,'ᵡ'=>1,'ᵢ'=>1,'ᵣ'=>1,'ᵤ'=>1,'ᵥ'=>1,'ᵦ'=>1,'ᵧ'=>1,'ᵨ'=>1,'ᵩ'=>1,'ᵪ'=>1,'ᵸ'=>1,'ᶛ'=>1,'ᶜ'=>1,'ᶝ'=>1,'ᶞ'=>1,'ᶟ'=>1,'ᶠ'=>1,'ᶡ'=>1,'ᶢ'=>1,'ᶣ'=>1,'ᶤ'=>1,'ᶥ'=>1,'ᶦ'=>1,'ᶧ'=>1,'ᶨ'=>1,'ᶩ'=>1,'ᶪ'=>1,'ᶫ'=>1,'ᶬ'=>1,'ᶭ'=>1,'ᶮ'=>1,'ᶯ'=>1,'ᶰ'=>1,'ᶱ'=>1,'ᶲ'=>1,'ᶳ'=>1,'ᶴ'=>1,'ᶵ'=>1,'ᶶ'=>1,'ᶷ'=>1,'ᶸ'=>1,'ᶹ'=>1,'ᶺ'=>1,'ᶻ'=>1,'ᶼ'=>1,'ᶽ'=>1,'ᶾ'=>1,'ᶿ'=>1,'ẚ'=>1,'ẛ'=>1,'ά'=>1,'έ'=>1,'ή'=>1,'ί'=>1,'ό'=>1,'ύ'=>1,'ώ'=>1,'Ά'=>1,'᾽'=>1,'ι'=>1,'᾿'=>1,'῀'=>1,'῁'=>1,'Έ'=>1,'Ή'=>1,'῍'=>1,'῎'=>1,'῏'=>1,'ΐ'=>1,'Ί'=>1,'῝'=>1,'῞'=>1,'῟'=>1,'ΰ'=>1,'Ύ'=>1,'῭'=>1,'΅'=>1,'`'=>1,'Ό'=>1,'Ώ'=>1,'´'=>1,'῾'=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,'‑'=>1,'‗'=>1,'․'=>1,'‥'=>1,'…'=>1,' '=>1,'″'=>1,'‴'=>1,'‶'=>1,'‷'=>1,'‼'=>1,'‾'=>1,'⁇'=>1,'⁈'=>1,'⁉'=>1,'⁗'=>1,' '=>1,'⁰'=>1,'ⁱ'=>1,'⁴'=>1,'⁵'=>1,'⁶'=>1,'⁷'=>1,'⁸'=>1,'⁹'=>1,'⁺'=>1,'⁻'=>1,'⁼'=>1,'⁽'=>1,'⁾'=>1,'ⁿ'=>1,'₀'=>1,'₁'=>1,'₂'=>1,'₃'=>1,'₄'=>1,'₅'=>1,'₆'=>1,'₇'=>1,'₈'=>1,'₉'=>1,'₊'=>1,'₋'=>1,'₌'=>1,'₍'=>1,'₎'=>1,'ₐ'=>1,'ₑ'=>1,'ₒ'=>1,'ₓ'=>1,'ₔ'=>1,'₨'=>1,'℀'=>1,'℁'=>1,'ℂ'=>1,'℃'=>1,'℅'=>1,'℆'=>1,'ℇ'=>1,'℉'=>1,'ℊ'=>1,'ℋ'=>1,'ℌ'=>1,'ℍ'=>1,'ℎ'=>1,'ℏ'=>1,'ℐ'=>1,'ℑ'=>1,'ℒ'=>1,'ℓ'=>1,'ℕ'=>1,'№'=>1,'ℙ'=>1,'ℚ'=>1,'ℛ'=>1,'ℜ'=>1,'ℝ'=>1,'℠'=>1,'℡'=>1,'™'=>1,'ℤ'=>1,'Ω'=>1,'ℨ'=>1,'K'=>1,'Å'=>1,'ℬ'=>1,'ℭ'=>1,'ℯ'=>1,'ℰ'=>1,'ℱ'=>1,'ℳ'=>1,'ℴ'=>1,'ℵ'=>1,'ℶ'=>1,'ℷ'=>1,'ℸ'=>1,'ℹ'=>1,'℻'=>1,'ℼ'=>1,'ℽ'=>1,'ℾ'=>1,'ℿ'=>1,'⅀'=>1,'ⅅ'=>1,'ⅆ'=>1,'ⅇ'=>1,'ⅈ'=>1,'ⅉ'=>1,'⅓'=>1,'⅔'=>1,'⅕'=>1,'⅖'=>1,'⅗'=>1,'⅘'=>1,'⅙'=>1,'⅚'=>1,'⅛'=>1,'⅜'=>1,'⅝'=>1,'⅞'=>1,'⅟'=>1,'Ⅰ'=>1,'Ⅱ'=>1,'Ⅲ'=>1,'Ⅳ'=>1,'Ⅴ'=>1,'Ⅵ'=>1,'Ⅶ'=>1,'Ⅷ'=>1,'Ⅸ'=>1,'Ⅹ'=>1,'Ⅺ'=>1,'Ⅻ'=>1,'Ⅼ'=>1,'Ⅽ'=>1,'Ⅾ'=>1,'Ⅿ'=>1,'ⅰ'=>1,'ⅱ'=>1,'ⅲ'=>1,'ⅳ'=>1,'ⅴ'=>1,'ⅵ'=>1,'ⅶ'=>1,'ⅷ'=>1,'ⅸ'=>1,'ⅹ'=>1,'ⅺ'=>1,'ⅻ'=>1,'ⅼ'=>1,'ⅽ'=>1,'ⅾ'=>1,'ⅿ'=>1,'∬'=>1,'∭'=>1,'∯'=>1,'∰'=>1,'〈'=>1,'〉'=>1,'①'=>1,'②'=>1,'③'=>1,'④'=>1,'⑤'=>1,'⑥'=>1,'⑦'=>1,'⑧'=>1,'⑨'=>1,'⑩'=>1,'⑪'=>1,'⑫'=>1,'⑬'=>1,'⑭'=>1,'⑮'=>1,'⑯'=>1,'⑰'=>1,'⑱'=>1,'⑲'=>1,'⑳'=>1,'⑴'=>1,'⑵'=>1,'⑶'=>1,'⑷'=>1,'⑸'=>1,'⑹'=>1,'⑺'=>1,'⑻'=>1,'⑼'=>1,'⑽'=>1,'⑾'=>1,'⑿'=>1,'⒀'=>1,'⒁'=>1,'⒂'=>1,'⒃'=>1,'⒄'=>1,'⒅'=>1,'⒆'=>1,'⒇'=>1,'⒈'=>1,'⒉'=>1,'⒊'=>1,'⒋'=>1,'⒌'=>1,'⒍'=>1,'⒎'=>1,'⒏'=>1,'⒐'=>1,'⒑'=>1,'⒒'=>1,'⒓'=>1,'⒔'=>1,'⒕'=>1,'⒖'=>1,'⒗'=>1,'⒘'=>1,'⒙'=>1,'⒚'=>1,'⒛'=>1,'⒜'=>1,'⒝'=>1,'⒞'=>1,'⒟'=>1,'⒠'=>1,'⒡'=>1,'⒢'=>1,'⒣'=>1,'⒤'=>1,'⒥'=>1,'⒦'=>1,'⒧'=>1,'⒨'=>1,'⒩'=>1,'⒪'=>1,'⒫'=>1,'⒬'=>1,'⒭'=>1,'⒮'=>1,'⒯'=>1,'⒰'=>1,'⒱'=>1,'⒲'=>1,'⒳'=>1,'⒴'=>1,'⒵'=>1,'Ⓐ'=>1,'Ⓑ'=>1,'Ⓒ'=>1,'Ⓓ'=>1,'Ⓔ'=>1,'Ⓕ'=>1,'Ⓖ'=>1,'Ⓗ'=>1,'Ⓘ'=>1,'Ⓙ'=>1,'Ⓚ'=>1,'Ⓛ'=>1,'Ⓜ'=>1,'Ⓝ'=>1,'Ⓞ'=>1,'Ⓟ'=>1,'Ⓠ'=>1,'Ⓡ'=>1,'Ⓢ'=>1,'Ⓣ'=>1,'Ⓤ'=>1,'Ⓥ'=>1,'Ⓦ'=>1,'Ⓧ'=>1,'Ⓨ'=>1,'Ⓩ'=>1,'ⓐ'=>1,'ⓑ'=>1,'ⓒ'=>1,'ⓓ'=>1,'ⓔ'=>1,'ⓕ'=>1,'ⓖ'=>1,'ⓗ'=>1,'ⓘ'=>1,'ⓙ'=>1,'ⓚ'=>1,'ⓛ'=>1,'ⓜ'=>1,'ⓝ'=>1,'ⓞ'=>1,'ⓟ'=>1,'ⓠ'=>1,'ⓡ'=>1,'ⓢ'=>1,'ⓣ'=>1,'ⓤ'=>1,'ⓥ'=>1,'ⓦ'=>1,'ⓧ'=>1,'ⓨ'=>1,'ⓩ'=>1,'⓪'=>1,'⨌'=>1,'⩴'=>1,'⩵'=>1,'⩶'=>1,'⫝̸'=>1,'ⵯ'=>1,'⺟'=>1,'⻳'=>1,'⼀'=>1,'⼁'=>1,'⼂'=>1,'⼃'=>1,'⼄'=>1,'⼅'=>1,'⼆'=>1,'⼇'=>1,'⼈'=>1,'⼉'=>1,'⼊'=>1,'⼋'=>1,'⼌'=>1,'⼍'=>1,'⼎'=>1,'⼏'=>1,'⼐'=>1,'⼑'=>1,'⼒'=>1,'⼓'=>1,'⼔'=>1,'⼕'=>1,'⼖'=>1,'⼗'=>1,'⼘'=>1,'⼙'=>1,'⼚'=>1,'⼛'=>1,'⼜'=>1,'⼝'=>1,'⼞'=>1,'⼟'=>1,'⼠'=>1,'⼡'=>1,'⼢'=>1,'⼣'=>1,'⼤'=>1,'⼥'=>1,'⼦'=>1,'⼧'=>1,'⼨'=>1,'⼩'=>1,'⼪'=>1,'⼫'=>1,'⼬'=>1,'⼭'=>1,'⼮'=>1,'⼯'=>1,'⼰'=>1,'⼱'=>1,'⼲'=>1,'⼳'=>1,'⼴'=>1,'⼵'=>1,'⼶'=>1,'⼷'=>1,'⼸'=>1,'⼹'=>1,'⼺'=>1,'⼻'=>1,'⼼'=>1,'⼽'=>1,'⼾'=>1,'⼿'=>1,'⽀'=>1,'⽁'=>1,'⽂'=>1,'⽃'=>1,'⽄'=>1,'⽅'=>1,'⽆'=>1,'⽇'=>1,'⽈'=>1,'⽉'=>1,'⽊'=>1,'⽋'=>1,'⽌'=>1,'⽍'=>1,'⽎'=>1,'⽏'=>1,'⽐'=>1,'⽑'=>1,'⽒'=>1,'⽓'=>1,'⽔'=>1,'⽕'=>1,'⽖'=>1,'⽗'=>1,'⽘'=>1,'⽙'=>1,'⽚'=>1,'⽛'=>1,'⽜'=>1,'⽝'=>1,'⽞'=>1,'⽟'=>1,'⽠'=>1,'⽡'=>1,'⽢'=>1,'⽣'=>1,'⽤'=>1,'⽥'=>1,'⽦'=>1,'⽧'=>1,'⽨'=>1,'⽩'=>1,'⽪'=>1,'⽫'=>1,'⽬'=>1,'⽭'=>1,'⽮'=>1,'⽯'=>1,'⽰'=>1,'⽱'=>1,'⽲'=>1,'⽳'=>1,'⽴'=>1,'⽵'=>1,'⽶'=>1,'⽷'=>1,'⽸'=>1,'⽹'=>1,'⽺'=>1,'⽻'=>1,'⽼'=>1,'⽽'=>1,'⽾'=>1,'⽿'=>1,'⾀'=>1,'⾁'=>1,'⾂'=>1,'⾃'=>1,'⾄'=>1,'⾅'=>1,'⾆'=>1,'⾇'=>1,'⾈'=>1,'⾉'=>1,'⾊'=>1,'⾋'=>1,'⾌'=>1,'⾍'=>1,'⾎'=>1,'⾏'=>1,'⾐'=>1,'⾑'=>1,'⾒'=>1,'⾓'=>1,'⾔'=>1,'⾕'=>1,'⾖'=>1,'⾗'=>1,'⾘'=>1,'⾙'=>1,'⾚'=>1,'⾛'=>1,'⾜'=>1,'⾝'=>1,'⾞'=>1,'⾟'=>1,'⾠'=>1,'⾡'=>1,'⾢'=>1,'⾣'=>1,'⾤'=>1,'⾥'=>1,'⾦'=>1,'⾧'=>1,'⾨'=>1,'⾩'=>1,'⾪'=>1,'⾫'=>1,'⾬'=>1,'⾭'=>1,'⾮'=>1,'⾯'=>1,'⾰'=>1,'⾱'=>1,'⾲'=>1,'⾳'=>1,'⾴'=>1,'⾵'=>1,'⾶'=>1,'⾷'=>1,'⾸'=>1,'⾹'=>1,'⾺'=>1,'⾻'=>1,'⾼'=>1,'⾽'=>1,'⾾'=>1,'⾿'=>1,'⿀'=>1,'⿁'=>1,'⿂'=>1,'⿃'=>1,'⿄'=>1,'⿅'=>1,'⿆'=>1,'⿇'=>1,'⿈'=>1,'⿉'=>1,'⿊'=>1,'⿋'=>1,'⿌'=>1,'⿍'=>1,'⿎'=>1,'⿏'=>1,'⿐'=>1,'⿑'=>1,'⿒'=>1,'⿓'=>1,'⿔'=>1,'⿕'=>1,' '=>1,'〶'=>1,'〸'=>1,'〹'=>1,'〺'=>1,'゛'=>1,'゜'=>1,'ゟ'=>1,'ヿ'=>1,'ㄱ'=>1,'ㄲ'=>1,'ㄳ'=>1,'ㄴ'=>1,'ㄵ'=>1,'ㄶ'=>1,'ㄷ'=>1,'ㄸ'=>1,'ㄹ'=>1,'ㄺ'=>1,'ㄻ'=>1,'ㄼ'=>1,'ㄽ'=>1,'ㄾ'=>1,'ㄿ'=>1,'ㅀ'=>1,'ㅁ'=>1,'ㅂ'=>1,'ㅃ'=>1,'ㅄ'=>1,'ㅅ'=>1,'ㅆ'=>1,'ㅇ'=>1,'ㅈ'=>1,'ㅉ'=>1,'ㅊ'=>1,'ㅋ'=>1,'ㅌ'=>1,'ㅍ'=>1,'ㅎ'=>1,'ㅏ'=>1,'ㅐ'=>1,'ㅑ'=>1,'ㅒ'=>1,'ㅓ'=>1,'ㅔ'=>1,'ㅕ'=>1,'ㅖ'=>1,'ㅗ'=>1,'ㅘ'=>1,'ㅙ'=>1,'ㅚ'=>1,'ㅛ'=>1,'ㅜ'=>1,'ㅝ'=>1,'ㅞ'=>1,'ㅟ'=>1,'ㅠ'=>1,'ㅡ'=>1,'ㅢ'=>1,'ㅣ'=>1,'ㅤ'=>1,'ㅥ'=>1,'ㅦ'=>1,'ㅧ'=>1,'ㅨ'=>1,'ㅩ'=>1,'ㅪ'=>1,'ㅫ'=>1,'ㅬ'=>1,'ㅭ'=>1,'ㅮ'=>1,'ㅯ'=>1,'ㅰ'=>1,'ㅱ'=>1,'ㅲ'=>1,'ㅳ'=>1,'ㅴ'=>1,'ㅵ'=>1,'ㅶ'=>1,'ㅷ'=>1,'ㅸ'=>1,'ㅹ'=>1,'ㅺ'=>1,'ㅻ'=>1,'ㅼ'=>1,'ㅽ'=>1,'ㅾ'=>1,'ㅿ'=>1,'ㆀ'=>1,'ㆁ'=>1,'ㆂ'=>1,'ㆃ'=>1,'ㆄ'=>1,'ㆅ'=>1,'ㆆ'=>1,'ㆇ'=>1,'ㆈ'=>1,'ㆉ'=>1,'ㆊ'=>1,'ㆋ'=>1,'ㆌ'=>1,'ㆍ'=>1,'ㆎ'=>1,'㆒'=>1,'㆓'=>1,'㆔'=>1,'㆕'=>1,'㆖'=>1,'㆗'=>1,'㆘'=>1,'㆙'=>1,'㆚'=>1,'㆛'=>1,'㆜'=>1,'㆝'=>1,'㆞'=>1,'㆟'=>1,'㈀'=>1,'㈁'=>1,'㈂'=>1,'㈃'=>1,'㈄'=>1,'㈅'=>1,'㈆'=>1,'㈇'=>1,'㈈'=>1,'㈉'=>1,'㈊'=>1,'㈋'=>1,'㈌'=>1,'㈍'=>1,'㈎'=>1,'㈏'=>1,'㈐'=>1,'㈑'=>1,'㈒'=>1,'㈓'=>1,'㈔'=>1,'㈕'=>1,'㈖'=>1,'㈗'=>1,'㈘'=>1,'㈙'=>1,'㈚'=>1,'㈛'=>1,'㈜'=>1,'㈝'=>1,'㈞'=>1,'㈠'=>1,'㈡'=>1,'㈢'=>1,'㈣'=>1,'㈤'=>1,'㈥'=>1,'㈦'=>1,'㈧'=>1,'㈨'=>1,'㈩'=>1,'㈪'=>1,'㈫'=>1,'㈬'=>1,'㈭'=>1,'㈮'=>1,'㈯'=>1,'㈰'=>1,'㈱'=>1,'㈲'=>1,'㈳'=>1,'㈴'=>1,'㈵'=>1,'㈶'=>1,'㈷'=>1,'㈸'=>1,'㈹'=>1,'㈺'=>1,'㈻'=>1,'㈼'=>1,'㈽'=>1,'㈾'=>1,'㈿'=>1,'㉀'=>1,'㉁'=>1,'㉂'=>1,'㉃'=>1,'㉐'=>1,'㉑'=>1,'㉒'=>1,'㉓'=>1,'㉔'=>1,'㉕'=>1,'㉖'=>1,'㉗'=>1,'㉘'=>1,'㉙'=>1,'㉚'=>1,'㉛'=>1,'㉜'=>1,'㉝'=>1,'㉞'=>1,'㉟'=>1,'㉠'=>1,'㉡'=>1,'㉢'=>1,'㉣'=>1,'㉤'=>1,'㉥'=>1,'㉦'=>1,'㉧'=>1,'㉨'=>1,'㉩'=>1,'㉪'=>1,'㉫'=>1,'㉬'=>1,'㉭'=>1,'㉮'=>1,'㉯'=>1,'㉰'=>1,'㉱'=>1,'㉲'=>1,'㉳'=>1,'㉴'=>1,'㉵'=>1,'㉶'=>1,'㉷'=>1,'㉸'=>1,'㉹'=>1,'㉺'=>1,'㉻'=>1,'㉼'=>1,'㉽'=>1,'㉾'=>1,'㊀'=>1,'㊁'=>1,'㊂'=>1,'㊃'=>1,'㊄'=>1,'㊅'=>1,'㊆'=>1,'㊇'=>1,'㊈'=>1,'㊉'=>1,'㊊'=>1,'㊋'=>1,'㊌'=>1,'㊍'=>1,'㊎'=>1,'㊏'=>1,'㊐'=>1,'㊑'=>1,'㊒'=>1,'㊓'=>1,'㊔'=>1,'㊕'=>1,'㊖'=>1,'㊗'=>1,'㊘'=>1,'㊙'=>1,'㊚'=>1,'㊛'=>1,'㊜'=>1,'㊝'=>1,'㊞'=>1,'㊟'=>1,'㊠'=>1,'㊡'=>1,'㊢'=>1,'㊣'=>1,'㊤'=>1,'㊥'=>1,'㊦'=>1,'㊧'=>1,'㊨'=>1,'㊩'=>1,'㊪'=>1,'㊫'=>1,'㊬'=>1,'㊭'=>1,'㊮'=>1,'㊯'=>1,'㊰'=>1,'㊱'=>1,'㊲'=>1,'㊳'=>1,'㊴'=>1,'㊵'=>1,'㊶'=>1,'㊷'=>1,'㊸'=>1,'㊹'=>1,'㊺'=>1,'㊻'=>1,'㊼'=>1,'㊽'=>1,'㊾'=>1,'㊿'=>1,'㋀'=>1,'㋁'=>1,'㋂'=>1,'㋃'=>1,'㋄'=>1,'㋅'=>1,'㋆'=>1,'㋇'=>1,'㋈'=>1,'㋉'=>1,'㋊'=>1,'㋋'=>1,'㋌'=>1,'㋍'=>1,'㋎'=>1,'㋏'=>1,'㋐'=>1,'㋑'=>1,'㋒'=>1,'㋓'=>1,'㋔'=>1,'㋕'=>1,'㋖'=>1,'㋗'=>1,'㋘'=>1,'㋙'=>1,'㋚'=>1,'㋛'=>1,'㋜'=>1,'㋝'=>1,'㋞'=>1,'㋟'=>1,'㋠'=>1,'㋡'=>1,'㋢'=>1,'㋣'=>1,'㋤'=>1,'㋥'=>1,'㋦'=>1,'㋧'=>1,'㋨'=>1,'㋩'=>1,'㋪'=>1,'㋫'=>1,'㋬'=>1,'㋭'=>1,'㋮'=>1,'㋯'=>1,'㋰'=>1,'㋱'=>1,'㋲'=>1,'㋳'=>1,'㋴'=>1,'㋵'=>1,'㋶'=>1,'㋷'=>1,'㋸'=>1,'㋹'=>1,'㋺'=>1,'㋻'=>1,'㋼'=>1,'㋽'=>1,'㋾'=>1,'㌀'=>1,'㌁'=>1,'㌂'=>1,'㌃'=>1,'㌄'=>1,'㌅'=>1,'㌆'=>1,'㌇'=>1,'㌈'=>1,'㌉'=>1,'㌊'=>1,'㌋'=>1,'㌌'=>1,'㌍'=>1,'㌎'=>1,'㌏'=>1,'㌐'=>1,'㌑'=>1,'㌒'=>1,'㌓'=>1,'㌔'=>1,'㌕'=>1,'㌖'=>1,'㌗'=>1,'㌘'=>1,'㌙'=>1,'㌚'=>1,'㌛'=>1,'㌜'=>1,'㌝'=>1,'㌞'=>1,'㌟'=>1,'㌠'=>1,'㌡'=>1,'㌢'=>1,'㌣'=>1,'㌤'=>1,'㌥'=>1,'㌦'=>1,'㌧'=>1,'㌨'=>1,'㌩'=>1,'㌪'=>1,'㌫'=>1,'㌬'=>1,'㌭'=>1,'㌮'=>1,'㌯'=>1,'㌰'=>1,'㌱'=>1,'㌲'=>1,'㌳'=>1,'㌴'=>1,'㌵'=>1,'㌶'=>1,'㌷'=>1,'㌸'=>1,'㌹'=>1,'㌺'=>1,'㌻'=>1,'㌼'=>1,'㌽'=>1,'㌾'=>1,'㌿'=>1,'㍀'=>1,'㍁'=>1,'㍂'=>1,'㍃'=>1,'㍄'=>1,'㍅'=>1,'㍆'=>1,'㍇'=>1,'㍈'=>1,'㍉'=>1,'㍊'=>1,'㍋'=>1,'㍌'=>1,'㍍'=>1,'㍎'=>1,'㍏'=>1,'㍐'=>1,'㍑'=>1,'㍒'=>1,'㍓'=>1,'㍔'=>1,'㍕'=>1,'㍖'=>1,'㍗'=>1,'㍘'=>1,'㍙'=>1,'㍚'=>1,'㍛'=>1,'㍜'=>1,'㍝'=>1,'㍞'=>1,'㍟'=>1,'㍠'=>1,'㍡'=>1,'㍢'=>1,'㍣'=>1,'㍤'=>1,'㍥'=>1,'㍦'=>1,'㍧'=>1,'㍨'=>1,'㍩'=>1,'㍪'=>1,'㍫'=>1,'㍬'=>1,'㍭'=>1,'㍮'=>1,'㍯'=>1,'㍰'=>1,'㍱'=>1,'㍲'=>1,'㍳'=>1,'㍴'=>1,'㍵'=>1,'㍶'=>1,'㍷'=>1,'㍸'=>1,'㍹'=>1,'㍺'=>1,'㍻'=>1,'㍼'=>1,'㍽'=>1,'㍾'=>1,'㍿'=>1,'㎀'=>1,'㎁'=>1,'㎂'=>1,'㎃'=>1,'㎄'=>1,'㎅'=>1,'㎆'=>1,'㎇'=>1,'㎈'=>1,'㎉'=>1,'㎊'=>1,'㎋'=>1,'㎌'=>1,'㎍'=>1,'㎎'=>1,'㎏'=>1,'㎐'=>1,'㎑'=>1,'㎒'=>1,'㎓'=>1,'㎔'=>1,'㎕'=>1,'㎖'=>1,'㎗'=>1,'㎘'=>1,'㎙'=>1,'㎚'=>1,'㎛'=>1,'㎜'=>1,'㎝'=>1,'㎞'=>1,'㎟'=>1,'㎠'=>1,'㎡'=>1,'㎢'=>1,'㎣'=>1,'㎤'=>1,'㎥'=>1,'㎦'=>1,'㎧'=>1,'㎨'=>1,'㎩'=>1,'㎪'=>1,'㎫'=>1,'㎬'=>1,'㎭'=>1,'㎮'=>1,'㎯'=>1,'㎰'=>1,'㎱'=>1,'㎲'=>1,'㎳'=>1,'㎴'=>1,'㎵'=>1,'㎶'=>1,'㎷'=>1,'㎸'=>1,'㎹'=>1,'㎺'=>1,'㎻'=>1,'㎼'=>1,'㎽'=>1,'㎾'=>1,'㎿'=>1,'㏀'=>1,'㏁'=>1,'㏂'=>1,'㏃'=>1,'㏄'=>1,'㏅'=>1,'㏆'=>1,'㏇'=>1,'㏈'=>1,'㏉'=>1,'㏊'=>1,'㏋'=>1,'㏌'=>1,'㏍'=>1,'㏎'=>1,'㏏'=>1,'㏐'=>1,'㏑'=>1,'㏒'=>1,'㏓'=>1,'㏔'=>1,'㏕'=>1,'㏖'=>1,'㏗'=>1,'㏘'=>1,'㏙'=>1,'㏚'=>1,'㏛'=>1,'㏜'=>1,'㏝'=>1,'㏞'=>1,'㏟'=>1,'㏠'=>1,'㏡'=>1,'㏢'=>1,'㏣'=>1,'㏤'=>1,'㏥'=>1,'㏦'=>1,'㏧'=>1,'㏨'=>1,'㏩'=>1,'㏪'=>1,'㏫'=>1,'㏬'=>1,'㏭'=>1,'㏮'=>1,'㏯'=>1,'㏰'=>1,'㏱'=>1,'㏲'=>1,'㏳'=>1,'㏴'=>1,'㏵'=>1,'㏶'=>1,'㏷'=>1,'㏸'=>1,'㏹'=>1,'㏺'=>1,'㏻'=>1,'㏼'=>1,'㏽'=>1,'㏾'=>1,'㏿'=>1,'豈'=>1,'更'=>1,'車'=>1,'賈'=>1,'滑'=>1,'串'=>1,'句'=>1,'龜'=>1,'龜'=>1,'契'=>1,'金'=>1,'喇'=>1,'奈'=>1,'懶'=>1,'癩'=>1,'羅'=>1,'蘿'=>1,'螺'=>1,'裸'=>1,'邏'=>1,'樂'=>1,'洛'=>1,'烙'=>1,'珞'=>1,'落'=>1,'酪'=>1,'駱'=>1,'亂'=>1,'卵'=>1,'欄'=>1,'爛'=>1,'蘭'=>1,'鸞'=>1,'嵐'=>1,'濫'=>1,'藍'=>1,'襤'=>1,'拉'=>1,'臘'=>1,'蠟'=>1,'廊'=>1,'朗'=>1,'浪'=>1,'狼'=>1,'郎'=>1,'來'=>1,'冷'=>1,'勞'=>1,'擄'=>1,'櫓'=>1,'爐'=>1,'盧'=>1,'老'=>1,'蘆'=>1,'虜'=>1,'路'=>1,'露'=>1,'魯'=>1,'鷺'=>1,'碌'=>1,'祿'=>1,'綠'=>1,'菉'=>1,'錄'=>1,'鹿'=>1,'論'=>1,'壟'=>1,'弄'=>1,'籠'=>1,'聾'=>1,'牢'=>1,'磊'=>1,'賂'=>1,'雷'=>1,'壘'=>1,'屢'=>1,'樓'=>1,'淚'=>1,'漏'=>1,'累'=>1,'縷'=>1,'陋'=>1,'勒'=>1,'肋'=>1,'凜'=>1,'凌'=>1,'稜'=>1,'綾'=>1,'菱'=>1,'陵'=>1,'讀'=>1,'拏'=>1,'樂'=>1,'諾'=>1,'丹'=>1,'寧'=>1,'怒'=>1,'率'=>1,'異'=>1,'北'=>1,'磻'=>1,'便'=>1,'復'=>1,'不'=>1,'泌'=>1,'數'=>1,'索'=>1,'參'=>1,'塞'=>1,'省'=>1,'葉'=>1,'說'=>1,'殺'=>1,'辰'=>1,'沈'=>1,'拾'=>1,'若'=>1,'掠'=>1,'略'=>1,'亮'=>1,'兩'=>1,'凉'=>1,'梁'=>1,'糧'=>1,'良'=>1,'諒'=>1,'量'=>1,'勵'=>1,'呂'=>1,'女'=>1,'廬'=>1,'旅'=>1,'濾'=>1,'礪'=>1,'閭'=>1,'驪'=>1,'麗'=>1,'黎'=>1,'力'=>1,'曆'=>1,'歷'=>1,'轢'=>1,'年'=>1,'憐'=>1,'戀'=>1,'撚'=>1,'漣'=>1,'煉'=>1,'璉'=>1,'秊'=>1,'練'=>1,'聯'=>1,'輦'=>1,'蓮'=>1,'連'=>1,'鍊'=>1,'列'=>1,'劣'=>1,'咽'=>1,'烈'=>1,'裂'=>1,'說'=>1,'廉'=>1,'念'=>1,'捻'=>1,'殮'=>1,'簾'=>1,'獵'=>1,'令'=>1,'囹'=>1,'寧'=>1,'嶺'=>1,'怜'=>1,'玲'=>1,'瑩'=>1,'羚'=>1,'聆'=>1,'鈴'=>1,'零'=>1,'靈'=>1,'領'=>1,'例'=>1,'禮'=>1,'醴'=>1,'隸'=>1,'惡'=>1,'了'=>1,'僚'=>1,'寮'=>1,'尿'=>1,'料'=>1,'樂'=>1,'燎'=>1,'療'=>1,'蓼'=>1,'遼'=>1,'龍'=>1,'暈'=>1,'阮'=>1,'劉'=>1,'杻'=>1,'柳'=>1,'流'=>1,'溜'=>1,'琉'=>1,'留'=>1,'硫'=>1,'紐'=>1,'類'=>1,'六'=>1,'戮'=>1,'陸'=>1,'倫'=>1,'崙'=>1,'淪'=>1,'輪'=>1,'律'=>1,'慄'=>1,'栗'=>1,'率'=>1,'隆'=>1,'利'=>1,'吏'=>1,'履'=>1,'易'=>1,'李'=>1,'梨'=>1,'泥'=>1,'理'=>1,'痢'=>1,'罹'=>1,'裏'=>1,'裡'=>1,'里'=>1,'離'=>1,'匿'=>1,'溺'=>1,'吝'=>1,'燐'=>1,'璘'=>1,'藺'=>1,'隣'=>1,'鱗'=>1,'麟'=>1,'林'=>1,'淋'=>1,'臨'=>1,'立'=>1,'笠'=>1,'粒'=>1,'狀'=>1,'炙'=>1,'識'=>1,'什'=>1,'茶'=>1,'刺'=>1,'切'=>1,'度'=>1,'拓'=>1,'糖'=>1,'宅'=>1,'洞'=>1,'暴'=>1,'輻'=>1,'行'=>1,'降'=>1,'見'=>1,'廓'=>1,'兀'=>1,'嗀'=>1,'塚'=>1,'晴'=>1,'凞'=>1,'猪'=>1,'益'=>1,'礼'=>1,'神'=>1,'祥'=>1,'福'=>1,'靖'=>1,'精'=>1,'羽'=>1,'蘒'=>1,'諸'=>1,'逸'=>1,'都'=>1,'飯'=>1,'飼'=>1,'館'=>1,'鶴'=>1,'侮'=>1,'僧'=>1,'免'=>1,'勉'=>1,'勤'=>1,'卑'=>1,'喝'=>1,'嘆'=>1,'器'=>1,'塀'=>1,'墨'=>1,'層'=>1,'屮'=>1,'悔'=>1,'慨'=>1,'憎'=>1,'懲'=>1,'敏'=>1,'既'=>1,'暑'=>1,'梅'=>1,'海'=>1,'渚'=>1,'漢'=>1,'煮'=>1,'爫'=>1,'琢'=>1,'碑'=>1,'社'=>1,'祉'=>1,'祈'=>1,'祐'=>1,'祖'=>1,'祝'=>1,'禍'=>1,'禎'=>1,'穀'=>1,'突'=>1,'節'=>1,'練'=>1,'縉'=>1,'繁'=>1,'署'=>1,'者'=>1,'臭'=>1,'艹'=>1,'艹'=>1,'著'=>1,'褐'=>1,'視'=>1,'謁'=>1,'謹'=>1,'賓'=>1,'贈'=>1,'辶'=>1,'逸'=>1,'難'=>1,'響'=>1,'頻'=>1,'並'=>1,'况'=>1,'全'=>1,'侀'=>1,'充'=>1,'冀'=>1,'勇'=>1,'勺'=>1,'喝'=>1,'啕'=>1,'喙'=>1,'嗢'=>1,'塚'=>1,'墳'=>1,'奄'=>1,'奔'=>1,'婢'=>1,'嬨'=>1,'廒'=>1,'廙'=>1,'彩'=>1,'徭'=>1,'惘'=>1,'慎'=>1,'愈'=>1,'憎'=>1,'慠'=>1,'懲'=>1,'戴'=>1,'揄'=>1,'搜'=>1,'摒'=>1,'敖'=>1,'晴'=>1,'朗'=>1,'望'=>1,'杖'=>1,'歹'=>1,'殺'=>1,'流'=>1,'滛'=>1,'滋'=>1,'漢'=>1,'瀞'=>1,'煮'=>1,'瞧'=>1,'爵'=>1,'犯'=>1,'猪'=>1,'瑱'=>1,'甆'=>1,'画'=>1,'瘝'=>1,'瘟'=>1,'益'=>1,'盛'=>1,'直'=>1,'睊'=>1,'着'=>1,'磌'=>1,'窱'=>1,'節'=>1,'类'=>1,'絛'=>1,'練'=>1,'缾'=>1,'者'=>1,'荒'=>1,'華'=>1,'蝹'=>1,'襁'=>1,'覆'=>1,'視'=>1,'調'=>1,'諸'=>1,'請'=>1,'謁'=>1,'諾'=>1,'諭'=>1,'謹'=>1,'變'=>1,'贈'=>1,'輸'=>1,'遲'=>1,'醙'=>1,'鉶'=>1,'陼'=>1,'難'=>1,'靖'=>1,'韛'=>1,'響'=>1,'頋'=>1,'頻'=>1,'鬒'=>1,'龜'=>1,'𢡊'=>1,'𢡄'=>1,'𣏕'=>1,'㮝'=>1,'䀘'=>1,'䀹'=>1,'𥉉'=>1,'𥳐'=>1,'𧻓'=>1,'齃'=>1,'龎'=>1,'ff'=>1,'fi'=>1,'fl'=>1,'ffi'=>1,'ffl'=>1,'ſt'=>1,'st'=>1,'ﬓ'=>1,'ﬔ'=>1,'ﬕ'=>1,'ﬖ'=>1,'ﬗ'=>1,'יִ'=>1,'ײַ'=>1,'ﬠ'=>1,'ﬡ'=>1,'ﬢ'=>1,'ﬣ'=>1,'ﬤ'=>1,'ﬥ'=>1,'ﬦ'=>1,'ﬧ'=>1,'ﬨ'=>1,'﬩'=>1,'שׁ'=>1,'שׂ'=>1,'שּׁ'=>1,'שּׂ'=>1,'אַ'=>1,'אָ'=>1,'אּ'=>1,'בּ'=>1,'גּ'=>1,'דּ'=>1,'הּ'=>1,'וּ'=>1,'זּ'=>1,'טּ'=>1,'יּ'=>1,'ךּ'=>1,'כּ'=>1,'לּ'=>1,'מּ'=>1,'נּ'=>1,'סּ'=>1,'ףּ'=>1,'פּ'=>1,'צּ'=>1,'קּ'=>1,'רּ'=>1,'שּ'=>1,'תּ'=>1,'וֹ'=>1,'בֿ'=>1,'כֿ'=>1,'פֿ'=>1,'ﭏ'=>1,'ﭐ'=>1,'ﭑ'=>1,'ﭒ'=>1,'ﭓ'=>1,'ﭔ'=>1,'ﭕ'=>1,'ﭖ'=>1,'ﭗ'=>1,'ﭘ'=>1,'ﭙ'=>1,'ﭚ'=>1,'ﭛ'=>1,'ﭜ'=>1,'ﭝ'=>1,'ﭞ'=>1,'ﭟ'=>1,'ﭠ'=>1,'ﭡ'=>1,'ﭢ'=>1,'ﭣ'=>1,'ﭤ'=>1,'ﭥ'=>1,'ﭦ'=>1,'ﭧ'=>1,'ﭨ'=>1,'ﭩ'=>1,'ﭪ'=>1,'ﭫ'=>1,'ﭬ'=>1,'ﭭ'=>1,'ﭮ'=>1,'ﭯ'=>1,'ﭰ'=>1,'ﭱ'=>1,'ﭲ'=>1,'ﭳ'=>1,'ﭴ'=>1,'ﭵ'=>1,'ﭶ'=>1,'ﭷ'=>1,'ﭸ'=>1,'ﭹ'=>1,'ﭺ'=>1,'ﭻ'=>1,'ﭼ'=>1,'ﭽ'=>1,'ﭾ'=>1,'ﭿ'=>1,'ﮀ'=>1,'ﮁ'=>1,'ﮂ'=>1,'ﮃ'=>1,'ﮄ'=>1,'ﮅ'=>1,'ﮆ'=>1,'ﮇ'=>1,'ﮈ'=>1,'ﮉ'=>1,'ﮊ'=>1,'ﮋ'=>1,'ﮌ'=>1,'ﮍ'=>1,'ﮎ'=>1,'ﮏ'=>1,'ﮐ'=>1,'ﮑ'=>1,'ﮒ'=>1,'ﮓ'=>1,'ﮔ'=>1,'ﮕ'=>1,'ﮖ'=>1,'ﮗ'=>1,'ﮘ'=>1,'ﮙ'=>1,'ﮚ'=>1,'ﮛ'=>1,'ﮜ'=>1,'ﮝ'=>1,'ﮞ'=>1,'ﮟ'=>1,'ﮠ'=>1,'ﮡ'=>1,'ﮢ'=>1,'ﮣ'=>1,'ﮤ'=>1,'ﮥ'=>1,'ﮦ'=>1,'ﮧ'=>1,'ﮨ'=>1,'ﮩ'=>1,'ﮪ'=>1,'ﮫ'=>1,'ﮬ'=>1,'ﮭ'=>1,'ﮮ'=>1,'ﮯ'=>1,'ﮰ'=>1,'ﮱ'=>1,'ﯓ'=>1,'ﯔ'=>1,'ﯕ'=>1,'ﯖ'=>1,'ﯗ'=>1,'ﯘ'=>1,'ﯙ'=>1,'ﯚ'=>1,'ﯛ'=>1,'ﯜ'=>1,'ﯝ'=>1,'ﯞ'=>1,'ﯟ'=>1,'ﯠ'=>1,'ﯡ'=>1,'ﯢ'=>1,'ﯣ'=>1,'ﯤ'=>1,'ﯥ'=>1,'ﯦ'=>1,'ﯧ'=>1,'ﯨ'=>1,'ﯩ'=>1,'ﯪ'=>1,'ﯫ'=>1,'ﯬ'=>1,'ﯭ'=>1,'ﯮ'=>1,'ﯯ'=>1,'ﯰ'=>1,'ﯱ'=>1,'ﯲ'=>1,'ﯳ'=>1,'ﯴ'=>1,'ﯵ'=>1,'ﯶ'=>1,'ﯷ'=>1,'ﯸ'=>1,'ﯹ'=>1,'ﯺ'=>1,'ﯻ'=>1,'ﯼ'=>1,'ﯽ'=>1,'ﯾ'=>1,'ﯿ'=>1,'ﰀ'=>1,'ﰁ'=>1,'ﰂ'=>1,'ﰃ'=>1,'ﰄ'=>1,'ﰅ'=>1,'ﰆ'=>1,'ﰇ'=>1,'ﰈ'=>1,'ﰉ'=>1,'ﰊ'=>1,'ﰋ'=>1,'ﰌ'=>1,'ﰍ'=>1,'ﰎ'=>1,'ﰏ'=>1,'ﰐ'=>1,'ﰑ'=>1,'ﰒ'=>1,'ﰓ'=>1,'ﰔ'=>1,'ﰕ'=>1,'ﰖ'=>1,'ﰗ'=>1,'ﰘ'=>1,'ﰙ'=>1,'ﰚ'=>1,'ﰛ'=>1,'ﰜ'=>1,'ﰝ'=>1,'ﰞ'=>1,'ﰟ'=>1,'ﰠ'=>1,'ﰡ'=>1,'ﰢ'=>1,'ﰣ'=>1,'ﰤ'=>1,'ﰥ'=>1,'ﰦ'=>1,'ﰧ'=>1,'ﰨ'=>1,'ﰩ'=>1,'ﰪ'=>1,'ﰫ'=>1,'ﰬ'=>1,'ﰭ'=>1,'ﰮ'=>1,'ﰯ'=>1,'ﰰ'=>1,'ﰱ'=>1,'ﰲ'=>1,'ﰳ'=>1,'ﰴ'=>1,'ﰵ'=>1,'ﰶ'=>1,'ﰷ'=>1,'ﰸ'=>1,'ﰹ'=>1,'ﰺ'=>1,'ﰻ'=>1,'ﰼ'=>1,'ﰽ'=>1,'ﰾ'=>1,'ﰿ'=>1,'ﱀ'=>1,'ﱁ'=>1,'ﱂ'=>1,'ﱃ'=>1,'ﱄ'=>1,'ﱅ'=>1,'ﱆ'=>1,'ﱇ'=>1,'ﱈ'=>1,'ﱉ'=>1,'ﱊ'=>1,'ﱋ'=>1,'ﱌ'=>1,'ﱍ'=>1,'ﱎ'=>1,'ﱏ'=>1,'ﱐ'=>1,'ﱑ'=>1,'ﱒ'=>1,'ﱓ'=>1,'ﱔ'=>1,'ﱕ'=>1,'ﱖ'=>1,'ﱗ'=>1,'ﱘ'=>1,'ﱙ'=>1,'ﱚ'=>1,'ﱛ'=>1,'ﱜ'=>1,'ﱝ'=>1,'ﱞ'=>1,'ﱟ'=>1,'ﱠ'=>1,'ﱡ'=>1,'ﱢ'=>1,'ﱣ'=>1,'ﱤ'=>1,'ﱥ'=>1,'ﱦ'=>1,'ﱧ'=>1,'ﱨ'=>1,'ﱩ'=>1,'ﱪ'=>1,'ﱫ'=>1,'ﱬ'=>1,'ﱭ'=>1,'ﱮ'=>1,'ﱯ'=>1,'ﱰ'=>1,'ﱱ'=>1,'ﱲ'=>1,'ﱳ'=>1,'ﱴ'=>1,'ﱵ'=>1,'ﱶ'=>1,'ﱷ'=>1,'ﱸ'=>1,'ﱹ'=>1,'ﱺ'=>1,'ﱻ'=>1,'ﱼ'=>1,'ﱽ'=>1,'ﱾ'=>1,'ﱿ'=>1,'ﲀ'=>1,'ﲁ'=>1,'ﲂ'=>1,'ﲃ'=>1,'ﲄ'=>1,'ﲅ'=>1,'ﲆ'=>1,'ﲇ'=>1,'ﲈ'=>1,'ﲉ'=>1,'ﲊ'=>1,'ﲋ'=>1,'ﲌ'=>1,'ﲍ'=>1,'ﲎ'=>1,'ﲏ'=>1,'ﲐ'=>1,'ﲑ'=>1,'ﲒ'=>1,'ﲓ'=>1,'ﲔ'=>1,'ﲕ'=>1,'ﲖ'=>1,'ﲗ'=>1,'ﲘ'=>1,'ﲙ'=>1,'ﲚ'=>1,'ﲛ'=>1,'ﲜ'=>1,'ﲝ'=>1,'ﲞ'=>1,'ﲟ'=>1,'ﲠ'=>1,'ﲡ'=>1,'ﲢ'=>1,'ﲣ'=>1,'ﲤ'=>1,'ﲥ'=>1,'ﲦ'=>1,'ﲧ'=>1,'ﲨ'=>1,'ﲩ'=>1,'ﲪ'=>1,'ﲫ'=>1,'ﲬ'=>1,'ﲭ'=>1,'ﲮ'=>1,'ﲯ'=>1,'ﲰ'=>1,'ﲱ'=>1,'ﲲ'=>1,'ﲳ'=>1,'ﲴ'=>1,'ﲵ'=>1,'ﲶ'=>1,'ﲷ'=>1,'ﲸ'=>1,'ﲹ'=>1,'ﲺ'=>1,'ﲻ'=>1,'ﲼ'=>1,'ﲽ'=>1,'ﲾ'=>1,'ﲿ'=>1,'ﳀ'=>1,'ﳁ'=>1,'ﳂ'=>1,'ﳃ'=>1,'ﳄ'=>1,'ﳅ'=>1,'ﳆ'=>1,'ﳇ'=>1,'ﳈ'=>1,'ﳉ'=>1,'ﳊ'=>1,'ﳋ'=>1,'ﳌ'=>1,'ﳍ'=>1,'ﳎ'=>1,'ﳏ'=>1,'ﳐ'=>1,'ﳑ'=>1,'ﳒ'=>1,'ﳓ'=>1,'ﳔ'=>1,'ﳕ'=>1,'ﳖ'=>1,'ﳗ'=>1,'ﳘ'=>1,'ﳙ'=>1,'ﳚ'=>1,'ﳛ'=>1,'ﳜ'=>1,'ﳝ'=>1,'ﳞ'=>1,'ﳟ'=>1,'ﳠ'=>1,'ﳡ'=>1,'ﳢ'=>1,'ﳣ'=>1,'ﳤ'=>1,'ﳥ'=>1,'ﳦ'=>1,'ﳧ'=>1,'ﳨ'=>1,'ﳩ'=>1,'ﳪ'=>1,'ﳫ'=>1,'ﳬ'=>1,'ﳭ'=>1,'ﳮ'=>1,'ﳯ'=>1,'ﳰ'=>1,'ﳱ'=>1,'ﳲ'=>1,'ﳳ'=>1,'ﳴ'=>1,'ﳵ'=>1,'ﳶ'=>1,'ﳷ'=>1,'ﳸ'=>1,'ﳹ'=>1,'ﳺ'=>1,'ﳻ'=>1,'ﳼ'=>1,'ﳽ'=>1,'ﳾ'=>1,'ﳿ'=>1,'ﴀ'=>1,'ﴁ'=>1,'ﴂ'=>1,'ﴃ'=>1,'ﴄ'=>1,'ﴅ'=>1,'ﴆ'=>1,'ﴇ'=>1,'ﴈ'=>1,'ﴉ'=>1,'ﴊ'=>1,'ﴋ'=>1,'ﴌ'=>1,'ﴍ'=>1,'ﴎ'=>1,'ﴏ'=>1,'ﴐ'=>1,'ﴑ'=>1,'ﴒ'=>1,'ﴓ'=>1,'ﴔ'=>1,'ﴕ'=>1,'ﴖ'=>1,'ﴗ'=>1,'ﴘ'=>1,'ﴙ'=>1,'ﴚ'=>1,'ﴛ'=>1,'ﴜ'=>1,'ﴝ'=>1,'ﴞ'=>1,'ﴟ'=>1,'ﴠ'=>1,'ﴡ'=>1,'ﴢ'=>1,'ﴣ'=>1,'ﴤ'=>1,'ﴥ'=>1,'ﴦ'=>1,'ﴧ'=>1,'ﴨ'=>1,'ﴩ'=>1,'ﴪ'=>1,'ﴫ'=>1,'ﴬ'=>1,'ﴭ'=>1,'ﴮ'=>1,'ﴯ'=>1,'ﴰ'=>1,'ﴱ'=>1,'ﴲ'=>1,'ﴳ'=>1,'ﴴ'=>1,'ﴵ'=>1,'ﴶ'=>1,'ﴷ'=>1,'ﴸ'=>1,'ﴹ'=>1,'ﴺ'=>1,'ﴻ'=>1,'ﴼ'=>1,'ﴽ'=>1,'ﵐ'=>1,'ﵑ'=>1,'ﵒ'=>1,'ﵓ'=>1,'ﵔ'=>1,'ﵕ'=>1,'ﵖ'=>1,'ﵗ'=>1,'ﵘ'=>1,'ﵙ'=>1,'ﵚ'=>1,'ﵛ'=>1,'ﵜ'=>1,'ﵝ'=>1,'ﵞ'=>1,'ﵟ'=>1,'ﵠ'=>1,'ﵡ'=>1,'ﵢ'=>1,'ﵣ'=>1,'ﵤ'=>1,'ﵥ'=>1,'ﵦ'=>1,'ﵧ'=>1,'ﵨ'=>1,'ﵩ'=>1,'ﵪ'=>1,'ﵫ'=>1,'ﵬ'=>1,'ﵭ'=>1,'ﵮ'=>1,'ﵯ'=>1,'ﵰ'=>1,'ﵱ'=>1,'ﵲ'=>1,'ﵳ'=>1,'ﵴ'=>1,'ﵵ'=>1,'ﵶ'=>1,'ﵷ'=>1,'ﵸ'=>1,'ﵹ'=>1,'ﵺ'=>1,'ﵻ'=>1,'ﵼ'=>1,'ﵽ'=>1,'ﵾ'=>1,'ﵿ'=>1,'ﶀ'=>1,'ﶁ'=>1,'ﶂ'=>1,'ﶃ'=>1,'ﶄ'=>1,'ﶅ'=>1,'ﶆ'=>1,'ﶇ'=>1,'ﶈ'=>1,'ﶉ'=>1,'ﶊ'=>1,'ﶋ'=>1,'ﶌ'=>1,'ﶍ'=>1,'ﶎ'=>1,'ﶏ'=>1,'ﶒ'=>1,'ﶓ'=>1,'ﶔ'=>1,'ﶕ'=>1,'ﶖ'=>1,'ﶗ'=>1,'ﶘ'=>1,'ﶙ'=>1,'ﶚ'=>1,'ﶛ'=>1,'ﶜ'=>1,'ﶝ'=>1,'ﶞ'=>1,'ﶟ'=>1,'ﶠ'=>1,'ﶡ'=>1,'ﶢ'=>1,'ﶣ'=>1,'ﶤ'=>1,'ﶥ'=>1,'ﶦ'=>1,'ﶧ'=>1,'ﶨ'=>1,'ﶩ'=>1,'ﶪ'=>1,'ﶫ'=>1,'ﶬ'=>1,'ﶭ'=>1,'ﶮ'=>1,'ﶯ'=>1,'ﶰ'=>1,'ﶱ'=>1,'ﶲ'=>1,'ﶳ'=>1,'ﶴ'=>1,'ﶵ'=>1,'ﶶ'=>1,'ﶷ'=>1,'ﶸ'=>1,'ﶹ'=>1,'ﶺ'=>1,'ﶻ'=>1,'ﶼ'=>1,'ﶽ'=>1,'ﶾ'=>1,'ﶿ'=>1,'ﷀ'=>1,'ﷁ'=>1,'ﷂ'=>1,'ﷃ'=>1,'ﷄ'=>1,'ﷅ'=>1,'ﷆ'=>1,'ﷇ'=>1,'ﷰ'=>1,'ﷱ'=>1,'ﷲ'=>1,'ﷳ'=>1,'ﷴ'=>1,'ﷵ'=>1,'ﷶ'=>1,'ﷷ'=>1,'ﷸ'=>1,'ﷹ'=>1,'ﷺ'=>1,'ﷻ'=>1,'﷼'=>1,'︐'=>1,'︑'=>1,'︒'=>1,'︓'=>1,'︔'=>1,'︕'=>1,'︖'=>1,'︗'=>1,'︘'=>1,'︙'=>1,'︰'=>1,'︱'=>1,'︲'=>1,'︳'=>1,'︴'=>1,'︵'=>1,'︶'=>1,'︷'=>1,'︸'=>1,'︹'=>1,'︺'=>1,'︻'=>1,'︼'=>1,'︽'=>1,'︾'=>1,'︿'=>1,'﹀'=>1,'﹁'=>1,'﹂'=>1,'﹃'=>1,'﹄'=>1,'﹇'=>1,'﹈'=>1,'﹉'=>1,'﹊'=>1,'﹋'=>1,'﹌'=>1,'﹍'=>1,'﹎'=>1,'﹏'=>1,'﹐'=>1,'﹑'=>1,'﹒'=>1,'﹔'=>1,'﹕'=>1,'﹖'=>1,'﹗'=>1,'﹘'=>1,'﹙'=>1,'﹚'=>1,'﹛'=>1,'﹜'=>1,'﹝'=>1,'﹞'=>1,'﹟'=>1,'﹠'=>1,'﹡'=>1,'﹢'=>1,'﹣'=>1,'﹤'=>1,'﹥'=>1,'﹦'=>1,'﹨'=>1,'﹩'=>1,'﹪'=>1,'﹫'=>1,'ﹰ'=>1,'ﹱ'=>1,'ﹲ'=>1,'ﹴ'=>1,'ﹶ'=>1,'ﹷ'=>1,'ﹸ'=>1,'ﹹ'=>1,'ﹺ'=>1,'ﹻ'=>1,'ﹼ'=>1,'ﹽ'=>1,'ﹾ'=>1,'ﹿ'=>1,'ﺀ'=>1,'ﺁ'=>1,'ﺂ'=>1,'ﺃ'=>1,'ﺄ'=>1,'ﺅ'=>1,'ﺆ'=>1,'ﺇ'=>1,'ﺈ'=>1,'ﺉ'=>1,'ﺊ'=>1,'ﺋ'=>1,'ﺌ'=>1,'ﺍ'=>1,'ﺎ'=>1,'ﺏ'=>1,'ﺐ'=>1,'ﺑ'=>1,'ﺒ'=>1,'ﺓ'=>1,'ﺔ'=>1,'ﺕ'=>1,'ﺖ'=>1,'ﺗ'=>1,'ﺘ'=>1,'ﺙ'=>1,'ﺚ'=>1,'ﺛ'=>1,'ﺜ'=>1,'ﺝ'=>1,'ﺞ'=>1,'ﺟ'=>1,'ﺠ'=>1,'ﺡ'=>1,'ﺢ'=>1,'ﺣ'=>1,'ﺤ'=>1,'ﺥ'=>1,'ﺦ'=>1,'ﺧ'=>1,'ﺨ'=>1,'ﺩ'=>1,'ﺪ'=>1,'ﺫ'=>1,'ﺬ'=>1,'ﺭ'=>1,'ﺮ'=>1,'ﺯ'=>1,'ﺰ'=>1,'ﺱ'=>1,'ﺲ'=>1,'ﺳ'=>1,'ﺴ'=>1,'ﺵ'=>1,'ﺶ'=>1,'ﺷ'=>1,'ﺸ'=>1,'ﺹ'=>1,'ﺺ'=>1,'ﺻ'=>1,'ﺼ'=>1,'ﺽ'=>1,'ﺾ'=>1,'ﺿ'=>1,'ﻀ'=>1,'ﻁ'=>1,'ﻂ'=>1,'ﻃ'=>1,'ﻄ'=>1,'ﻅ'=>1,'ﻆ'=>1,'ﻇ'=>1,'ﻈ'=>1,'ﻉ'=>1,'ﻊ'=>1,'ﻋ'=>1,'ﻌ'=>1,'ﻍ'=>1,'ﻎ'=>1,'ﻏ'=>1,'ﻐ'=>1,'ﻑ'=>1,'ﻒ'=>1,'ﻓ'=>1,'ﻔ'=>1,'ﻕ'=>1,'ﻖ'=>1,'ﻗ'=>1,'ﻘ'=>1,'ﻙ'=>1,'ﻚ'=>1,'ﻛ'=>1,'ﻜ'=>1,'ﻝ'=>1,'ﻞ'=>1,'ﻟ'=>1,'ﻠ'=>1,'ﻡ'=>1,'ﻢ'=>1,'ﻣ'=>1,'ﻤ'=>1,'ﻥ'=>1,'ﻦ'=>1,'ﻧ'=>1,'ﻨ'=>1,'ﻩ'=>1,'ﻪ'=>1,'ﻫ'=>1,'ﻬ'=>1,'ﻭ'=>1,'ﻮ'=>1,'ﻯ'=>1,'ﻰ'=>1,'ﻱ'=>1,'ﻲ'=>1,'ﻳ'=>1,'ﻴ'=>1,'ﻵ'=>1,'ﻶ'=>1,'ﻷ'=>1,'ﻸ'=>1,'ﻹ'=>1,'ﻺ'=>1,'ﻻ'=>1,'ﻼ'=>1,'!'=>1,'"'=>1,'#'=>1,'$'=>1,'%'=>1,'&'=>1,'''=>1,'('=>1,')'=>1,'*'=>1,'+'=>1,','=>1,'-'=>1,'.'=>1,'/'=>1,'0'=>1,'1'=>1,'2'=>1,'3'=>1,'4'=>1,'5'=>1,'6'=>1,'7'=>1,'8'=>1,'9'=>1,':'=>1,';'=>1,'<'=>1,'='=>1,'>'=>1,'?'=>1,'@'=>1,'A'=>1,'B'=>1,'C'=>1,'D'=>1,'E'=>1,'F'=>1,'G'=>1,'H'=>1,'I'=>1,'J'=>1,'K'=>1,'L'=>1,'M'=>1,'N'=>1,'O'=>1,'P'=>1,'Q'=>1,'R'=>1,'S'=>1,'T'=>1,'U'=>1,'V'=>1,'W'=>1,'X'=>1,'Y'=>1,'Z'=>1,'['=>1,'\'=>1,']'=>1,'^'=>1,'_'=>1,'`'=>1,'a'=>1,'b'=>1,'c'=>1,'d'=>1,'e'=>1,'f'=>1,'g'=>1,'h'=>1,'i'=>1,'j'=>1,'k'=>1,'l'=>1,'m'=>1,'n'=>1,'o'=>1,'p'=>1,'q'=>1,'r'=>1,'s'=>1,'t'=>1,'u'=>1,'v'=>1,'w'=>1,'x'=>1,'y'=>1,'z'=>1,'{'=>1,'|'=>1,'}'=>1,'~'=>1,'⦅'=>1,'⦆'=>1,'。'=>1,'「'=>1,'」'=>1,'、'=>1,'・'=>1,'ヲ'=>1,'ァ'=>1,'ィ'=>1,'ゥ'=>1,'ェ'=>1,'ォ'=>1,'ャ'=>1,'ュ'=>1,'ョ'=>1,'ッ'=>1,'ー'=>1,'ア'=>1,'イ'=>1,'ウ'=>1,'エ'=>1,'オ'=>1,'カ'=>1,'キ'=>1,'ク'=>1,'ケ'=>1,'コ'=>1,'サ'=>1,'シ'=>1,'ス'=>1,'セ'=>1,'ソ'=>1,'タ'=>1,'チ'=>1,'ツ'=>1,'テ'=>1,'ト'=>1,'ナ'=>1,'ニ'=>1,'ヌ'=>1,'ネ'=>1,'ノ'=>1,'ハ'=>1,'ヒ'=>1,'フ'=>1,'ヘ'=>1,'ホ'=>1,'マ'=>1,'ミ'=>1,'ム'=>1,'メ'=>1,'モ'=>1,'ヤ'=>1,'ユ'=>1,'ヨ'=>1,'ラ'=>1,'リ'=>1,'ル'=>1,'レ'=>1,'ロ'=>1,'ワ'=>1,'ン'=>1,'゙'=>1,'゚'=>1,'ᅠ'=>1,'ᄀ'=>1,'ᄁ'=>1,'ᆪ'=>1,'ᄂ'=>1,'ᆬ'=>1,'ᆭ'=>1,'ᄃ'=>1,'ᄄ'=>1,'ᄅ'=>1,'ᆰ'=>1,'ᆱ'=>1,'ᆲ'=>1,'ᆳ'=>1,'ᆴ'=>1,'ᆵ'=>1,'ᄚ'=>1,'ᄆ'=>1,'ᄇ'=>1,'ᄈ'=>1,'ᄡ'=>1,'ᄉ'=>1,'ᄊ'=>1,'ᄋ'=>1,'ᄌ'=>1,'ᄍ'=>1,'ᄎ'=>1,'ᄏ'=>1,'ᄐ'=>1,'ᄑ'=>1,'ᄒ'=>1,'ᅡ'=>1,'ᅢ'=>1,'ᅣ'=>1,'ᅤ'=>1,'ᅥ'=>1,'ᅦ'=>1,'ᅧ'=>1,'ᅨ'=>1,'ᅩ'=>1,'ᅪ'=>1,'ᅫ'=>1,'ᅬ'=>1,'ᅭ'=>1,'ᅮ'=>1,'ᅯ'=>1,'ᅰ'=>1,'ᅱ'=>1,'ᅲ'=>1,'ᅳ'=>1,'ᅴ'=>1,'ᅵ'=>1,'¢'=>1,'£'=>1,'¬'=>1,' ̄'=>1,'¦'=>1,'¥'=>1,'₩'=>1,'│'=>1,'←'=>1,'↑'=>1,'→'=>1,'↓'=>1,'■'=>1,'○'=>1,'𝅗𝅥'=>1,'𝅘𝅥'=>1,'𝅘𝅥𝅮'=>1,'𝅘𝅥𝅯'=>1,'𝅘𝅥𝅰'=>1,'𝅘𝅥𝅱'=>1,'𝅘𝅥𝅲'=>1,'𝆹𝅥'=>1,'𝆺𝅥'=>1,'𝆹𝅥𝅮'=>1,'𝆺𝅥𝅮'=>1,'𝆹𝅥𝅯'=>1,'𝆺𝅥𝅯'=>1,'𝐀'=>1,'𝐁'=>1,'𝐂'=>1,'𝐃'=>1,'𝐄'=>1,'𝐅'=>1,'𝐆'=>1,'𝐇'=>1,'𝐈'=>1,'𝐉'=>1,'𝐊'=>1,'𝐋'=>1,'𝐌'=>1,'𝐍'=>1,'𝐎'=>1,'𝐏'=>1,'𝐐'=>1,'𝐑'=>1,'𝐒'=>1,'𝐓'=>1,'𝐔'=>1,'𝐕'=>1,'𝐖'=>1,'𝐗'=>1,'𝐘'=>1,'𝐙'=>1,'𝐚'=>1,'𝐛'=>1,'𝐜'=>1,'𝐝'=>1,'𝐞'=>1,'𝐟'=>1,'𝐠'=>1,'𝐡'=>1,'𝐢'=>1,'𝐣'=>1,'𝐤'=>1,'𝐥'=>1,'𝐦'=>1,'𝐧'=>1,'𝐨'=>1,'𝐩'=>1,'𝐪'=>1,'𝐫'=>1,'𝐬'=>1,'𝐭'=>1,'𝐮'=>1,'𝐯'=>1,'𝐰'=>1,'𝐱'=>1,'𝐲'=>1,'𝐳'=>1,'𝐴'=>1,'𝐵'=>1,'𝐶'=>1,'𝐷'=>1,'𝐸'=>1,'𝐹'=>1,'𝐺'=>1,'𝐻'=>1,'𝐼'=>1,'𝐽'=>1,'𝐾'=>1,'𝐿'=>1,'𝑀'=>1,'𝑁'=>1,'𝑂'=>1,'𝑃'=>1,'𝑄'=>1,'𝑅'=>1,'𝑆'=>1,'𝑇'=>1,'𝑈'=>1,'𝑉'=>1,'𝑊'=>1,'𝑋'=>1,'𝑌'=>1,'𝑍'=>1,'𝑎'=>1,'𝑏'=>1,'𝑐'=>1,'𝑑'=>1,'𝑒'=>1,'𝑓'=>1,'𝑔'=>1,'𝑖'=>1,'𝑗'=>1,'𝑘'=>1,'𝑙'=>1,'𝑚'=>1,'𝑛'=>1,'𝑜'=>1,'𝑝'=>1,'𝑞'=>1,'𝑟'=>1,'𝑠'=>1,'𝑡'=>1,'𝑢'=>1,'𝑣'=>1,'𝑤'=>1,'𝑥'=>1,'𝑦'=>1,'𝑧'=>1,'𝑨'=>1,'𝑩'=>1,'𝑪'=>1,'𝑫'=>1,'𝑬'=>1,'𝑭'=>1,'𝑮'=>1,'𝑯'=>1,'𝑰'=>1,'𝑱'=>1,'𝑲'=>1,'𝑳'=>1,'𝑴'=>1,'𝑵'=>1,'𝑶'=>1,'𝑷'=>1,'𝑸'=>1,'𝑹'=>1,'𝑺'=>1,'𝑻'=>1,'𝑼'=>1,'𝑽'=>1,'𝑾'=>1,'𝑿'=>1,'𝒀'=>1,'𝒁'=>1,'𝒂'=>1,'𝒃'=>1,'𝒄'=>1,'𝒅'=>1,'𝒆'=>1,'𝒇'=>1,'𝒈'=>1,'𝒉'=>1,'𝒊'=>1,'𝒋'=>1,'𝒌'=>1,'𝒍'=>1,'𝒎'=>1,'𝒏'=>1,'𝒐'=>1,'𝒑'=>1,'𝒒'=>1,'𝒓'=>1,'𝒔'=>1,'𝒕'=>1,'𝒖'=>1,'𝒗'=>1,'𝒘'=>1,'𝒙'=>1,'𝒚'=>1,'𝒛'=>1,'𝒜'=>1,'𝒞'=>1,'𝒟'=>1,'𝒢'=>1,'𝒥'=>1,'𝒦'=>1,'𝒩'=>1,'𝒪'=>1,'𝒫'=>1,'𝒬'=>1,'𝒮'=>1,'𝒯'=>1,'𝒰'=>1,'𝒱'=>1,'𝒲'=>1,'𝒳'=>1,'𝒴'=>1,'𝒵'=>1,'𝒶'=>1,'𝒷'=>1,'𝒸'=>1,'𝒹'=>1,'𝒻'=>1,'𝒽'=>1,'𝒾'=>1,'𝒿'=>1,'𝓀'=>1,'𝓁'=>1,'𝓂'=>1,'𝓃'=>1,'𝓅'=>1,'𝓆'=>1,'𝓇'=>1,'𝓈'=>1,'𝓉'=>1,'𝓊'=>1,'𝓋'=>1,'𝓌'=>1,'𝓍'=>1,'𝓎'=>1,'𝓏'=>1,'𝓐'=>1,'𝓑'=>1,'𝓒'=>1,'𝓓'=>1,'𝓔'=>1,'𝓕'=>1,'𝓖'=>1,'𝓗'=>1,'𝓘'=>1,'𝓙'=>1,'𝓚'=>1,'𝓛'=>1,'𝓜'=>1,'𝓝'=>1,'𝓞'=>1,'𝓟'=>1,'𝓠'=>1,'𝓡'=>1,'𝓢'=>1,'𝓣'=>1,'𝓤'=>1,'𝓥'=>1,'𝓦'=>1,'𝓧'=>1,'𝓨'=>1,'𝓩'=>1,'𝓪'=>1,'𝓫'=>1,'𝓬'=>1,'𝓭'=>1,'𝓮'=>1,'𝓯'=>1,'𝓰'=>1,'𝓱'=>1,'𝓲'=>1,'𝓳'=>1,'𝓴'=>1,'𝓵'=>1,'𝓶'=>1,'𝓷'=>1,'𝓸'=>1,'𝓹'=>1,'𝓺'=>1,'𝓻'=>1,'𝓼'=>1,'𝓽'=>1,'𝓾'=>1,'𝓿'=>1,'𝔀'=>1,'𝔁'=>1,'𝔂'=>1,'𝔃'=>1,'𝔄'=>1,'𝔅'=>1,'𝔇'=>1,'𝔈'=>1,'𝔉'=>1,'𝔊'=>1,'𝔍'=>1,'𝔎'=>1,'𝔏'=>1,'𝔐'=>1,'𝔑'=>1,'𝔒'=>1,'𝔓'=>1,'𝔔'=>1,'𝔖'=>1,'𝔗'=>1,'𝔘'=>1,'𝔙'=>1,'𝔚'=>1,'𝔛'=>1,'𝔜'=>1,'𝔞'=>1,'𝔟'=>1,'𝔠'=>1,'𝔡'=>1,'𝔢'=>1,'𝔣'=>1,'𝔤'=>1,'𝔥'=>1,'𝔦'=>1,'𝔧'=>1,'𝔨'=>1,'𝔩'=>1,'𝔪'=>1,'𝔫'=>1,'𝔬'=>1,'𝔭'=>1,'𝔮'=>1,'𝔯'=>1,'𝔰'=>1,'𝔱'=>1,'𝔲'=>1,'𝔳'=>1,'𝔴'=>1,'𝔵'=>1,'𝔶'=>1,'𝔷'=>1,'𝔸'=>1,'𝔹'=>1,'𝔻'=>1,'𝔼'=>1,'𝔽'=>1,'𝔾'=>1,'𝕀'=>1,'𝕁'=>1,'𝕂'=>1,'𝕃'=>1,'𝕄'=>1,'𝕆'=>1,'𝕊'=>1,'𝕋'=>1,'𝕌'=>1,'𝕍'=>1,'𝕎'=>1,'𝕏'=>1,'𝕐'=>1,'𝕒'=>1,'𝕓'=>1,'𝕔'=>1,'𝕕'=>1,'𝕖'=>1,'𝕗'=>1,'𝕘'=>1,'𝕙'=>1,'𝕚'=>1,'𝕛'=>1,'𝕜'=>1,'𝕝'=>1,'𝕞'=>1,'𝕟'=>1,'𝕠'=>1,'𝕡'=>1,'𝕢'=>1,'𝕣'=>1,'𝕤'=>1,'𝕥'=>1,'𝕦'=>1,'𝕧'=>1,'𝕨'=>1,'𝕩'=>1,'𝕪'=>1,'𝕫'=>1,'𝕬'=>1,'𝕭'=>1,'𝕮'=>1,'𝕯'=>1,'𝕰'=>1,'𝕱'=>1,'𝕲'=>1,'𝕳'=>1,'𝕴'=>1,'𝕵'=>1,'𝕶'=>1,'𝕷'=>1,'𝕸'=>1,'𝕹'=>1,'𝕺'=>1,'𝕻'=>1,'𝕼'=>1,'𝕽'=>1,'𝕾'=>1,'𝕿'=>1,'𝖀'=>1,'𝖁'=>1,'𝖂'=>1,'𝖃'=>1,'𝖄'=>1,'𝖅'=>1,'𝖆'=>1,'𝖇'=>1,'𝖈'=>1,'𝖉'=>1,'𝖊'=>1,'𝖋'=>1,'𝖌'=>1,'𝖍'=>1,'𝖎'=>1,'𝖏'=>1,'𝖐'=>1,'𝖑'=>1,'𝖒'=>1,'𝖓'=>1,'𝖔'=>1,'𝖕'=>1,'𝖖'=>1,'𝖗'=>1,'𝖘'=>1,'𝖙'=>1,'𝖚'=>1,'𝖛'=>1,'𝖜'=>1,'𝖝'=>1,'𝖞'=>1,'𝖟'=>1,'𝖠'=>1,'𝖡'=>1,'𝖢'=>1,'𝖣'=>1,'𝖤'=>1,'𝖥'=>1,'𝖦'=>1,'𝖧'=>1,'𝖨'=>1,'𝖩'=>1,'𝖪'=>1,'𝖫'=>1,'𝖬'=>1,'𝖭'=>1,'𝖮'=>1,'𝖯'=>1,'𝖰'=>1,'𝖱'=>1,'𝖲'=>1,'𝖳'=>1,'𝖴'=>1,'𝖵'=>1,'𝖶'=>1,'𝖷'=>1,'𝖸'=>1,'𝖹'=>1,'𝖺'=>1,'𝖻'=>1,'𝖼'=>1,'𝖽'=>1,'𝖾'=>1,'𝖿'=>1,'𝗀'=>1,'𝗁'=>1,'𝗂'=>1,'𝗃'=>1,'𝗄'=>1,'𝗅'=>1,'𝗆'=>1,'𝗇'=>1,'𝗈'=>1,'𝗉'=>1,'𝗊'=>1,'𝗋'=>1,'𝗌'=>1,'𝗍'=>1,'𝗎'=>1,'𝗏'=>1,'𝗐'=>1,'𝗑'=>1,'𝗒'=>1,'𝗓'=>1,'𝗔'=>1,'𝗕'=>1,'𝗖'=>1,'𝗗'=>1,'𝗘'=>1,'𝗙'=>1,'𝗚'=>1,'𝗛'=>1,'𝗜'=>1,'𝗝'=>1,'𝗞'=>1,'𝗟'=>1,'𝗠'=>1,'𝗡'=>1,'𝗢'=>1,'𝗣'=>1,'𝗤'=>1,'𝗥'=>1,'𝗦'=>1,'𝗧'=>1,'𝗨'=>1,'𝗩'=>1,'𝗪'=>1,'𝗫'=>1,'𝗬'=>1,'𝗭'=>1,'𝗮'=>1,'𝗯'=>1,'𝗰'=>1,'𝗱'=>1,'𝗲'=>1,'𝗳'=>1,'𝗴'=>1,'𝗵'=>1,'𝗶'=>1,'𝗷'=>1,'𝗸'=>1,'𝗹'=>1,'𝗺'=>1,'𝗻'=>1,'𝗼'=>1,'𝗽'=>1,'𝗾'=>1,'𝗿'=>1,'𝘀'=>1,'𝘁'=>1,'𝘂'=>1,'𝘃'=>1,'𝘄'=>1,'𝘅'=>1,'𝘆'=>1,'𝘇'=>1,'𝘈'=>1,'𝘉'=>1,'𝘊'=>1,'𝘋'=>1,'𝘌'=>1,'𝘍'=>1,'𝘎'=>1,'𝘏'=>1,'𝘐'=>1,'𝘑'=>1,'𝘒'=>1,'𝘓'=>1,'𝘔'=>1,'𝘕'=>1,'𝘖'=>1,'𝘗'=>1,'𝘘'=>1,'𝘙'=>1,'𝘚'=>1,'𝘛'=>1,'𝘜'=>1,'𝘝'=>1,'𝘞'=>1,'𝘟'=>1,'𝘠'=>1,'𝘡'=>1,'𝘢'=>1,'𝘣'=>1,'𝘤'=>1,'𝘥'=>1,'𝘦'=>1,'𝘧'=>1,'𝘨'=>1,'𝘩'=>1,'𝘪'=>1,'𝘫'=>1,'𝘬'=>1,'𝘭'=>1,'𝘮'=>1,'𝘯'=>1,'𝘰'=>1,'𝘱'=>1,'𝘲'=>1,'𝘳'=>1,'𝘴'=>1,'𝘵'=>1,'𝘶'=>1,'𝘷'=>1,'𝘸'=>1,'𝘹'=>1,'𝘺'=>1,'𝘻'=>1,'𝘼'=>1,'𝘽'=>1,'𝘾'=>1,'𝘿'=>1,'𝙀'=>1,'𝙁'=>1,'𝙂'=>1,'𝙃'=>1,'𝙄'=>1,'𝙅'=>1,'𝙆'=>1,'𝙇'=>1,'𝙈'=>1,'𝙉'=>1,'𝙊'=>1,'𝙋'=>1,'𝙌'=>1,'𝙍'=>1,'𝙎'=>1,'𝙏'=>1,'𝙐'=>1,'𝙑'=>1,'𝙒'=>1,'𝙓'=>1,'𝙔'=>1,'𝙕'=>1,'𝙖'=>1,'𝙗'=>1,'𝙘'=>1,'𝙙'=>1,'𝙚'=>1,'𝙛'=>1,'𝙜'=>1,'𝙝'=>1,'𝙞'=>1,'𝙟'=>1,'𝙠'=>1,'𝙡'=>1,'𝙢'=>1,'𝙣'=>1,'𝙤'=>1,'𝙥'=>1,'𝙦'=>1,'𝙧'=>1,'𝙨'=>1,'𝙩'=>1,'𝙪'=>1,'𝙫'=>1,'𝙬'=>1,'𝙭'=>1,'𝙮'=>1,'𝙯'=>1,'𝙰'=>1,'𝙱'=>1,'𝙲'=>1,'𝙳'=>1,'𝙴'=>1,'𝙵'=>1,'𝙶'=>1,'𝙷'=>1,'𝙸'=>1,'𝙹'=>1,'𝙺'=>1,'𝙻'=>1,'𝙼'=>1,'𝙽'=>1,'𝙾'=>1,'𝙿'=>1,'𝚀'=>1,'𝚁'=>1,'𝚂'=>1,'𝚃'=>1,'𝚄'=>1,'𝚅'=>1,'𝚆'=>1,'𝚇'=>1,'𝚈'=>1,'𝚉'=>1,'𝚊'=>1,'𝚋'=>1,'𝚌'=>1,'𝚍'=>1,'𝚎'=>1,'𝚏'=>1,'𝚐'=>1,'𝚑'=>1,'𝚒'=>1,'𝚓'=>1,'𝚔'=>1,'𝚕'=>1,'𝚖'=>1,'𝚗'=>1,'𝚘'=>1,'𝚙'=>1,'𝚚'=>1,'𝚛'=>1,'𝚜'=>1,'𝚝'=>1,'𝚞'=>1,'𝚟'=>1,'𝚠'=>1,'𝚡'=>1,'𝚢'=>1,'𝚣'=>1,'𝚤'=>1,'𝚥'=>1,'𝚨'=>1,'𝚩'=>1,'𝚪'=>1,'𝚫'=>1,'𝚬'=>1,'𝚭'=>1,'𝚮'=>1,'𝚯'=>1,'𝚰'=>1,'𝚱'=>1,'𝚲'=>1,'𝚳'=>1,'𝚴'=>1,'𝚵'=>1,'𝚶'=>1,'𝚷'=>1,'𝚸'=>1,'𝚹'=>1,'𝚺'=>1,'𝚻'=>1,'𝚼'=>1,'𝚽'=>1,'𝚾'=>1,'𝚿'=>1,'𝛀'=>1,'𝛁'=>1,'𝛂'=>1,'𝛃'=>1,'𝛄'=>1,'𝛅'=>1,'𝛆'=>1,'𝛇'=>1,'𝛈'=>1,'𝛉'=>1,'𝛊'=>1,'𝛋'=>1,'𝛌'=>1,'𝛍'=>1,'𝛎'=>1,'𝛏'=>1,'𝛐'=>1,'𝛑'=>1,'𝛒'=>1,'𝛓'=>1,'𝛔'=>1,'𝛕'=>1,'𝛖'=>1,'𝛗'=>1,'𝛘'=>1,'𝛙'=>1,'𝛚'=>1,'𝛛'=>1,'𝛜'=>1,'𝛝'=>1,'𝛞'=>1,'𝛟'=>1,'𝛠'=>1,'𝛡'=>1,'𝛢'=>1,'𝛣'=>1,'𝛤'=>1,'𝛥'=>1,'𝛦'=>1,'𝛧'=>1,'𝛨'=>1,'𝛩'=>1,'𝛪'=>1,'𝛫'=>1,'𝛬'=>1,'𝛭'=>1,'𝛮'=>1,'𝛯'=>1,'𝛰'=>1,'𝛱'=>1,'𝛲'=>1,'𝛳'=>1,'𝛴'=>1,'𝛵'=>1,'𝛶'=>1,'𝛷'=>1,'𝛸'=>1,'𝛹'=>1,'𝛺'=>1,'𝛻'=>1,'𝛼'=>1,'𝛽'=>1,'𝛾'=>1,'𝛿'=>1,'𝜀'=>1,'𝜁'=>1,'𝜂'=>1,'𝜃'=>1,'𝜄'=>1,'𝜅'=>1,'𝜆'=>1,'𝜇'=>1,'𝜈'=>1,'𝜉'=>1,'𝜊'=>1,'𝜋'=>1,'𝜌'=>1,'𝜍'=>1,'𝜎'=>1,'𝜏'=>1,'𝜐'=>1,'𝜑'=>1,'𝜒'=>1,'𝜓'=>1,'𝜔'=>1,'𝜕'=>1,'𝜖'=>1,'𝜗'=>1,'𝜘'=>1,'𝜙'=>1,'𝜚'=>1,'𝜛'=>1,'𝜜'=>1,'𝜝'=>1,'𝜞'=>1,'𝜟'=>1,'𝜠'=>1,'𝜡'=>1,'𝜢'=>1,'𝜣'=>1,'𝜤'=>1,'𝜥'=>1,'𝜦'=>1,'𝜧'=>1,'𝜨'=>1,'𝜩'=>1,'𝜪'=>1,'𝜫'=>1,'𝜬'=>1,'𝜭'=>1,'𝜮'=>1,'𝜯'=>1,'𝜰'=>1,'𝜱'=>1,'𝜲'=>1,'𝜳'=>1,'𝜴'=>1,'𝜵'=>1,'𝜶'=>1,'𝜷'=>1,'𝜸'=>1,'𝜹'=>1,'𝜺'=>1,'𝜻'=>1,'𝜼'=>1,'𝜽'=>1,'𝜾'=>1,'𝜿'=>1,'𝝀'=>1,'𝝁'=>1,'𝝂'=>1,'𝝃'=>1,'𝝄'=>1,'𝝅'=>1,'𝝆'=>1,'𝝇'=>1,'𝝈'=>1,'𝝉'=>1,'𝝊'=>1,'𝝋'=>1,'𝝌'=>1,'𝝍'=>1,'𝝎'=>1,'𝝏'=>1,'𝝐'=>1,'𝝑'=>1,'𝝒'=>1,'𝝓'=>1,'𝝔'=>1,'𝝕'=>1,'𝝖'=>1,'𝝗'=>1,'𝝘'=>1,'𝝙'=>1,'𝝚'=>1,'𝝛'=>1,'𝝜'=>1,'𝝝'=>1,'𝝞'=>1,'𝝟'=>1,'𝝠'=>1,'𝝡'=>1,'𝝢'=>1,'𝝣'=>1,'𝝤'=>1,'𝝥'=>1,'𝝦'=>1,'𝝧'=>1,'𝝨'=>1,'𝝩'=>1,'𝝪'=>1,'𝝫'=>1,'𝝬'=>1,'𝝭'=>1,'𝝮'=>1,'𝝯'=>1,'𝝰'=>1,'𝝱'=>1,'𝝲'=>1,'𝝳'=>1,'𝝴'=>1,'𝝵'=>1,'𝝶'=>1,'𝝷'=>1,'𝝸'=>1,'𝝹'=>1,'𝝺'=>1,'𝝻'=>1,'𝝼'=>1,'𝝽'=>1,'𝝾'=>1,'𝝿'=>1,'𝞀'=>1,'𝞁'=>1,'𝞂'=>1,'𝞃'=>1,'𝞄'=>1,'𝞅'=>1,'𝞆'=>1,'𝞇'=>1,'𝞈'=>1,'𝞉'=>1,'𝞊'=>1,'𝞋'=>1,'𝞌'=>1,'𝞍'=>1,'𝞎'=>1,'𝞏'=>1,'𝞐'=>1,'𝞑'=>1,'𝞒'=>1,'𝞓'=>1,'𝞔'=>1,'𝞕'=>1,'𝞖'=>1,'𝞗'=>1,'𝞘'=>1,'𝞙'=>1,'𝞚'=>1,'𝞛'=>1,'𝞜'=>1,'𝞝'=>1,'𝞞'=>1,'𝞟'=>1,'𝞠'=>1,'𝞡'=>1,'𝞢'=>1,'𝞣'=>1,'𝞤'=>1,'𝞥'=>1,'𝞦'=>1,'𝞧'=>1,'𝞨'=>1,'𝞩'=>1,'𝞪'=>1,'𝞫'=>1,'𝞬'=>1,'𝞭'=>1,'𝞮'=>1,'𝞯'=>1,'𝞰'=>1,'𝞱'=>1,'𝞲'=>1,'𝞳'=>1,'𝞴'=>1,'𝞵'=>1,'𝞶'=>1,'𝞷'=>1,'𝞸'=>1,'𝞹'=>1,'𝞺'=>1,'𝞻'=>1,'𝞼'=>1,'𝞽'=>1,'𝞾'=>1,'𝞿'=>1,'𝟀'=>1,'𝟁'=>1,'𝟂'=>1,'𝟃'=>1,'𝟄'=>1,'𝟅'=>1,'𝟆'=>1,'𝟇'=>1,'𝟈'=>1,'𝟉'=>1,'𝟊'=>1,'𝟋'=>1,'𝟎'=>1,'𝟏'=>1,'𝟐'=>1,'𝟑'=>1,'𝟒'=>1,'𝟓'=>1,'𝟔'=>1,'𝟕'=>1,'𝟖'=>1,'𝟗'=>1,'𝟘'=>1,'𝟙'=>1,'𝟚'=>1,'𝟛'=>1,'𝟜'=>1,'𝟝'=>1,'𝟞'=>1,'𝟟'=>1,'𝟠'=>1,'𝟡'=>1,'𝟢'=>1,'𝟣'=>1,'𝟤'=>1,'𝟥'=>1,'𝟦'=>1,'𝟧'=>1,'𝟨'=>1,'𝟩'=>1,'𝟪'=>1,'𝟫'=>1,'𝟬'=>1,'𝟭'=>1,'𝟮'=>1,'𝟯'=>1,'𝟰'=>1,'𝟱'=>1,'𝟲'=>1,'𝟳'=>1,'𝟴'=>1,'𝟵'=>1,'𝟶'=>1,'𝟷'=>1,'𝟸'=>1,'𝟹'=>1,'𝟺'=>1,'𝟻'=>1,'𝟼'=>1,'𝟽'=>1,'𝟾'=>1,'𝟿'=>1,'丽'=>1,'丸'=>1,'乁'=>1,'𠄢'=>1,'你'=>1,'侮'=>1,'侻'=>1,'倂'=>1,'偺'=>1,'備'=>1,'僧'=>1,'像'=>1,'㒞'=>1,'𠘺'=>1,'免'=>1,'兔'=>1,'兤'=>1,'具'=>1,'𠔜'=>1,'㒹'=>1,'內'=>1,'再'=>1,'𠕋'=>1,'冗'=>1,'冤'=>1,'仌'=>1,'冬'=>1,'况'=>1,'𩇟'=>1,'凵'=>1,'刃'=>1,'㓟'=>1,'刻'=>1,'剆'=>1,'割'=>1,'剷'=>1,'㔕'=>1,'勇'=>1,'勉'=>1,'勤'=>1,'勺'=>1,'包'=>1,'匆'=>1,'北'=>1,'卉'=>1,'卑'=>1,'博'=>1,'即'=>1,'卽'=>1,'卿'=>1,'卿'=>1,'卿'=>1,'𠨬'=>1,'灰'=>1,'及'=>1,'叟'=>1,'𠭣'=>1,'叫'=>1,'叱'=>1,'吆'=>1,'咞'=>1,'吸'=>1,'呈'=>1,'周'=>1,'咢'=>1,'哶'=>1,'唐'=>1,'啓'=>1,'啣'=>1,'善'=>1,'善'=>1,'喙'=>1,'喫'=>1,'喳'=>1,'嗂'=>1,'圖'=>1,'嘆'=>1,'圗'=>1,'噑'=>1,'噴'=>1,'切'=>1,'壮'=>1,'城'=>1,'埴'=>1,'堍'=>1,'型'=>1,'堲'=>1,'報'=>1,'墬'=>1,'𡓤'=>1,'売'=>1,'壷'=>1,'夆'=>1,'多'=>1,'夢'=>1,'奢'=>1,'𡚨'=>1,'𡛪'=>1,'姬'=>1,'娛'=>1,'娧'=>1,'姘'=>1,'婦'=>1,'㛮'=>1,'㛼'=>1,'嬈'=>1,'嬾'=>1,'嬾'=>1,'𡧈'=>1,'寃'=>1,'寘'=>1,'寧'=>1,'寳'=>1,'𡬘'=>1,'寿'=>1,'将'=>1,'当'=>1,'尢'=>1,'㞁'=>1,'屠'=>1,'屮'=>1,'峀'=>1,'岍'=>1,'𡷤'=>1,'嵃'=>1,'𡷦'=>1,'嵮'=>1,'嵫'=>1,'嵼'=>1,'巡'=>1,'巢'=>1,'㠯'=>1,'巽'=>1,'帨'=>1,'帽'=>1,'幩'=>1,'㡢'=>1,'𢆃'=>1,'㡼'=>1,'庰'=>1,'庳'=>1,'庶'=>1,'廊'=>1,'𪎒'=>1,'廾'=>1,'𢌱'=>1,'𢌱'=>1,'舁'=>1,'弢'=>1,'弢'=>1,'㣇'=>1,'𣊸'=>1,'𦇚'=>1,'形'=>1,'彫'=>1,'㣣'=>1,'徚'=>1,'忍'=>1,'志'=>1,'忹'=>1,'悁'=>1,'㤺'=>1,'㤜'=>1,'悔'=>1,'𢛔'=>1,'惇'=>1,'慈'=>1,'慌'=>1,'慎'=>1,'慌'=>1,'慺'=>1,'憎'=>1,'憲'=>1,'憤'=>1,'憯'=>1,'懞'=>1,'懲'=>1,'懶'=>1,'成'=>1,'戛'=>1,'扝'=>1,'抱'=>1,'拔'=>1,'捐'=>1,'𢬌'=>1,'挽'=>1,'拼'=>1,'捨'=>1,'掃'=>1,'揤'=>1,'𢯱'=>1,'搢'=>1,'揅'=>1,'掩'=>1,'㨮'=>1,'摩'=>1,'摾'=>1,'撝'=>1,'摷'=>1,'㩬'=>1,'敏'=>1,'敬'=>1,'𣀊'=>1,'旣'=>1,'書'=>1,'晉'=>1,'㬙'=>1,'暑'=>1,'㬈'=>1,'㫤'=>1,'冒'=>1,'冕'=>1,'最'=>1,'暜'=>1,'肭'=>1,'䏙'=>1,'朗'=>1,'望'=>1,'朡'=>1,'杞'=>1,'杓'=>1,'𣏃'=>1,'㭉'=>1,'柺'=>1,'枅'=>1,'桒'=>1,'梅'=>1,'𣑭'=>1,'梎'=>1,'栟'=>1,'椔'=>1,'㮝'=>1,'楂'=>1,'榣'=>1,'槪'=>1,'檨'=>1,'𣚣'=>1,'櫛'=>1,'㰘'=>1,'次'=>1,'𣢧'=>1,'歔'=>1,'㱎'=>1,'歲'=>1,'殟'=>1,'殺'=>1,'殻'=>1,'𣪍'=>1,'𡴋'=>1,'𣫺'=>1,'汎'=>1,'𣲼'=>1,'沿'=>1,'泍'=>1,'汧'=>1,'洖'=>1,'派'=>1,'海'=>1,'流'=>1,'浩'=>1,'浸'=>1,'涅'=>1,'𣴞'=>1,'洴'=>1,'港'=>1,'湮'=>1,'㴳'=>1,'滋'=>1,'滇'=>1,'𣻑'=>1,'淹'=>1,'潮'=>1,'𣽞'=>1,'𣾎'=>1,'濆'=>1,'瀹'=>1,'瀞'=>1,'瀛'=>1,'㶖'=>1,'灊'=>1,'災'=>1,'灷'=>1,'炭'=>1,'𠔥'=>1,'煅'=>1,'𤉣'=>1,'熜'=>1,'𤎫'=>1,'爨'=>1,'爵'=>1,'牐'=>1,'𤘈'=>1,'犀'=>1,'犕'=>1,'𤜵'=>1,'𤠔'=>1,'獺'=>1,'王'=>1,'㺬'=>1,'玥'=>1,'㺸'=>1,'㺸'=>1,'瑇'=>1,'瑜'=>1,'瑱'=>1,'璅'=>1,'瓊'=>1,'㼛'=>1,'甤'=>1,'𤰶'=>1,'甾'=>1,'𤲒'=>1,'異'=>1,'𢆟'=>1,'瘐'=>1,'𤾡'=>1,'𤾸'=>1,'𥁄'=>1,'㿼'=>1,'䀈'=>1,'直'=>1,'𥃳'=>1,'𥃲'=>1,'𥄙'=>1,'𥄳'=>1,'眞'=>1,'真'=>1,'真'=>1,'睊'=>1,'䀹'=>1,'瞋'=>1,'䁆'=>1,'䂖'=>1,'𥐝'=>1,'硎'=>1,'碌'=>1,'磌'=>1,'䃣'=>1,'𥘦'=>1,'祖'=>1,'𥚚'=>1,'𥛅'=>1,'福'=>1,'秫'=>1,'䄯'=>1,'穀'=>1,'穊'=>1,'穏'=>1,'𥥼'=>1,'𥪧'=>1,'𥪧'=>1,'竮'=>1,'䈂'=>1,'𥮫'=>1,'篆'=>1,'築'=>1,'䈧'=>1,'𥲀'=>1,'糒'=>1,'䊠'=>1,'糨'=>1,'糣'=>1,'紀'=>1,'𥾆'=>1,'絣'=>1,'䌁'=>1,'緇'=>1,'縂'=>1,'繅'=>1,'䌴'=>1,'𦈨'=>1,'𦉇'=>1,'䍙'=>1,'𦋙'=>1,'罺'=>1,'𦌾'=>1,'羕'=>1,'翺'=>1,'者'=>1,'𦓚'=>1,'𦔣'=>1,'聠'=>1,'𦖨'=>1,'聰'=>1,'𣍟'=>1,'䏕'=>1,'育'=>1,'脃'=>1,'䐋'=>1,'脾'=>1,'媵'=>1,'𦞧'=>1,'𦞵'=>1,'𣎓'=>1,'𣎜'=>1,'舁'=>1,'舄'=>1,'辞'=>1,'䑫'=>1,'芑'=>1,'芋'=>1,'芝'=>1,'劳'=>1,'花'=>1,'芳'=>1,'芽'=>1,'苦'=>1,'𦬼'=>1,'若'=>1,'茝'=>1,'荣'=>1,'莭'=>1,'茣'=>1,'莽'=>1,'菧'=>1,'著'=>1,'荓'=>1,'菊'=>1,'菌'=>1,'菜'=>1,'𦰶'=>1,'𦵫'=>1,'𦳕'=>1,'䔫'=>1,'蓱'=>1,'蓳'=>1,'蔖'=>1,'𧏊'=>1,'蕤'=>1,'𦼬'=>1,'䕝'=>1,'䕡'=>1,'𦾱'=>1,'𧃒'=>1,'䕫'=>1,'虐'=>1,'虜'=>1,'虧'=>1,'虩'=>1,'蚩'=>1,'蚈'=>1,'蜎'=>1,'蛢'=>1,'蝹'=>1,'蜨'=>1,'蝫'=>1,'螆'=>1,'䗗'=>1,'蟡'=>1,'蠁'=>1,'䗹'=>1,'衠'=>1,'衣'=>1,'𧙧'=>1,'裗'=>1,'裞'=>1,'䘵'=>1,'裺'=>1,'㒻'=>1,'𧢮'=>1,'𧥦'=>1,'䚾'=>1,'䛇'=>1,'誠'=>1,'諭'=>1,'變'=>1,'豕'=>1,'𧲨'=>1,'貫'=>1,'賁'=>1,'贛'=>1,'起'=>1,'𧼯'=>1,'𠠄'=>1,'跋'=>1,'趼'=>1,'跰'=>1,'𠣞'=>1,'軔'=>1,'輸'=>1,'𨗒'=>1,'𨗭'=>1,'邔'=>1,'郱'=>1,'鄑'=>1,'𨜮'=>1,'鄛'=>1,'鈸'=>1,'鋗'=>1,'鋘'=>1,'鉼'=>1,'鏹'=>1,'鐕'=>1,'𨯺'=>1,'開'=>1,'䦕'=>1,'閷'=>1,'𨵷'=>1,'䧦'=>1,'雃'=>1,'嶲'=>1,'霣'=>1,'𩅅'=>1,'𩈚'=>1,'䩮'=>1,'䩶'=>1,'韠'=>1,'𩐊'=>1,'䪲'=>1,'𩒖'=>1,'頋'=>1,'頋'=>1,'頩'=>1,'𩖶'=>1,'飢'=>1,'䬳'=>1,'餩'=>1,'馧'=>1,'駂'=>1,'駾'=>1,'䯎'=>1,'𩬰'=>1,'鬒'=>1,'鱀'=>1,'鳽'=>1,'䳎'=>1,'䳭'=>1,'鵧'=>1,'𪃎'=>1,'䳸'=>1,'𪄅'=>1,'𪈎'=>1,'𪊑'=>1,'麻'=>1,'䵖'=>1,'黹'=>1,'黾'=>1,'鼅'=>1,'鼏'=>1,'鼖'=>1,'鼻'=>1,'𪘀'=>1,'̀'=>0,'́'=>0,'̂'=>0,'̃'=>0,'̄'=>0,'̆'=>0,'̇'=>0,'̈'=>0,'̉'=>0,'̊'=>0,'̋'=>0,'̌'=>0,'̏'=>0,'̑'=>0,'̓'=>0,'̔'=>0,'̛'=>0,'̣'=>0,'̤'=>0,'̥'=>0,'̦'=>0,'̧'=>0,'̨'=>0,'̭'=>0,'̮'=>0,'̰'=>0,'̱'=>0,'̸'=>0,'͂'=>0,'ͅ'=>0,'ٓ'=>0,'ٔ'=>0,'ٕ'=>0,'़'=>0,'া'=>0,'ৗ'=>0,'ା'=>0,'ୖ'=>0,'ୗ'=>0,'ா'=>0,'ௗ'=>0,'ౖ'=>0,'ೂ'=>0,'ೕ'=>0,'ೖ'=>0,'ാ'=>0,'ൗ'=>0,'්'=>0,'ා'=>0,'ෟ'=>0,'ီ'=>0,'ᅡ'=>0,'ᅢ'=>0,'ᅣ'=>0,'ᅤ'=>0,'ᅥ'=>0,'ᅦ'=>0,'ᅧ'=>0,'ᅨ'=>0,'ᅩ'=>0,'ᅪ'=>0,'ᅫ'=>0,'ᅬ'=>0,'ᅭ'=>0,'ᅮ'=>0,'ᅯ'=>0,'ᅰ'=>0,'ᅱ'=>0,'ᅲ'=>0,'ᅳ'=>0,'ᅴ'=>0,'ᅵ'=>0,'ᆨ'=>0,'ᆩ'=>0,'ᆪ'=>0,'ᆫ'=>0,'ᆬ'=>0,'ᆭ'=>0,'ᆮ'=>0,'ᆯ'=>0,'ᆰ'=>0,'ᆱ'=>0,'ᆲ'=>0,'ᆳ'=>0,'ᆴ'=>0,'ᆵ'=>0,'ᆶ'=>0,'ᆷ'=>0,'ᆸ'=>0,'ᆹ'=>0,'ᆺ'=>0,'ᆻ'=>0,'ᆼ'=>0,'ᆽ'=>0,'ᆾ'=>0,'ᆿ'=>0,'ᇀ'=>0,'ᇁ'=>0,'ᇂ'=>0,'ᬵ'=>0,'゙'=>0,'゚'=>0);
\ No newline at end of file +$GLOBALS['utf_nfkc_qc']=array(' '=>1,'¨'=>1,'ª'=>1,'¯'=>1,'²'=>1,'³'=>1,'´'=>1,'µ'=>1,'¸'=>1,'¹'=>1,'º'=>1,'¼'=>1,'½'=>1,'¾'=>1,'IJ'=>1,'ij'=>1,'Ŀ'=>1,'ŀ'=>1,'ʼn'=>1,'ſ'=>1,'DŽ'=>1,'Dž'=>1,'dž'=>1,'LJ'=>1,'Lj'=>1,'lj'=>1,'NJ'=>1,'Nj'=>1,'nj'=>1,'DZ'=>1,'Dz'=>1,'dz'=>1,'ʰ'=>1,'ʱ'=>1,'ʲ'=>1,'ʳ'=>1,'ʴ'=>1,'ʵ'=>1,'ʶ'=>1,'ʷ'=>1,'ʸ'=>1,'˘'=>1,'˙'=>1,'˚'=>1,'˛'=>1,'˜'=>1,'˝'=>1,'ˠ'=>1,'ˡ'=>1,'ˢ'=>1,'ˣ'=>1,'ˤ'=>1,'̀'=>1,'́'=>1,'̓'=>1,'̈́'=>1,'ʹ'=>1,'ͺ'=>1,';'=>1,'΄'=>1,'΅'=>1,'·'=>1,'ϐ'=>1,'ϑ'=>1,'ϒ'=>1,'ϓ'=>1,'ϔ'=>1,'ϕ'=>1,'ϖ'=>1,'ϰ'=>1,'ϱ'=>1,'ϲ'=>1,'ϴ'=>1,'ϵ'=>1,'Ϲ'=>1,'և'=>1,'ٵ'=>1,'ٶ'=>1,'ٷ'=>1,'ٸ'=>1,'क़'=>1,'ख़'=>1,'ग़'=>1,'ज़'=>1,'ड़'=>1,'ढ़'=>1,'फ़'=>1,'य़'=>1,'ড়'=>1,'ঢ়'=>1,'য়'=>1,'ਲ਼'=>1,'ਸ਼'=>1,'ਖ਼'=>1,'ਗ਼'=>1,'ਜ਼'=>1,'ਫ਼'=>1,'ଡ଼'=>1,'ଢ଼'=>1,'ำ'=>1,'ຳ'=>1,'ໜ'=>1,'ໝ'=>1,'༌'=>1,'གྷ'=>1,'ཌྷ'=>1,'དྷ'=>1,'བྷ'=>1,'ཛྷ'=>1,'ཀྵ'=>1,'ཱི'=>1,'ཱུ'=>1,'ྲྀ'=>1,'ཷ'=>1,'ླྀ'=>1,'ཹ'=>1,'ཱྀ'=>1,'ྒྷ'=>1,'ྜྷ'=>1,'ྡྷ'=>1,'ྦྷ'=>1,'ྫྷ'=>1,'ྐྵ'=>1,'ჼ'=>1,'ᴬ'=>1,'ᴭ'=>1,'ᴮ'=>1,'ᴰ'=>1,'ᴱ'=>1,'ᴲ'=>1,'ᴳ'=>1,'ᴴ'=>1,'ᴵ'=>1,'ᴶ'=>1,'ᴷ'=>1,'ᴸ'=>1,'ᴹ'=>1,'ᴺ'=>1,'ᴼ'=>1,'ᴽ'=>1,'ᴾ'=>1,'ᴿ'=>1,'ᵀ'=>1,'ᵁ'=>1,'ᵂ'=>1,'ᵃ'=>1,'ᵄ'=>1,'ᵅ'=>1,'ᵆ'=>1,'ᵇ'=>1,'ᵈ'=>1,'ᵉ'=>1,'ᵊ'=>1,'ᵋ'=>1,'ᵌ'=>1,'ᵍ'=>1,'ᵏ'=>1,'ᵐ'=>1,'ᵑ'=>1,'ᵒ'=>1,'ᵓ'=>1,'ᵔ'=>1,'ᵕ'=>1,'ᵖ'=>1,'ᵗ'=>1,'ᵘ'=>1,'ᵙ'=>1,'ᵚ'=>1,'ᵛ'=>1,'ᵜ'=>1,'ᵝ'=>1,'ᵞ'=>1,'ᵟ'=>1,'ᵠ'=>1,'ᵡ'=>1,'ᵢ'=>1,'ᵣ'=>1,'ᵤ'=>1,'ᵥ'=>1,'ᵦ'=>1,'ᵧ'=>1,'ᵨ'=>1,'ᵩ'=>1,'ᵪ'=>1,'ᵸ'=>1,'ᶛ'=>1,'ᶜ'=>1,'ᶝ'=>1,'ᶞ'=>1,'ᶟ'=>1,'ᶠ'=>1,'ᶡ'=>1,'ᶢ'=>1,'ᶣ'=>1,'ᶤ'=>1,'ᶥ'=>1,'ᶦ'=>1,'ᶧ'=>1,'ᶨ'=>1,'ᶩ'=>1,'ᶪ'=>1,'ᶫ'=>1,'ᶬ'=>1,'ᶭ'=>1,'ᶮ'=>1,'ᶯ'=>1,'ᶰ'=>1,'ᶱ'=>1,'ᶲ'=>1,'ᶳ'=>1,'ᶴ'=>1,'ᶵ'=>1,'ᶶ'=>1,'ᶷ'=>1,'ᶸ'=>1,'ᶹ'=>1,'ᶺ'=>1,'ᶻ'=>1,'ᶼ'=>1,'ᶽ'=>1,'ᶾ'=>1,'ᶿ'=>1,'ẚ'=>1,'ẛ'=>1,'ά'=>1,'έ'=>1,'ή'=>1,'ί'=>1,'ό'=>1,'ύ'=>1,'ώ'=>1,'Ά'=>1,'᾽'=>1,'ι'=>1,'᾿'=>1,'῀'=>1,'῁'=>1,'Έ'=>1,'Ή'=>1,'῍'=>1,'῎'=>1,'῏'=>1,'ΐ'=>1,'Ί'=>1,'῝'=>1,'῞'=>1,'῟'=>1,'ΰ'=>1,'Ύ'=>1,'῭'=>1,'΅'=>1,'`'=>1,'Ό'=>1,'Ώ'=>1,'´'=>1,'῾'=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,'‑'=>1,'‗'=>1,'․'=>1,'‥'=>1,'…'=>1,' '=>1,'″'=>1,'‴'=>1,'‶'=>1,'‷'=>1,'‼'=>1,'‾'=>1,'⁇'=>1,'⁈'=>1,'⁉'=>1,'⁗'=>1,' '=>1,'⁰'=>1,'ⁱ'=>1,'⁴'=>1,'⁵'=>1,'⁶'=>1,'⁷'=>1,'⁸'=>1,'⁹'=>1,'⁺'=>1,'⁻'=>1,'⁼'=>1,'⁽'=>1,'⁾'=>1,'ⁿ'=>1,'₀'=>1,'₁'=>1,'₂'=>1,'₃'=>1,'₄'=>1,'₅'=>1,'₆'=>1,'₇'=>1,'₈'=>1,'₉'=>1,'₊'=>1,'₋'=>1,'₌'=>1,'₍'=>1,'₎'=>1,'ₐ'=>1,'ₑ'=>1,'ₒ'=>1,'ₓ'=>1,'ₔ'=>1,'₨'=>1,'℀'=>1,'℁'=>1,'ℂ'=>1,'℃'=>1,'℅'=>1,'℆'=>1,'ℇ'=>1,'℉'=>1,'ℊ'=>1,'ℋ'=>1,'ℌ'=>1,'ℍ'=>1,'ℎ'=>1,'ℏ'=>1,'ℐ'=>1,'ℑ'=>1,'ℒ'=>1,'ℓ'=>1,'ℕ'=>1,'№'=>1,'ℙ'=>1,'ℚ'=>1,'ℛ'=>1,'ℜ'=>1,'ℝ'=>1,'℠'=>1,'℡'=>1,'™'=>1,'ℤ'=>1,'Ω'=>1,'ℨ'=>1,'K'=>1,'Å'=>1,'ℬ'=>1,'ℭ'=>1,'ℯ'=>1,'ℰ'=>1,'ℱ'=>1,'ℳ'=>1,'ℴ'=>1,'ℵ'=>1,'ℶ'=>1,'ℷ'=>1,'ℸ'=>1,'ℹ'=>1,'℻'=>1,'ℼ'=>1,'ℽ'=>1,'ℾ'=>1,'ℿ'=>1,'⅀'=>1,'ⅅ'=>1,'ⅆ'=>1,'ⅇ'=>1,'ⅈ'=>1,'ⅉ'=>1,'⅓'=>1,'⅔'=>1,'⅕'=>1,'⅖'=>1,'⅗'=>1,'⅘'=>1,'⅙'=>1,'⅚'=>1,'⅛'=>1,'⅜'=>1,'⅝'=>1,'⅞'=>1,'⅟'=>1,'Ⅰ'=>1,'Ⅱ'=>1,'Ⅲ'=>1,'Ⅳ'=>1,'Ⅴ'=>1,'Ⅵ'=>1,'Ⅶ'=>1,'Ⅷ'=>1,'Ⅸ'=>1,'Ⅹ'=>1,'Ⅺ'=>1,'Ⅻ'=>1,'Ⅼ'=>1,'Ⅽ'=>1,'Ⅾ'=>1,'Ⅿ'=>1,'ⅰ'=>1,'ⅱ'=>1,'ⅲ'=>1,'ⅳ'=>1,'ⅴ'=>1,'ⅵ'=>1,'ⅶ'=>1,'ⅷ'=>1,'ⅸ'=>1,'ⅹ'=>1,'ⅺ'=>1,'ⅻ'=>1,'ⅼ'=>1,'ⅽ'=>1,'ⅾ'=>1,'ⅿ'=>1,'∬'=>1,'∭'=>1,'∯'=>1,'∰'=>1,'〈'=>1,'〉'=>1,'①'=>1,'②'=>1,'③'=>1,'④'=>1,'⑤'=>1,'⑥'=>1,'⑦'=>1,'⑧'=>1,'⑨'=>1,'⑩'=>1,'⑪'=>1,'⑫'=>1,'⑬'=>1,'⑭'=>1,'⑮'=>1,'⑯'=>1,'⑰'=>1,'⑱'=>1,'⑲'=>1,'⑳'=>1,'⑴'=>1,'⑵'=>1,'⑶'=>1,'⑷'=>1,'⑸'=>1,'⑹'=>1,'⑺'=>1,'⑻'=>1,'⑼'=>1,'⑽'=>1,'⑾'=>1,'⑿'=>1,'⒀'=>1,'⒁'=>1,'⒂'=>1,'⒃'=>1,'⒄'=>1,'⒅'=>1,'⒆'=>1,'⒇'=>1,'⒈'=>1,'⒉'=>1,'⒊'=>1,'⒋'=>1,'⒌'=>1,'⒍'=>1,'⒎'=>1,'⒏'=>1,'⒐'=>1,'⒑'=>1,'⒒'=>1,'⒓'=>1,'⒔'=>1,'⒕'=>1,'⒖'=>1,'⒗'=>1,'⒘'=>1,'⒙'=>1,'⒚'=>1,'⒛'=>1,'⒜'=>1,'⒝'=>1,'⒞'=>1,'⒟'=>1,'⒠'=>1,'⒡'=>1,'⒢'=>1,'⒣'=>1,'⒤'=>1,'⒥'=>1,'⒦'=>1,'⒧'=>1,'⒨'=>1,'⒩'=>1,'⒪'=>1,'⒫'=>1,'⒬'=>1,'⒭'=>1,'⒮'=>1,'⒯'=>1,'⒰'=>1,'⒱'=>1,'⒲'=>1,'⒳'=>1,'⒴'=>1,'⒵'=>1,'Ⓐ'=>1,'Ⓑ'=>1,'Ⓒ'=>1,'Ⓓ'=>1,'Ⓔ'=>1,'Ⓕ'=>1,'Ⓖ'=>1,'Ⓗ'=>1,'Ⓘ'=>1,'Ⓙ'=>1,'Ⓚ'=>1,'Ⓛ'=>1,'Ⓜ'=>1,'Ⓝ'=>1,'Ⓞ'=>1,'Ⓟ'=>1,'Ⓠ'=>1,'Ⓡ'=>1,'Ⓢ'=>1,'Ⓣ'=>1,'Ⓤ'=>1,'Ⓥ'=>1,'Ⓦ'=>1,'Ⓧ'=>1,'Ⓨ'=>1,'Ⓩ'=>1,'ⓐ'=>1,'ⓑ'=>1,'ⓒ'=>1,'ⓓ'=>1,'ⓔ'=>1,'ⓕ'=>1,'ⓖ'=>1,'ⓗ'=>1,'ⓘ'=>1,'ⓙ'=>1,'ⓚ'=>1,'ⓛ'=>1,'ⓜ'=>1,'ⓝ'=>1,'ⓞ'=>1,'ⓟ'=>1,'ⓠ'=>1,'ⓡ'=>1,'ⓢ'=>1,'ⓣ'=>1,'ⓤ'=>1,'ⓥ'=>1,'ⓦ'=>1,'ⓧ'=>1,'ⓨ'=>1,'ⓩ'=>1,'⓪'=>1,'⨌'=>1,'⩴'=>1,'⩵'=>1,'⩶'=>1,'⫝̸'=>1,'ⵯ'=>1,'⺟'=>1,'⻳'=>1,'⼀'=>1,'⼁'=>1,'⼂'=>1,'⼃'=>1,'⼄'=>1,'⼅'=>1,'⼆'=>1,'⼇'=>1,'⼈'=>1,'⼉'=>1,'⼊'=>1,'⼋'=>1,'⼌'=>1,'⼍'=>1,'⼎'=>1,'⼏'=>1,'⼐'=>1,'⼑'=>1,'⼒'=>1,'⼓'=>1,'⼔'=>1,'⼕'=>1,'⼖'=>1,'⼗'=>1,'⼘'=>1,'⼙'=>1,'⼚'=>1,'⼛'=>1,'⼜'=>1,'⼝'=>1,'⼞'=>1,'⼟'=>1,'⼠'=>1,'⼡'=>1,'⼢'=>1,'⼣'=>1,'⼤'=>1,'⼥'=>1,'⼦'=>1,'⼧'=>1,'⼨'=>1,'⼩'=>1,'⼪'=>1,'⼫'=>1,'⼬'=>1,'⼭'=>1,'⼮'=>1,'⼯'=>1,'⼰'=>1,'⼱'=>1,'⼲'=>1,'⼳'=>1,'⼴'=>1,'⼵'=>1,'⼶'=>1,'⼷'=>1,'⼸'=>1,'⼹'=>1,'⼺'=>1,'⼻'=>1,'⼼'=>1,'⼽'=>1,'⼾'=>1,'⼿'=>1,'⽀'=>1,'⽁'=>1,'⽂'=>1,'⽃'=>1,'⽄'=>1,'⽅'=>1,'⽆'=>1,'⽇'=>1,'⽈'=>1,'⽉'=>1,'⽊'=>1,'⽋'=>1,'⽌'=>1,'⽍'=>1,'⽎'=>1,'⽏'=>1,'⽐'=>1,'⽑'=>1,'⽒'=>1,'⽓'=>1,'⽔'=>1,'⽕'=>1,'⽖'=>1,'⽗'=>1,'⽘'=>1,'⽙'=>1,'⽚'=>1,'⽛'=>1,'⽜'=>1,'⽝'=>1,'⽞'=>1,'⽟'=>1,'⽠'=>1,'⽡'=>1,'⽢'=>1,'⽣'=>1,'⽤'=>1,'⽥'=>1,'⽦'=>1,'⽧'=>1,'⽨'=>1,'⽩'=>1,'⽪'=>1,'⽫'=>1,'⽬'=>1,'⽭'=>1,'⽮'=>1,'⽯'=>1,'⽰'=>1,'⽱'=>1,'⽲'=>1,'⽳'=>1,'⽴'=>1,'⽵'=>1,'⽶'=>1,'⽷'=>1,'⽸'=>1,'⽹'=>1,'⽺'=>1,'⽻'=>1,'⽼'=>1,'⽽'=>1,'⽾'=>1,'⽿'=>1,'⾀'=>1,'⾁'=>1,'⾂'=>1,'⾃'=>1,'⾄'=>1,'⾅'=>1,'⾆'=>1,'⾇'=>1,'⾈'=>1,'⾉'=>1,'⾊'=>1,'⾋'=>1,'⾌'=>1,'⾍'=>1,'⾎'=>1,'⾏'=>1,'⾐'=>1,'⾑'=>1,'⾒'=>1,'⾓'=>1,'⾔'=>1,'⾕'=>1,'⾖'=>1,'⾗'=>1,'⾘'=>1,'⾙'=>1,'⾚'=>1,'⾛'=>1,'⾜'=>1,'⾝'=>1,'⾞'=>1,'⾟'=>1,'⾠'=>1,'⾡'=>1,'⾢'=>1,'⾣'=>1,'⾤'=>1,'⾥'=>1,'⾦'=>1,'⾧'=>1,'⾨'=>1,'⾩'=>1,'⾪'=>1,'⾫'=>1,'⾬'=>1,'⾭'=>1,'⾮'=>1,'⾯'=>1,'⾰'=>1,'⾱'=>1,'⾲'=>1,'⾳'=>1,'⾴'=>1,'⾵'=>1,'⾶'=>1,'⾷'=>1,'⾸'=>1,'⾹'=>1,'⾺'=>1,'⾻'=>1,'⾼'=>1,'⾽'=>1,'⾾'=>1,'⾿'=>1,'⿀'=>1,'⿁'=>1,'⿂'=>1,'⿃'=>1,'⿄'=>1,'⿅'=>1,'⿆'=>1,'⿇'=>1,'⿈'=>1,'⿉'=>1,'⿊'=>1,'⿋'=>1,'⿌'=>1,'⿍'=>1,'⿎'=>1,'⿏'=>1,'⿐'=>1,'⿑'=>1,'⿒'=>1,'⿓'=>1,'⿔'=>1,'⿕'=>1,' '=>1,'〶'=>1,'〸'=>1,'〹'=>1,'〺'=>1,'゛'=>1,'゜'=>1,'ゟ'=>1,'ヿ'=>1,'ㄱ'=>1,'ㄲ'=>1,'ㄳ'=>1,'ㄴ'=>1,'ㄵ'=>1,'ㄶ'=>1,'ㄷ'=>1,'ㄸ'=>1,'ㄹ'=>1,'ㄺ'=>1,'ㄻ'=>1,'ㄼ'=>1,'ㄽ'=>1,'ㄾ'=>1,'ㄿ'=>1,'ㅀ'=>1,'ㅁ'=>1,'ㅂ'=>1,'ㅃ'=>1,'ㅄ'=>1,'ㅅ'=>1,'ㅆ'=>1,'ㅇ'=>1,'ㅈ'=>1,'ㅉ'=>1,'ㅊ'=>1,'ㅋ'=>1,'ㅌ'=>1,'ㅍ'=>1,'ㅎ'=>1,'ㅏ'=>1,'ㅐ'=>1,'ㅑ'=>1,'ㅒ'=>1,'ㅓ'=>1,'ㅔ'=>1,'ㅕ'=>1,'ㅖ'=>1,'ㅗ'=>1,'ㅘ'=>1,'ㅙ'=>1,'ㅚ'=>1,'ㅛ'=>1,'ㅜ'=>1,'ㅝ'=>1,'ㅞ'=>1,'ㅟ'=>1,'ㅠ'=>1,'ㅡ'=>1,'ㅢ'=>1,'ㅣ'=>1,'ㅤ'=>1,'ㅥ'=>1,'ㅦ'=>1,'ㅧ'=>1,'ㅨ'=>1,'ㅩ'=>1,'ㅪ'=>1,'ㅫ'=>1,'ㅬ'=>1,'ㅭ'=>1,'ㅮ'=>1,'ㅯ'=>1,'ㅰ'=>1,'ㅱ'=>1,'ㅲ'=>1,'ㅳ'=>1,'ㅴ'=>1,'ㅵ'=>1,'ㅶ'=>1,'ㅷ'=>1,'ㅸ'=>1,'ㅹ'=>1,'ㅺ'=>1,'ㅻ'=>1,'ㅼ'=>1,'ㅽ'=>1,'ㅾ'=>1,'ㅿ'=>1,'ㆀ'=>1,'ㆁ'=>1,'ㆂ'=>1,'ㆃ'=>1,'ㆄ'=>1,'ㆅ'=>1,'ㆆ'=>1,'ㆇ'=>1,'ㆈ'=>1,'ㆉ'=>1,'ㆊ'=>1,'ㆋ'=>1,'ㆌ'=>1,'ㆍ'=>1,'ㆎ'=>1,'㆒'=>1,'㆓'=>1,'㆔'=>1,'㆕'=>1,'㆖'=>1,'㆗'=>1,'㆘'=>1,'㆙'=>1,'㆚'=>1,'㆛'=>1,'㆜'=>1,'㆝'=>1,'㆞'=>1,'㆟'=>1,'㈀'=>1,'㈁'=>1,'㈂'=>1,'㈃'=>1,'㈄'=>1,'㈅'=>1,'㈆'=>1,'㈇'=>1,'㈈'=>1,'㈉'=>1,'㈊'=>1,'㈋'=>1,'㈌'=>1,'㈍'=>1,'㈎'=>1,'㈏'=>1,'㈐'=>1,'㈑'=>1,'㈒'=>1,'㈓'=>1,'㈔'=>1,'㈕'=>1,'㈖'=>1,'㈗'=>1,'㈘'=>1,'㈙'=>1,'㈚'=>1,'㈛'=>1,'㈜'=>1,'㈝'=>1,'㈞'=>1,'㈠'=>1,'㈡'=>1,'㈢'=>1,'㈣'=>1,'㈤'=>1,'㈥'=>1,'㈦'=>1,'㈧'=>1,'㈨'=>1,'㈩'=>1,'㈪'=>1,'㈫'=>1,'㈬'=>1,'㈭'=>1,'㈮'=>1,'㈯'=>1,'㈰'=>1,'㈱'=>1,'㈲'=>1,'㈳'=>1,'㈴'=>1,'㈵'=>1,'㈶'=>1,'㈷'=>1,'㈸'=>1,'㈹'=>1,'㈺'=>1,'㈻'=>1,'㈼'=>1,'㈽'=>1,'㈾'=>1,'㈿'=>1,'㉀'=>1,'㉁'=>1,'㉂'=>1,'㉃'=>1,'㉐'=>1,'㉑'=>1,'㉒'=>1,'㉓'=>1,'㉔'=>1,'㉕'=>1,'㉖'=>1,'㉗'=>1,'㉘'=>1,'㉙'=>1,'㉚'=>1,'㉛'=>1,'㉜'=>1,'㉝'=>1,'㉞'=>1,'㉟'=>1,'㉠'=>1,'㉡'=>1,'㉢'=>1,'㉣'=>1,'㉤'=>1,'㉥'=>1,'㉦'=>1,'㉧'=>1,'㉨'=>1,'㉩'=>1,'㉪'=>1,'㉫'=>1,'㉬'=>1,'㉭'=>1,'㉮'=>1,'㉯'=>1,'㉰'=>1,'㉱'=>1,'㉲'=>1,'㉳'=>1,'㉴'=>1,'㉵'=>1,'㉶'=>1,'㉷'=>1,'㉸'=>1,'㉹'=>1,'㉺'=>1,'㉻'=>1,'㉼'=>1,'㉽'=>1,'㉾'=>1,'㊀'=>1,'㊁'=>1,'㊂'=>1,'㊃'=>1,'㊄'=>1,'㊅'=>1,'㊆'=>1,'㊇'=>1,'㊈'=>1,'㊉'=>1,'㊊'=>1,'㊋'=>1,'㊌'=>1,'㊍'=>1,'㊎'=>1,'㊏'=>1,'㊐'=>1,'㊑'=>1,'㊒'=>1,'㊓'=>1,'㊔'=>1,'㊕'=>1,'㊖'=>1,'㊗'=>1,'㊘'=>1,'㊙'=>1,'㊚'=>1,'㊛'=>1,'㊜'=>1,'㊝'=>1,'㊞'=>1,'㊟'=>1,'㊠'=>1,'㊡'=>1,'㊢'=>1,'㊣'=>1,'㊤'=>1,'㊥'=>1,'㊦'=>1,'㊧'=>1,'㊨'=>1,'㊩'=>1,'㊪'=>1,'㊫'=>1,'㊬'=>1,'㊭'=>1,'㊮'=>1,'㊯'=>1,'㊰'=>1,'㊱'=>1,'㊲'=>1,'㊳'=>1,'㊴'=>1,'㊵'=>1,'㊶'=>1,'㊷'=>1,'㊸'=>1,'㊹'=>1,'㊺'=>1,'㊻'=>1,'㊼'=>1,'㊽'=>1,'㊾'=>1,'㊿'=>1,'㋀'=>1,'㋁'=>1,'㋂'=>1,'㋃'=>1,'㋄'=>1,'㋅'=>1,'㋆'=>1,'㋇'=>1,'㋈'=>1,'㋉'=>1,'㋊'=>1,'㋋'=>1,'㋌'=>1,'㋍'=>1,'㋎'=>1,'㋏'=>1,'㋐'=>1,'㋑'=>1,'㋒'=>1,'㋓'=>1,'㋔'=>1,'㋕'=>1,'㋖'=>1,'㋗'=>1,'㋘'=>1,'㋙'=>1,'㋚'=>1,'㋛'=>1,'㋜'=>1,'㋝'=>1,'㋞'=>1,'㋟'=>1,'㋠'=>1,'㋡'=>1,'㋢'=>1,'㋣'=>1,'㋤'=>1,'㋥'=>1,'㋦'=>1,'㋧'=>1,'㋨'=>1,'㋩'=>1,'㋪'=>1,'㋫'=>1,'㋬'=>1,'㋭'=>1,'㋮'=>1,'㋯'=>1,'㋰'=>1,'㋱'=>1,'㋲'=>1,'㋳'=>1,'㋴'=>1,'㋵'=>1,'㋶'=>1,'㋷'=>1,'㋸'=>1,'㋹'=>1,'㋺'=>1,'㋻'=>1,'㋼'=>1,'㋽'=>1,'㋾'=>1,'㌀'=>1,'㌁'=>1,'㌂'=>1,'㌃'=>1,'㌄'=>1,'㌅'=>1,'㌆'=>1,'㌇'=>1,'㌈'=>1,'㌉'=>1,'㌊'=>1,'㌋'=>1,'㌌'=>1,'㌍'=>1,'㌎'=>1,'㌏'=>1,'㌐'=>1,'㌑'=>1,'㌒'=>1,'㌓'=>1,'㌔'=>1,'㌕'=>1,'㌖'=>1,'㌗'=>1,'㌘'=>1,'㌙'=>1,'㌚'=>1,'㌛'=>1,'㌜'=>1,'㌝'=>1,'㌞'=>1,'㌟'=>1,'㌠'=>1,'㌡'=>1,'㌢'=>1,'㌣'=>1,'㌤'=>1,'㌥'=>1,'㌦'=>1,'㌧'=>1,'㌨'=>1,'㌩'=>1,'㌪'=>1,'㌫'=>1,'㌬'=>1,'㌭'=>1,'㌮'=>1,'㌯'=>1,'㌰'=>1,'㌱'=>1,'㌲'=>1,'㌳'=>1,'㌴'=>1,'㌵'=>1,'㌶'=>1,'㌷'=>1,'㌸'=>1,'㌹'=>1,'㌺'=>1,'㌻'=>1,'㌼'=>1,'㌽'=>1,'㌾'=>1,'㌿'=>1,'㍀'=>1,'㍁'=>1,'㍂'=>1,'㍃'=>1,'㍄'=>1,'㍅'=>1,'㍆'=>1,'㍇'=>1,'㍈'=>1,'㍉'=>1,'㍊'=>1,'㍋'=>1,'㍌'=>1,'㍍'=>1,'㍎'=>1,'㍏'=>1,'㍐'=>1,'㍑'=>1,'㍒'=>1,'㍓'=>1,'㍔'=>1,'㍕'=>1,'㍖'=>1,'㍗'=>1,'㍘'=>1,'㍙'=>1,'㍚'=>1,'㍛'=>1,'㍜'=>1,'㍝'=>1,'㍞'=>1,'㍟'=>1,'㍠'=>1,'㍡'=>1,'㍢'=>1,'㍣'=>1,'㍤'=>1,'㍥'=>1,'㍦'=>1,'㍧'=>1,'㍨'=>1,'㍩'=>1,'㍪'=>1,'㍫'=>1,'㍬'=>1,'㍭'=>1,'㍮'=>1,'㍯'=>1,'㍰'=>1,'㍱'=>1,'㍲'=>1,'㍳'=>1,'㍴'=>1,'㍵'=>1,'㍶'=>1,'㍷'=>1,'㍸'=>1,'㍹'=>1,'㍺'=>1,'㍻'=>1,'㍼'=>1,'㍽'=>1,'㍾'=>1,'㍿'=>1,'㎀'=>1,'㎁'=>1,'㎂'=>1,'㎃'=>1,'㎄'=>1,'㎅'=>1,'㎆'=>1,'㎇'=>1,'㎈'=>1,'㎉'=>1,'㎊'=>1,'㎋'=>1,'㎌'=>1,'㎍'=>1,'㎎'=>1,'㎏'=>1,'㎐'=>1,'㎑'=>1,'㎒'=>1,'㎓'=>1,'㎔'=>1,'㎕'=>1,'㎖'=>1,'㎗'=>1,'㎘'=>1,'㎙'=>1,'㎚'=>1,'㎛'=>1,'㎜'=>1,'㎝'=>1,'㎞'=>1,'㎟'=>1,'㎠'=>1,'㎡'=>1,'㎢'=>1,'㎣'=>1,'㎤'=>1,'㎥'=>1,'㎦'=>1,'㎧'=>1,'㎨'=>1,'㎩'=>1,'㎪'=>1,'㎫'=>1,'㎬'=>1,'㎭'=>1,'㎮'=>1,'㎯'=>1,'㎰'=>1,'㎱'=>1,'㎲'=>1,'㎳'=>1,'㎴'=>1,'㎵'=>1,'㎶'=>1,'㎷'=>1,'㎸'=>1,'㎹'=>1,'㎺'=>1,'㎻'=>1,'㎼'=>1,'㎽'=>1,'㎾'=>1,'㎿'=>1,'㏀'=>1,'㏁'=>1,'㏂'=>1,'㏃'=>1,'㏄'=>1,'㏅'=>1,'㏆'=>1,'㏇'=>1,'㏈'=>1,'㏉'=>1,'㏊'=>1,'㏋'=>1,'㏌'=>1,'㏍'=>1,'㏎'=>1,'㏏'=>1,'㏐'=>1,'㏑'=>1,'㏒'=>1,'㏓'=>1,'㏔'=>1,'㏕'=>1,'㏖'=>1,'㏗'=>1,'㏘'=>1,'㏙'=>1,'㏚'=>1,'㏛'=>1,'㏜'=>1,'㏝'=>1,'㏞'=>1,'㏟'=>1,'㏠'=>1,'㏡'=>1,'㏢'=>1,'㏣'=>1,'㏤'=>1,'㏥'=>1,'㏦'=>1,'㏧'=>1,'㏨'=>1,'㏩'=>1,'㏪'=>1,'㏫'=>1,'㏬'=>1,'㏭'=>1,'㏮'=>1,'㏯'=>1,'㏰'=>1,'㏱'=>1,'㏲'=>1,'㏳'=>1,'㏴'=>1,'㏵'=>1,'㏶'=>1,'㏷'=>1,'㏸'=>1,'㏹'=>1,'㏺'=>1,'㏻'=>1,'㏼'=>1,'㏽'=>1,'㏾'=>1,'㏿'=>1,'豈'=>1,'更'=>1,'車'=>1,'賈'=>1,'滑'=>1,'串'=>1,'句'=>1,'龜'=>1,'龜'=>1,'契'=>1,'金'=>1,'喇'=>1,'奈'=>1,'懶'=>1,'癩'=>1,'羅'=>1,'蘿'=>1,'螺'=>1,'裸'=>1,'邏'=>1,'樂'=>1,'洛'=>1,'烙'=>1,'珞'=>1,'落'=>1,'酪'=>1,'駱'=>1,'亂'=>1,'卵'=>1,'欄'=>1,'爛'=>1,'蘭'=>1,'鸞'=>1,'嵐'=>1,'濫'=>1,'藍'=>1,'襤'=>1,'拉'=>1,'臘'=>1,'蠟'=>1,'廊'=>1,'朗'=>1,'浪'=>1,'狼'=>1,'郎'=>1,'來'=>1,'冷'=>1,'勞'=>1,'擄'=>1,'櫓'=>1,'爐'=>1,'盧'=>1,'老'=>1,'蘆'=>1,'虜'=>1,'路'=>1,'露'=>1,'魯'=>1,'鷺'=>1,'碌'=>1,'祿'=>1,'綠'=>1,'菉'=>1,'錄'=>1,'鹿'=>1,'論'=>1,'壟'=>1,'弄'=>1,'籠'=>1,'聾'=>1,'牢'=>1,'磊'=>1,'賂'=>1,'雷'=>1,'壘'=>1,'屢'=>1,'樓'=>1,'淚'=>1,'漏'=>1,'累'=>1,'縷'=>1,'陋'=>1,'勒'=>1,'肋'=>1,'凜'=>1,'凌'=>1,'稜'=>1,'綾'=>1,'菱'=>1,'陵'=>1,'讀'=>1,'拏'=>1,'樂'=>1,'諾'=>1,'丹'=>1,'寧'=>1,'怒'=>1,'率'=>1,'異'=>1,'北'=>1,'磻'=>1,'便'=>1,'復'=>1,'不'=>1,'泌'=>1,'數'=>1,'索'=>1,'參'=>1,'塞'=>1,'省'=>1,'葉'=>1,'說'=>1,'殺'=>1,'辰'=>1,'沈'=>1,'拾'=>1,'若'=>1,'掠'=>1,'略'=>1,'亮'=>1,'兩'=>1,'凉'=>1,'梁'=>1,'糧'=>1,'良'=>1,'諒'=>1,'量'=>1,'勵'=>1,'呂'=>1,'女'=>1,'廬'=>1,'旅'=>1,'濾'=>1,'礪'=>1,'閭'=>1,'驪'=>1,'麗'=>1,'黎'=>1,'力'=>1,'曆'=>1,'歷'=>1,'轢'=>1,'年'=>1,'憐'=>1,'戀'=>1,'撚'=>1,'漣'=>1,'煉'=>1,'璉'=>1,'秊'=>1,'練'=>1,'聯'=>1,'輦'=>1,'蓮'=>1,'連'=>1,'鍊'=>1,'列'=>1,'劣'=>1,'咽'=>1,'烈'=>1,'裂'=>1,'說'=>1,'廉'=>1,'念'=>1,'捻'=>1,'殮'=>1,'簾'=>1,'獵'=>1,'令'=>1,'囹'=>1,'寧'=>1,'嶺'=>1,'怜'=>1,'玲'=>1,'瑩'=>1,'羚'=>1,'聆'=>1,'鈴'=>1,'零'=>1,'靈'=>1,'領'=>1,'例'=>1,'禮'=>1,'醴'=>1,'隸'=>1,'惡'=>1,'了'=>1,'僚'=>1,'寮'=>1,'尿'=>1,'料'=>1,'樂'=>1,'燎'=>1,'療'=>1,'蓼'=>1,'遼'=>1,'龍'=>1,'暈'=>1,'阮'=>1,'劉'=>1,'杻'=>1,'柳'=>1,'流'=>1,'溜'=>1,'琉'=>1,'留'=>1,'硫'=>1,'紐'=>1,'類'=>1,'六'=>1,'戮'=>1,'陸'=>1,'倫'=>1,'崙'=>1,'淪'=>1,'輪'=>1,'律'=>1,'慄'=>1,'栗'=>1,'率'=>1,'隆'=>1,'利'=>1,'吏'=>1,'履'=>1,'易'=>1,'李'=>1,'梨'=>1,'泥'=>1,'理'=>1,'痢'=>1,'罹'=>1,'裏'=>1,'裡'=>1,'里'=>1,'離'=>1,'匿'=>1,'溺'=>1,'吝'=>1,'燐'=>1,'璘'=>1,'藺'=>1,'隣'=>1,'鱗'=>1,'麟'=>1,'林'=>1,'淋'=>1,'臨'=>1,'立'=>1,'笠'=>1,'粒'=>1,'狀'=>1,'炙'=>1,'識'=>1,'什'=>1,'茶'=>1,'刺'=>1,'切'=>1,'度'=>1,'拓'=>1,'糖'=>1,'宅'=>1,'洞'=>1,'暴'=>1,'輻'=>1,'行'=>1,'降'=>1,'見'=>1,'廓'=>1,'兀'=>1,'嗀'=>1,'塚'=>1,'晴'=>1,'凞'=>1,'猪'=>1,'益'=>1,'礼'=>1,'神'=>1,'祥'=>1,'福'=>1,'靖'=>1,'精'=>1,'羽'=>1,'蘒'=>1,'諸'=>1,'逸'=>1,'都'=>1,'飯'=>1,'飼'=>1,'館'=>1,'鶴'=>1,'侮'=>1,'僧'=>1,'免'=>1,'勉'=>1,'勤'=>1,'卑'=>1,'喝'=>1,'嘆'=>1,'器'=>1,'塀'=>1,'墨'=>1,'層'=>1,'屮'=>1,'悔'=>1,'慨'=>1,'憎'=>1,'懲'=>1,'敏'=>1,'既'=>1,'暑'=>1,'梅'=>1,'海'=>1,'渚'=>1,'漢'=>1,'煮'=>1,'爫'=>1,'琢'=>1,'碑'=>1,'社'=>1,'祉'=>1,'祈'=>1,'祐'=>1,'祖'=>1,'祝'=>1,'禍'=>1,'禎'=>1,'穀'=>1,'突'=>1,'節'=>1,'練'=>1,'縉'=>1,'繁'=>1,'署'=>1,'者'=>1,'臭'=>1,'艹'=>1,'艹'=>1,'著'=>1,'褐'=>1,'視'=>1,'謁'=>1,'謹'=>1,'賓'=>1,'贈'=>1,'辶'=>1,'逸'=>1,'難'=>1,'響'=>1,'頻'=>1,'並'=>1,'况'=>1,'全'=>1,'侀'=>1,'充'=>1,'冀'=>1,'勇'=>1,'勺'=>1,'喝'=>1,'啕'=>1,'喙'=>1,'嗢'=>1,'塚'=>1,'墳'=>1,'奄'=>1,'奔'=>1,'婢'=>1,'嬨'=>1,'廒'=>1,'廙'=>1,'彩'=>1,'徭'=>1,'惘'=>1,'慎'=>1,'愈'=>1,'憎'=>1,'慠'=>1,'懲'=>1,'戴'=>1,'揄'=>1,'搜'=>1,'摒'=>1,'敖'=>1,'晴'=>1,'朗'=>1,'望'=>1,'杖'=>1,'歹'=>1,'殺'=>1,'流'=>1,'滛'=>1,'滋'=>1,'漢'=>1,'瀞'=>1,'煮'=>1,'瞧'=>1,'爵'=>1,'犯'=>1,'猪'=>1,'瑱'=>1,'甆'=>1,'画'=>1,'瘝'=>1,'瘟'=>1,'益'=>1,'盛'=>1,'直'=>1,'睊'=>1,'着'=>1,'磌'=>1,'窱'=>1,'節'=>1,'类'=>1,'絛'=>1,'練'=>1,'缾'=>1,'者'=>1,'荒'=>1,'華'=>1,'蝹'=>1,'襁'=>1,'覆'=>1,'視'=>1,'調'=>1,'諸'=>1,'請'=>1,'謁'=>1,'諾'=>1,'諭'=>1,'謹'=>1,'變'=>1,'贈'=>1,'輸'=>1,'遲'=>1,'醙'=>1,'鉶'=>1,'陼'=>1,'難'=>1,'靖'=>1,'韛'=>1,'響'=>1,'頋'=>1,'頻'=>1,'鬒'=>1,'龜'=>1,'𢡊'=>1,'𢡄'=>1,'𣏕'=>1,'㮝'=>1,'䀘'=>1,'䀹'=>1,'𥉉'=>1,'𥳐'=>1,'𧻓'=>1,'齃'=>1,'龎'=>1,'ff'=>1,'fi'=>1,'fl'=>1,'ffi'=>1,'ffl'=>1,'ſt'=>1,'st'=>1,'ﬓ'=>1,'ﬔ'=>1,'ﬕ'=>1,'ﬖ'=>1,'ﬗ'=>1,'יִ'=>1,'ײַ'=>1,'ﬠ'=>1,'ﬡ'=>1,'ﬢ'=>1,'ﬣ'=>1,'ﬤ'=>1,'ﬥ'=>1,'ﬦ'=>1,'ﬧ'=>1,'ﬨ'=>1,'﬩'=>1,'שׁ'=>1,'שׂ'=>1,'שּׁ'=>1,'שּׂ'=>1,'אַ'=>1,'אָ'=>1,'אּ'=>1,'בּ'=>1,'גּ'=>1,'דּ'=>1,'הּ'=>1,'וּ'=>1,'זּ'=>1,'טּ'=>1,'יּ'=>1,'ךּ'=>1,'כּ'=>1,'לּ'=>1,'מּ'=>1,'נּ'=>1,'סּ'=>1,'ףּ'=>1,'פּ'=>1,'צּ'=>1,'קּ'=>1,'רּ'=>1,'שּ'=>1,'תּ'=>1,'וֹ'=>1,'בֿ'=>1,'כֿ'=>1,'פֿ'=>1,'ﭏ'=>1,'ﭐ'=>1,'ﭑ'=>1,'ﭒ'=>1,'ﭓ'=>1,'ﭔ'=>1,'ﭕ'=>1,'ﭖ'=>1,'ﭗ'=>1,'ﭘ'=>1,'ﭙ'=>1,'ﭚ'=>1,'ﭛ'=>1,'ﭜ'=>1,'ﭝ'=>1,'ﭞ'=>1,'ﭟ'=>1,'ﭠ'=>1,'ﭡ'=>1,'ﭢ'=>1,'ﭣ'=>1,'ﭤ'=>1,'ﭥ'=>1,'ﭦ'=>1,'ﭧ'=>1,'ﭨ'=>1,'ﭩ'=>1,'ﭪ'=>1,'ﭫ'=>1,'ﭬ'=>1,'ﭭ'=>1,'ﭮ'=>1,'ﭯ'=>1,'ﭰ'=>1,'ﭱ'=>1,'ﭲ'=>1,'ﭳ'=>1,'ﭴ'=>1,'ﭵ'=>1,'ﭶ'=>1,'ﭷ'=>1,'ﭸ'=>1,'ﭹ'=>1,'ﭺ'=>1,'ﭻ'=>1,'ﭼ'=>1,'ﭽ'=>1,'ﭾ'=>1,'ﭿ'=>1,'ﮀ'=>1,'ﮁ'=>1,'ﮂ'=>1,'ﮃ'=>1,'ﮄ'=>1,'ﮅ'=>1,'ﮆ'=>1,'ﮇ'=>1,'ﮈ'=>1,'ﮉ'=>1,'ﮊ'=>1,'ﮋ'=>1,'ﮌ'=>1,'ﮍ'=>1,'ﮎ'=>1,'ﮏ'=>1,'ﮐ'=>1,'ﮑ'=>1,'ﮒ'=>1,'ﮓ'=>1,'ﮔ'=>1,'ﮕ'=>1,'ﮖ'=>1,'ﮗ'=>1,'ﮘ'=>1,'ﮙ'=>1,'ﮚ'=>1,'ﮛ'=>1,'ﮜ'=>1,'ﮝ'=>1,'ﮞ'=>1,'ﮟ'=>1,'ﮠ'=>1,'ﮡ'=>1,'ﮢ'=>1,'ﮣ'=>1,'ﮤ'=>1,'ﮥ'=>1,'ﮦ'=>1,'ﮧ'=>1,'ﮨ'=>1,'ﮩ'=>1,'ﮪ'=>1,'ﮫ'=>1,'ﮬ'=>1,'ﮭ'=>1,'ﮮ'=>1,'ﮯ'=>1,'ﮰ'=>1,'ﮱ'=>1,'ﯓ'=>1,'ﯔ'=>1,'ﯕ'=>1,'ﯖ'=>1,'ﯗ'=>1,'ﯘ'=>1,'ﯙ'=>1,'ﯚ'=>1,'ﯛ'=>1,'ﯜ'=>1,'ﯝ'=>1,'ﯞ'=>1,'ﯟ'=>1,'ﯠ'=>1,'ﯡ'=>1,'ﯢ'=>1,'ﯣ'=>1,'ﯤ'=>1,'ﯥ'=>1,'ﯦ'=>1,'ﯧ'=>1,'ﯨ'=>1,'ﯩ'=>1,'ﯪ'=>1,'ﯫ'=>1,'ﯬ'=>1,'ﯭ'=>1,'ﯮ'=>1,'ﯯ'=>1,'ﯰ'=>1,'ﯱ'=>1,'ﯲ'=>1,'ﯳ'=>1,'ﯴ'=>1,'ﯵ'=>1,'ﯶ'=>1,'ﯷ'=>1,'ﯸ'=>1,'ﯹ'=>1,'ﯺ'=>1,'ﯻ'=>1,'ﯼ'=>1,'ﯽ'=>1,'ﯾ'=>1,'ﯿ'=>1,'ﰀ'=>1,'ﰁ'=>1,'ﰂ'=>1,'ﰃ'=>1,'ﰄ'=>1,'ﰅ'=>1,'ﰆ'=>1,'ﰇ'=>1,'ﰈ'=>1,'ﰉ'=>1,'ﰊ'=>1,'ﰋ'=>1,'ﰌ'=>1,'ﰍ'=>1,'ﰎ'=>1,'ﰏ'=>1,'ﰐ'=>1,'ﰑ'=>1,'ﰒ'=>1,'ﰓ'=>1,'ﰔ'=>1,'ﰕ'=>1,'ﰖ'=>1,'ﰗ'=>1,'ﰘ'=>1,'ﰙ'=>1,'ﰚ'=>1,'ﰛ'=>1,'ﰜ'=>1,'ﰝ'=>1,'ﰞ'=>1,'ﰟ'=>1,'ﰠ'=>1,'ﰡ'=>1,'ﰢ'=>1,'ﰣ'=>1,'ﰤ'=>1,'ﰥ'=>1,'ﰦ'=>1,'ﰧ'=>1,'ﰨ'=>1,'ﰩ'=>1,'ﰪ'=>1,'ﰫ'=>1,'ﰬ'=>1,'ﰭ'=>1,'ﰮ'=>1,'ﰯ'=>1,'ﰰ'=>1,'ﰱ'=>1,'ﰲ'=>1,'ﰳ'=>1,'ﰴ'=>1,'ﰵ'=>1,'ﰶ'=>1,'ﰷ'=>1,'ﰸ'=>1,'ﰹ'=>1,'ﰺ'=>1,'ﰻ'=>1,'ﰼ'=>1,'ﰽ'=>1,'ﰾ'=>1,'ﰿ'=>1,'ﱀ'=>1,'ﱁ'=>1,'ﱂ'=>1,'ﱃ'=>1,'ﱄ'=>1,'ﱅ'=>1,'ﱆ'=>1,'ﱇ'=>1,'ﱈ'=>1,'ﱉ'=>1,'ﱊ'=>1,'ﱋ'=>1,'ﱌ'=>1,'ﱍ'=>1,'ﱎ'=>1,'ﱏ'=>1,'ﱐ'=>1,'ﱑ'=>1,'ﱒ'=>1,'ﱓ'=>1,'ﱔ'=>1,'ﱕ'=>1,'ﱖ'=>1,'ﱗ'=>1,'ﱘ'=>1,'ﱙ'=>1,'ﱚ'=>1,'ﱛ'=>1,'ﱜ'=>1,'ﱝ'=>1,'ﱞ'=>1,'ﱟ'=>1,'ﱠ'=>1,'ﱡ'=>1,'ﱢ'=>1,'ﱣ'=>1,'ﱤ'=>1,'ﱥ'=>1,'ﱦ'=>1,'ﱧ'=>1,'ﱨ'=>1,'ﱩ'=>1,'ﱪ'=>1,'ﱫ'=>1,'ﱬ'=>1,'ﱭ'=>1,'ﱮ'=>1,'ﱯ'=>1,'ﱰ'=>1,'ﱱ'=>1,'ﱲ'=>1,'ﱳ'=>1,'ﱴ'=>1,'ﱵ'=>1,'ﱶ'=>1,'ﱷ'=>1,'ﱸ'=>1,'ﱹ'=>1,'ﱺ'=>1,'ﱻ'=>1,'ﱼ'=>1,'ﱽ'=>1,'ﱾ'=>1,'ﱿ'=>1,'ﲀ'=>1,'ﲁ'=>1,'ﲂ'=>1,'ﲃ'=>1,'ﲄ'=>1,'ﲅ'=>1,'ﲆ'=>1,'ﲇ'=>1,'ﲈ'=>1,'ﲉ'=>1,'ﲊ'=>1,'ﲋ'=>1,'ﲌ'=>1,'ﲍ'=>1,'ﲎ'=>1,'ﲏ'=>1,'ﲐ'=>1,'ﲑ'=>1,'ﲒ'=>1,'ﲓ'=>1,'ﲔ'=>1,'ﲕ'=>1,'ﲖ'=>1,'ﲗ'=>1,'ﲘ'=>1,'ﲙ'=>1,'ﲚ'=>1,'ﲛ'=>1,'ﲜ'=>1,'ﲝ'=>1,'ﲞ'=>1,'ﲟ'=>1,'ﲠ'=>1,'ﲡ'=>1,'ﲢ'=>1,'ﲣ'=>1,'ﲤ'=>1,'ﲥ'=>1,'ﲦ'=>1,'ﲧ'=>1,'ﲨ'=>1,'ﲩ'=>1,'ﲪ'=>1,'ﲫ'=>1,'ﲬ'=>1,'ﲭ'=>1,'ﲮ'=>1,'ﲯ'=>1,'ﲰ'=>1,'ﲱ'=>1,'ﲲ'=>1,'ﲳ'=>1,'ﲴ'=>1,'ﲵ'=>1,'ﲶ'=>1,'ﲷ'=>1,'ﲸ'=>1,'ﲹ'=>1,'ﲺ'=>1,'ﲻ'=>1,'ﲼ'=>1,'ﲽ'=>1,'ﲾ'=>1,'ﲿ'=>1,'ﳀ'=>1,'ﳁ'=>1,'ﳂ'=>1,'ﳃ'=>1,'ﳄ'=>1,'ﳅ'=>1,'ﳆ'=>1,'ﳇ'=>1,'ﳈ'=>1,'ﳉ'=>1,'ﳊ'=>1,'ﳋ'=>1,'ﳌ'=>1,'ﳍ'=>1,'ﳎ'=>1,'ﳏ'=>1,'ﳐ'=>1,'ﳑ'=>1,'ﳒ'=>1,'ﳓ'=>1,'ﳔ'=>1,'ﳕ'=>1,'ﳖ'=>1,'ﳗ'=>1,'ﳘ'=>1,'ﳙ'=>1,'ﳚ'=>1,'ﳛ'=>1,'ﳜ'=>1,'ﳝ'=>1,'ﳞ'=>1,'ﳟ'=>1,'ﳠ'=>1,'ﳡ'=>1,'ﳢ'=>1,'ﳣ'=>1,'ﳤ'=>1,'ﳥ'=>1,'ﳦ'=>1,'ﳧ'=>1,'ﳨ'=>1,'ﳩ'=>1,'ﳪ'=>1,'ﳫ'=>1,'ﳬ'=>1,'ﳭ'=>1,'ﳮ'=>1,'ﳯ'=>1,'ﳰ'=>1,'ﳱ'=>1,'ﳲ'=>1,'ﳳ'=>1,'ﳴ'=>1,'ﳵ'=>1,'ﳶ'=>1,'ﳷ'=>1,'ﳸ'=>1,'ﳹ'=>1,'ﳺ'=>1,'ﳻ'=>1,'ﳼ'=>1,'ﳽ'=>1,'ﳾ'=>1,'ﳿ'=>1,'ﴀ'=>1,'ﴁ'=>1,'ﴂ'=>1,'ﴃ'=>1,'ﴄ'=>1,'ﴅ'=>1,'ﴆ'=>1,'ﴇ'=>1,'ﴈ'=>1,'ﴉ'=>1,'ﴊ'=>1,'ﴋ'=>1,'ﴌ'=>1,'ﴍ'=>1,'ﴎ'=>1,'ﴏ'=>1,'ﴐ'=>1,'ﴑ'=>1,'ﴒ'=>1,'ﴓ'=>1,'ﴔ'=>1,'ﴕ'=>1,'ﴖ'=>1,'ﴗ'=>1,'ﴘ'=>1,'ﴙ'=>1,'ﴚ'=>1,'ﴛ'=>1,'ﴜ'=>1,'ﴝ'=>1,'ﴞ'=>1,'ﴟ'=>1,'ﴠ'=>1,'ﴡ'=>1,'ﴢ'=>1,'ﴣ'=>1,'ﴤ'=>1,'ﴥ'=>1,'ﴦ'=>1,'ﴧ'=>1,'ﴨ'=>1,'ﴩ'=>1,'ﴪ'=>1,'ﴫ'=>1,'ﴬ'=>1,'ﴭ'=>1,'ﴮ'=>1,'ﴯ'=>1,'ﴰ'=>1,'ﴱ'=>1,'ﴲ'=>1,'ﴳ'=>1,'ﴴ'=>1,'ﴵ'=>1,'ﴶ'=>1,'ﴷ'=>1,'ﴸ'=>1,'ﴹ'=>1,'ﴺ'=>1,'ﴻ'=>1,'ﴼ'=>1,'ﴽ'=>1,'ﵐ'=>1,'ﵑ'=>1,'ﵒ'=>1,'ﵓ'=>1,'ﵔ'=>1,'ﵕ'=>1,'ﵖ'=>1,'ﵗ'=>1,'ﵘ'=>1,'ﵙ'=>1,'ﵚ'=>1,'ﵛ'=>1,'ﵜ'=>1,'ﵝ'=>1,'ﵞ'=>1,'ﵟ'=>1,'ﵠ'=>1,'ﵡ'=>1,'ﵢ'=>1,'ﵣ'=>1,'ﵤ'=>1,'ﵥ'=>1,'ﵦ'=>1,'ﵧ'=>1,'ﵨ'=>1,'ﵩ'=>1,'ﵪ'=>1,'ﵫ'=>1,'ﵬ'=>1,'ﵭ'=>1,'ﵮ'=>1,'ﵯ'=>1,'ﵰ'=>1,'ﵱ'=>1,'ﵲ'=>1,'ﵳ'=>1,'ﵴ'=>1,'ﵵ'=>1,'ﵶ'=>1,'ﵷ'=>1,'ﵸ'=>1,'ﵹ'=>1,'ﵺ'=>1,'ﵻ'=>1,'ﵼ'=>1,'ﵽ'=>1,'ﵾ'=>1,'ﵿ'=>1,'ﶀ'=>1,'ﶁ'=>1,'ﶂ'=>1,'ﶃ'=>1,'ﶄ'=>1,'ﶅ'=>1,'ﶆ'=>1,'ﶇ'=>1,'ﶈ'=>1,'ﶉ'=>1,'ﶊ'=>1,'ﶋ'=>1,'ﶌ'=>1,'ﶍ'=>1,'ﶎ'=>1,'ﶏ'=>1,'ﶒ'=>1,'ﶓ'=>1,'ﶔ'=>1,'ﶕ'=>1,'ﶖ'=>1,'ﶗ'=>1,'ﶘ'=>1,'ﶙ'=>1,'ﶚ'=>1,'ﶛ'=>1,'ﶜ'=>1,'ﶝ'=>1,'ﶞ'=>1,'ﶟ'=>1,'ﶠ'=>1,'ﶡ'=>1,'ﶢ'=>1,'ﶣ'=>1,'ﶤ'=>1,'ﶥ'=>1,'ﶦ'=>1,'ﶧ'=>1,'ﶨ'=>1,'ﶩ'=>1,'ﶪ'=>1,'ﶫ'=>1,'ﶬ'=>1,'ﶭ'=>1,'ﶮ'=>1,'ﶯ'=>1,'ﶰ'=>1,'ﶱ'=>1,'ﶲ'=>1,'ﶳ'=>1,'ﶴ'=>1,'ﶵ'=>1,'ﶶ'=>1,'ﶷ'=>1,'ﶸ'=>1,'ﶹ'=>1,'ﶺ'=>1,'ﶻ'=>1,'ﶼ'=>1,'ﶽ'=>1,'ﶾ'=>1,'ﶿ'=>1,'ﷀ'=>1,'ﷁ'=>1,'ﷂ'=>1,'ﷃ'=>1,'ﷄ'=>1,'ﷅ'=>1,'ﷆ'=>1,'ﷇ'=>1,'ﷰ'=>1,'ﷱ'=>1,'ﷲ'=>1,'ﷳ'=>1,'ﷴ'=>1,'ﷵ'=>1,'ﷶ'=>1,'ﷷ'=>1,'ﷸ'=>1,'ﷹ'=>1,'ﷺ'=>1,'ﷻ'=>1,'﷼'=>1,'︐'=>1,'︑'=>1,'︒'=>1,'︓'=>1,'︔'=>1,'︕'=>1,'︖'=>1,'︗'=>1,'︘'=>1,'︙'=>1,'︰'=>1,'︱'=>1,'︲'=>1,'︳'=>1,'︴'=>1,'︵'=>1,'︶'=>1,'︷'=>1,'︸'=>1,'︹'=>1,'︺'=>1,'︻'=>1,'︼'=>1,'︽'=>1,'︾'=>1,'︿'=>1,'﹀'=>1,'﹁'=>1,'﹂'=>1,'﹃'=>1,'﹄'=>1,'﹇'=>1,'﹈'=>1,'﹉'=>1,'﹊'=>1,'﹋'=>1,'﹌'=>1,'﹍'=>1,'﹎'=>1,'﹏'=>1,'﹐'=>1,'﹑'=>1,'﹒'=>1,'﹔'=>1,'﹕'=>1,'﹖'=>1,'﹗'=>1,'﹘'=>1,'﹙'=>1,'﹚'=>1,'﹛'=>1,'﹜'=>1,'﹝'=>1,'﹞'=>1,'﹟'=>1,'﹠'=>1,'﹡'=>1,'﹢'=>1,'﹣'=>1,'﹤'=>1,'﹥'=>1,'﹦'=>1,'﹨'=>1,'﹩'=>1,'﹪'=>1,'﹫'=>1,'ﹰ'=>1,'ﹱ'=>1,'ﹲ'=>1,'ﹴ'=>1,'ﹶ'=>1,'ﹷ'=>1,'ﹸ'=>1,'ﹹ'=>1,'ﹺ'=>1,'ﹻ'=>1,'ﹼ'=>1,'ﹽ'=>1,'ﹾ'=>1,'ﹿ'=>1,'ﺀ'=>1,'ﺁ'=>1,'ﺂ'=>1,'ﺃ'=>1,'ﺄ'=>1,'ﺅ'=>1,'ﺆ'=>1,'ﺇ'=>1,'ﺈ'=>1,'ﺉ'=>1,'ﺊ'=>1,'ﺋ'=>1,'ﺌ'=>1,'ﺍ'=>1,'ﺎ'=>1,'ﺏ'=>1,'ﺐ'=>1,'ﺑ'=>1,'ﺒ'=>1,'ﺓ'=>1,'ﺔ'=>1,'ﺕ'=>1,'ﺖ'=>1,'ﺗ'=>1,'ﺘ'=>1,'ﺙ'=>1,'ﺚ'=>1,'ﺛ'=>1,'ﺜ'=>1,'ﺝ'=>1,'ﺞ'=>1,'ﺟ'=>1,'ﺠ'=>1,'ﺡ'=>1,'ﺢ'=>1,'ﺣ'=>1,'ﺤ'=>1,'ﺥ'=>1,'ﺦ'=>1,'ﺧ'=>1,'ﺨ'=>1,'ﺩ'=>1,'ﺪ'=>1,'ﺫ'=>1,'ﺬ'=>1,'ﺭ'=>1,'ﺮ'=>1,'ﺯ'=>1,'ﺰ'=>1,'ﺱ'=>1,'ﺲ'=>1,'ﺳ'=>1,'ﺴ'=>1,'ﺵ'=>1,'ﺶ'=>1,'ﺷ'=>1,'ﺸ'=>1,'ﺹ'=>1,'ﺺ'=>1,'ﺻ'=>1,'ﺼ'=>1,'ﺽ'=>1,'ﺾ'=>1,'ﺿ'=>1,'ﻀ'=>1,'ﻁ'=>1,'ﻂ'=>1,'ﻃ'=>1,'ﻄ'=>1,'ﻅ'=>1,'ﻆ'=>1,'ﻇ'=>1,'ﻈ'=>1,'ﻉ'=>1,'ﻊ'=>1,'ﻋ'=>1,'ﻌ'=>1,'ﻍ'=>1,'ﻎ'=>1,'ﻏ'=>1,'ﻐ'=>1,'ﻑ'=>1,'ﻒ'=>1,'ﻓ'=>1,'ﻔ'=>1,'ﻕ'=>1,'ﻖ'=>1,'ﻗ'=>1,'ﻘ'=>1,'ﻙ'=>1,'ﻚ'=>1,'ﻛ'=>1,'ﻜ'=>1,'ﻝ'=>1,'ﻞ'=>1,'ﻟ'=>1,'ﻠ'=>1,'ﻡ'=>1,'ﻢ'=>1,'ﻣ'=>1,'ﻤ'=>1,'ﻥ'=>1,'ﻦ'=>1,'ﻧ'=>1,'ﻨ'=>1,'ﻩ'=>1,'ﻪ'=>1,'ﻫ'=>1,'ﻬ'=>1,'ﻭ'=>1,'ﻮ'=>1,'ﻯ'=>1,'ﻰ'=>1,'ﻱ'=>1,'ﻲ'=>1,'ﻳ'=>1,'ﻴ'=>1,'ﻵ'=>1,'ﻶ'=>1,'ﻷ'=>1,'ﻸ'=>1,'ﻹ'=>1,'ﻺ'=>1,'ﻻ'=>1,'ﻼ'=>1,'!'=>1,'"'=>1,'#'=>1,'$'=>1,'%'=>1,'&'=>1,'''=>1,'('=>1,')'=>1,'*'=>1,'+'=>1,','=>1,'-'=>1,'.'=>1,'/'=>1,'0'=>1,'1'=>1,'2'=>1,'3'=>1,'4'=>1,'5'=>1,'6'=>1,'7'=>1,'8'=>1,'9'=>1,':'=>1,';'=>1,'<'=>1,'='=>1,'>'=>1,'?'=>1,'@'=>1,'A'=>1,'B'=>1,'C'=>1,'D'=>1,'E'=>1,'F'=>1,'G'=>1,'H'=>1,'I'=>1,'J'=>1,'K'=>1,'L'=>1,'M'=>1,'N'=>1,'O'=>1,'P'=>1,'Q'=>1,'R'=>1,'S'=>1,'T'=>1,'U'=>1,'V'=>1,'W'=>1,'X'=>1,'Y'=>1,'Z'=>1,'['=>1,'\'=>1,']'=>1,'^'=>1,'_'=>1,'`'=>1,'a'=>1,'b'=>1,'c'=>1,'d'=>1,'e'=>1,'f'=>1,'g'=>1,'h'=>1,'i'=>1,'j'=>1,'k'=>1,'l'=>1,'m'=>1,'n'=>1,'o'=>1,'p'=>1,'q'=>1,'r'=>1,'s'=>1,'t'=>1,'u'=>1,'v'=>1,'w'=>1,'x'=>1,'y'=>1,'z'=>1,'{'=>1,'|'=>1,'}'=>1,'~'=>1,'⦅'=>1,'⦆'=>1,'。'=>1,'「'=>1,'」'=>1,'、'=>1,'・'=>1,'ヲ'=>1,'ァ'=>1,'ィ'=>1,'ゥ'=>1,'ェ'=>1,'ォ'=>1,'ャ'=>1,'ュ'=>1,'ョ'=>1,'ッ'=>1,'ー'=>1,'ア'=>1,'イ'=>1,'ウ'=>1,'エ'=>1,'オ'=>1,'カ'=>1,'キ'=>1,'ク'=>1,'ケ'=>1,'コ'=>1,'サ'=>1,'シ'=>1,'ス'=>1,'セ'=>1,'ソ'=>1,'タ'=>1,'チ'=>1,'ツ'=>1,'テ'=>1,'ト'=>1,'ナ'=>1,'ニ'=>1,'ヌ'=>1,'ネ'=>1,'ノ'=>1,'ハ'=>1,'ヒ'=>1,'フ'=>1,'ヘ'=>1,'ホ'=>1,'マ'=>1,'ミ'=>1,'ム'=>1,'メ'=>1,'モ'=>1,'ヤ'=>1,'ユ'=>1,'ヨ'=>1,'ラ'=>1,'リ'=>1,'ル'=>1,'レ'=>1,'ロ'=>1,'ワ'=>1,'ン'=>1,'゙'=>1,'゚'=>1,'ᅠ'=>1,'ᄀ'=>1,'ᄁ'=>1,'ᆪ'=>1,'ᄂ'=>1,'ᆬ'=>1,'ᆭ'=>1,'ᄃ'=>1,'ᄄ'=>1,'ᄅ'=>1,'ᆰ'=>1,'ᆱ'=>1,'ᆲ'=>1,'ᆳ'=>1,'ᆴ'=>1,'ᆵ'=>1,'ᄚ'=>1,'ᄆ'=>1,'ᄇ'=>1,'ᄈ'=>1,'ᄡ'=>1,'ᄉ'=>1,'ᄊ'=>1,'ᄋ'=>1,'ᄌ'=>1,'ᄍ'=>1,'ᄎ'=>1,'ᄏ'=>1,'ᄐ'=>1,'ᄑ'=>1,'ᄒ'=>1,'ᅡ'=>1,'ᅢ'=>1,'ᅣ'=>1,'ᅤ'=>1,'ᅥ'=>1,'ᅦ'=>1,'ᅧ'=>1,'ᅨ'=>1,'ᅩ'=>1,'ᅪ'=>1,'ᅫ'=>1,'ᅬ'=>1,'ᅭ'=>1,'ᅮ'=>1,'ᅯ'=>1,'ᅰ'=>1,'ᅱ'=>1,'ᅲ'=>1,'ᅳ'=>1,'ᅴ'=>1,'ᅵ'=>1,'¢'=>1,'£'=>1,'¬'=>1,' ̄'=>1,'¦'=>1,'¥'=>1,'₩'=>1,'│'=>1,'←'=>1,'↑'=>1,'→'=>1,'↓'=>1,'■'=>1,'○'=>1,'𝅗𝅥'=>1,'𝅘𝅥'=>1,'𝅘𝅥𝅮'=>1,'𝅘𝅥𝅯'=>1,'𝅘𝅥𝅰'=>1,'𝅘𝅥𝅱'=>1,'𝅘𝅥𝅲'=>1,'𝆹𝅥'=>1,'𝆺𝅥'=>1,'𝆹𝅥𝅮'=>1,'𝆺𝅥𝅮'=>1,'𝆹𝅥𝅯'=>1,'𝆺𝅥𝅯'=>1,'𝐀'=>1,'𝐁'=>1,'𝐂'=>1,'𝐃'=>1,'𝐄'=>1,'𝐅'=>1,'𝐆'=>1,'𝐇'=>1,'𝐈'=>1,'𝐉'=>1,'𝐊'=>1,'𝐋'=>1,'𝐌'=>1,'𝐍'=>1,'𝐎'=>1,'𝐏'=>1,'𝐐'=>1,'𝐑'=>1,'𝐒'=>1,'𝐓'=>1,'𝐔'=>1,'𝐕'=>1,'𝐖'=>1,'𝐗'=>1,'𝐘'=>1,'𝐙'=>1,'𝐚'=>1,'𝐛'=>1,'𝐜'=>1,'𝐝'=>1,'𝐞'=>1,'𝐟'=>1,'𝐠'=>1,'𝐡'=>1,'𝐢'=>1,'𝐣'=>1,'𝐤'=>1,'𝐥'=>1,'𝐦'=>1,'𝐧'=>1,'𝐨'=>1,'𝐩'=>1,'𝐪'=>1,'𝐫'=>1,'𝐬'=>1,'𝐭'=>1,'𝐮'=>1,'𝐯'=>1,'𝐰'=>1,'𝐱'=>1,'𝐲'=>1,'𝐳'=>1,'𝐴'=>1,'𝐵'=>1,'𝐶'=>1,'𝐷'=>1,'𝐸'=>1,'𝐹'=>1,'𝐺'=>1,'𝐻'=>1,'𝐼'=>1,'𝐽'=>1,'𝐾'=>1,'𝐿'=>1,'𝑀'=>1,'𝑁'=>1,'𝑂'=>1,'𝑃'=>1,'𝑄'=>1,'𝑅'=>1,'𝑆'=>1,'𝑇'=>1,'𝑈'=>1,'𝑉'=>1,'𝑊'=>1,'𝑋'=>1,'𝑌'=>1,'𝑍'=>1,'𝑎'=>1,'𝑏'=>1,'𝑐'=>1,'𝑑'=>1,'𝑒'=>1,'𝑓'=>1,'𝑔'=>1,'𝑖'=>1,'𝑗'=>1,'𝑘'=>1,'𝑙'=>1,'𝑚'=>1,'𝑛'=>1,'𝑜'=>1,'𝑝'=>1,'𝑞'=>1,'𝑟'=>1,'𝑠'=>1,'𝑡'=>1,'𝑢'=>1,'𝑣'=>1,'𝑤'=>1,'𝑥'=>1,'𝑦'=>1,'𝑧'=>1,'𝑨'=>1,'𝑩'=>1,'𝑪'=>1,'𝑫'=>1,'𝑬'=>1,'𝑭'=>1,'𝑮'=>1,'𝑯'=>1,'𝑰'=>1,'𝑱'=>1,'𝑲'=>1,'𝑳'=>1,'𝑴'=>1,'𝑵'=>1,'𝑶'=>1,'𝑷'=>1,'𝑸'=>1,'𝑹'=>1,'𝑺'=>1,'𝑻'=>1,'𝑼'=>1,'𝑽'=>1,'𝑾'=>1,'𝑿'=>1,'𝒀'=>1,'𝒁'=>1,'𝒂'=>1,'𝒃'=>1,'𝒄'=>1,'𝒅'=>1,'𝒆'=>1,'𝒇'=>1,'𝒈'=>1,'𝒉'=>1,'𝒊'=>1,'𝒋'=>1,'𝒌'=>1,'𝒍'=>1,'𝒎'=>1,'𝒏'=>1,'𝒐'=>1,'𝒑'=>1,'𝒒'=>1,'𝒓'=>1,'𝒔'=>1,'𝒕'=>1,'𝒖'=>1,'𝒗'=>1,'𝒘'=>1,'𝒙'=>1,'𝒚'=>1,'𝒛'=>1,'𝒜'=>1,'𝒞'=>1,'𝒟'=>1,'𝒢'=>1,'𝒥'=>1,'𝒦'=>1,'𝒩'=>1,'𝒪'=>1,'𝒫'=>1,'𝒬'=>1,'𝒮'=>1,'𝒯'=>1,'𝒰'=>1,'𝒱'=>1,'𝒲'=>1,'𝒳'=>1,'𝒴'=>1,'𝒵'=>1,'𝒶'=>1,'𝒷'=>1,'𝒸'=>1,'𝒹'=>1,'𝒻'=>1,'𝒽'=>1,'𝒾'=>1,'𝒿'=>1,'𝓀'=>1,'𝓁'=>1,'𝓂'=>1,'𝓃'=>1,'𝓅'=>1,'𝓆'=>1,'𝓇'=>1,'𝓈'=>1,'𝓉'=>1,'𝓊'=>1,'𝓋'=>1,'𝓌'=>1,'𝓍'=>1,'𝓎'=>1,'𝓏'=>1,'𝓐'=>1,'𝓑'=>1,'𝓒'=>1,'𝓓'=>1,'𝓔'=>1,'𝓕'=>1,'𝓖'=>1,'𝓗'=>1,'𝓘'=>1,'𝓙'=>1,'𝓚'=>1,'𝓛'=>1,'𝓜'=>1,'𝓝'=>1,'𝓞'=>1,'𝓟'=>1,'𝓠'=>1,'𝓡'=>1,'𝓢'=>1,'𝓣'=>1,'𝓤'=>1,'𝓥'=>1,'𝓦'=>1,'𝓧'=>1,'𝓨'=>1,'𝓩'=>1,'𝓪'=>1,'𝓫'=>1,'𝓬'=>1,'𝓭'=>1,'𝓮'=>1,'𝓯'=>1,'𝓰'=>1,'𝓱'=>1,'𝓲'=>1,'𝓳'=>1,'𝓴'=>1,'𝓵'=>1,'𝓶'=>1,'𝓷'=>1,'𝓸'=>1,'𝓹'=>1,'𝓺'=>1,'𝓻'=>1,'𝓼'=>1,'𝓽'=>1,'𝓾'=>1,'𝓿'=>1,'𝔀'=>1,'𝔁'=>1,'𝔂'=>1,'𝔃'=>1,'𝔄'=>1,'𝔅'=>1,'𝔇'=>1,'𝔈'=>1,'𝔉'=>1,'𝔊'=>1,'𝔍'=>1,'𝔎'=>1,'𝔏'=>1,'𝔐'=>1,'𝔑'=>1,'𝔒'=>1,'𝔓'=>1,'𝔔'=>1,'𝔖'=>1,'𝔗'=>1,'𝔘'=>1,'𝔙'=>1,'𝔚'=>1,'𝔛'=>1,'𝔜'=>1,'𝔞'=>1,'𝔟'=>1,'𝔠'=>1,'𝔡'=>1,'𝔢'=>1,'𝔣'=>1,'𝔤'=>1,'𝔥'=>1,'𝔦'=>1,'𝔧'=>1,'𝔨'=>1,'𝔩'=>1,'𝔪'=>1,'𝔫'=>1,'𝔬'=>1,'𝔭'=>1,'𝔮'=>1,'𝔯'=>1,'𝔰'=>1,'𝔱'=>1,'𝔲'=>1,'𝔳'=>1,'𝔴'=>1,'𝔵'=>1,'𝔶'=>1,'𝔷'=>1,'𝔸'=>1,'𝔹'=>1,'𝔻'=>1,'𝔼'=>1,'𝔽'=>1,'𝔾'=>1,'𝕀'=>1,'𝕁'=>1,'𝕂'=>1,'𝕃'=>1,'𝕄'=>1,'𝕆'=>1,'𝕊'=>1,'𝕋'=>1,'𝕌'=>1,'𝕍'=>1,'𝕎'=>1,'𝕏'=>1,'𝕐'=>1,'𝕒'=>1,'𝕓'=>1,'𝕔'=>1,'𝕕'=>1,'𝕖'=>1,'𝕗'=>1,'𝕘'=>1,'𝕙'=>1,'𝕚'=>1,'𝕛'=>1,'𝕜'=>1,'𝕝'=>1,'𝕞'=>1,'𝕟'=>1,'𝕠'=>1,'𝕡'=>1,'𝕢'=>1,'𝕣'=>1,'𝕤'=>1,'𝕥'=>1,'𝕦'=>1,'𝕧'=>1,'𝕨'=>1,'𝕩'=>1,'𝕪'=>1,'𝕫'=>1,'𝕬'=>1,'𝕭'=>1,'𝕮'=>1,'𝕯'=>1,'𝕰'=>1,'𝕱'=>1,'𝕲'=>1,'𝕳'=>1,'𝕴'=>1,'𝕵'=>1,'𝕶'=>1,'𝕷'=>1,'𝕸'=>1,'𝕹'=>1,'𝕺'=>1,'𝕻'=>1,'𝕼'=>1,'𝕽'=>1,'𝕾'=>1,'𝕿'=>1,'𝖀'=>1,'𝖁'=>1,'𝖂'=>1,'𝖃'=>1,'𝖄'=>1,'𝖅'=>1,'𝖆'=>1,'𝖇'=>1,'𝖈'=>1,'𝖉'=>1,'𝖊'=>1,'𝖋'=>1,'𝖌'=>1,'𝖍'=>1,'𝖎'=>1,'𝖏'=>1,'𝖐'=>1,'𝖑'=>1,'𝖒'=>1,'𝖓'=>1,'𝖔'=>1,'𝖕'=>1,'𝖖'=>1,'𝖗'=>1,'𝖘'=>1,'𝖙'=>1,'𝖚'=>1,'𝖛'=>1,'𝖜'=>1,'𝖝'=>1,'𝖞'=>1,'𝖟'=>1,'𝖠'=>1,'𝖡'=>1,'𝖢'=>1,'𝖣'=>1,'𝖤'=>1,'𝖥'=>1,'𝖦'=>1,'𝖧'=>1,'𝖨'=>1,'𝖩'=>1,'𝖪'=>1,'𝖫'=>1,'𝖬'=>1,'𝖭'=>1,'𝖮'=>1,'𝖯'=>1,'𝖰'=>1,'𝖱'=>1,'𝖲'=>1,'𝖳'=>1,'𝖴'=>1,'𝖵'=>1,'𝖶'=>1,'𝖷'=>1,'𝖸'=>1,'𝖹'=>1,'𝖺'=>1,'𝖻'=>1,'𝖼'=>1,'𝖽'=>1,'𝖾'=>1,'𝖿'=>1,'𝗀'=>1,'𝗁'=>1,'𝗂'=>1,'𝗃'=>1,'𝗄'=>1,'𝗅'=>1,'𝗆'=>1,'𝗇'=>1,'𝗈'=>1,'𝗉'=>1,'𝗊'=>1,'𝗋'=>1,'𝗌'=>1,'𝗍'=>1,'𝗎'=>1,'𝗏'=>1,'𝗐'=>1,'𝗑'=>1,'𝗒'=>1,'𝗓'=>1,'𝗔'=>1,'𝗕'=>1,'𝗖'=>1,'𝗗'=>1,'𝗘'=>1,'𝗙'=>1,'𝗚'=>1,'𝗛'=>1,'𝗜'=>1,'𝗝'=>1,'𝗞'=>1,'𝗟'=>1,'𝗠'=>1,'𝗡'=>1,'𝗢'=>1,'𝗣'=>1,'𝗤'=>1,'𝗥'=>1,'𝗦'=>1,'𝗧'=>1,'𝗨'=>1,'𝗩'=>1,'𝗪'=>1,'𝗫'=>1,'𝗬'=>1,'𝗭'=>1,'𝗮'=>1,'𝗯'=>1,'𝗰'=>1,'𝗱'=>1,'𝗲'=>1,'𝗳'=>1,'𝗴'=>1,'𝗵'=>1,'𝗶'=>1,'𝗷'=>1,'𝗸'=>1,'𝗹'=>1,'𝗺'=>1,'𝗻'=>1,'𝗼'=>1,'𝗽'=>1,'𝗾'=>1,'𝗿'=>1,'𝘀'=>1,'𝘁'=>1,'𝘂'=>1,'𝘃'=>1,'𝘄'=>1,'𝘅'=>1,'𝘆'=>1,'𝘇'=>1,'𝘈'=>1,'𝘉'=>1,'𝘊'=>1,'𝘋'=>1,'𝘌'=>1,'𝘍'=>1,'𝘎'=>1,'𝘏'=>1,'𝘐'=>1,'𝘑'=>1,'𝘒'=>1,'𝘓'=>1,'𝘔'=>1,'𝘕'=>1,'𝘖'=>1,'𝘗'=>1,'𝘘'=>1,'𝘙'=>1,'𝘚'=>1,'𝘛'=>1,'𝘜'=>1,'𝘝'=>1,'𝘞'=>1,'𝘟'=>1,'𝘠'=>1,'𝘡'=>1,'𝘢'=>1,'𝘣'=>1,'𝘤'=>1,'𝘥'=>1,'𝘦'=>1,'𝘧'=>1,'𝘨'=>1,'𝘩'=>1,'𝘪'=>1,'𝘫'=>1,'𝘬'=>1,'𝘭'=>1,'𝘮'=>1,'𝘯'=>1,'𝘰'=>1,'𝘱'=>1,'𝘲'=>1,'𝘳'=>1,'𝘴'=>1,'𝘵'=>1,'𝘶'=>1,'𝘷'=>1,'𝘸'=>1,'𝘹'=>1,'𝘺'=>1,'𝘻'=>1,'𝘼'=>1,'𝘽'=>1,'𝘾'=>1,'𝘿'=>1,'𝙀'=>1,'𝙁'=>1,'𝙂'=>1,'𝙃'=>1,'𝙄'=>1,'𝙅'=>1,'𝙆'=>1,'𝙇'=>1,'𝙈'=>1,'𝙉'=>1,'𝙊'=>1,'𝙋'=>1,'𝙌'=>1,'𝙍'=>1,'𝙎'=>1,'𝙏'=>1,'𝙐'=>1,'𝙑'=>1,'𝙒'=>1,'𝙓'=>1,'𝙔'=>1,'𝙕'=>1,'𝙖'=>1,'𝙗'=>1,'𝙘'=>1,'𝙙'=>1,'𝙚'=>1,'𝙛'=>1,'𝙜'=>1,'𝙝'=>1,'𝙞'=>1,'𝙟'=>1,'𝙠'=>1,'𝙡'=>1,'𝙢'=>1,'𝙣'=>1,'𝙤'=>1,'𝙥'=>1,'𝙦'=>1,'𝙧'=>1,'𝙨'=>1,'𝙩'=>1,'𝙪'=>1,'𝙫'=>1,'𝙬'=>1,'𝙭'=>1,'𝙮'=>1,'𝙯'=>1,'𝙰'=>1,'𝙱'=>1,'𝙲'=>1,'𝙳'=>1,'𝙴'=>1,'𝙵'=>1,'𝙶'=>1,'𝙷'=>1,'𝙸'=>1,'𝙹'=>1,'𝙺'=>1,'𝙻'=>1,'𝙼'=>1,'𝙽'=>1,'𝙾'=>1,'𝙿'=>1,'𝚀'=>1,'𝚁'=>1,'𝚂'=>1,'𝚃'=>1,'𝚄'=>1,'𝚅'=>1,'𝚆'=>1,'𝚇'=>1,'𝚈'=>1,'𝚉'=>1,'𝚊'=>1,'𝚋'=>1,'𝚌'=>1,'𝚍'=>1,'𝚎'=>1,'𝚏'=>1,'𝚐'=>1,'𝚑'=>1,'𝚒'=>1,'𝚓'=>1,'𝚔'=>1,'𝚕'=>1,'𝚖'=>1,'𝚗'=>1,'𝚘'=>1,'𝚙'=>1,'𝚚'=>1,'𝚛'=>1,'𝚜'=>1,'𝚝'=>1,'𝚞'=>1,'𝚟'=>1,'𝚠'=>1,'𝚡'=>1,'𝚢'=>1,'𝚣'=>1,'𝚤'=>1,'𝚥'=>1,'𝚨'=>1,'𝚩'=>1,'𝚪'=>1,'𝚫'=>1,'𝚬'=>1,'𝚭'=>1,'𝚮'=>1,'𝚯'=>1,'𝚰'=>1,'𝚱'=>1,'𝚲'=>1,'𝚳'=>1,'𝚴'=>1,'𝚵'=>1,'𝚶'=>1,'𝚷'=>1,'𝚸'=>1,'𝚹'=>1,'𝚺'=>1,'𝚻'=>1,'𝚼'=>1,'𝚽'=>1,'𝚾'=>1,'𝚿'=>1,'𝛀'=>1,'𝛁'=>1,'𝛂'=>1,'𝛃'=>1,'𝛄'=>1,'𝛅'=>1,'𝛆'=>1,'𝛇'=>1,'𝛈'=>1,'𝛉'=>1,'𝛊'=>1,'𝛋'=>1,'𝛌'=>1,'𝛍'=>1,'𝛎'=>1,'𝛏'=>1,'𝛐'=>1,'𝛑'=>1,'𝛒'=>1,'𝛓'=>1,'𝛔'=>1,'𝛕'=>1,'𝛖'=>1,'𝛗'=>1,'𝛘'=>1,'𝛙'=>1,'𝛚'=>1,'𝛛'=>1,'𝛜'=>1,'𝛝'=>1,'𝛞'=>1,'𝛟'=>1,'𝛠'=>1,'𝛡'=>1,'𝛢'=>1,'𝛣'=>1,'𝛤'=>1,'𝛥'=>1,'𝛦'=>1,'𝛧'=>1,'𝛨'=>1,'𝛩'=>1,'𝛪'=>1,'𝛫'=>1,'𝛬'=>1,'𝛭'=>1,'𝛮'=>1,'𝛯'=>1,'𝛰'=>1,'𝛱'=>1,'𝛲'=>1,'𝛳'=>1,'𝛴'=>1,'𝛵'=>1,'𝛶'=>1,'𝛷'=>1,'𝛸'=>1,'𝛹'=>1,'𝛺'=>1,'𝛻'=>1,'𝛼'=>1,'𝛽'=>1,'𝛾'=>1,'𝛿'=>1,'𝜀'=>1,'𝜁'=>1,'𝜂'=>1,'𝜃'=>1,'𝜄'=>1,'𝜅'=>1,'𝜆'=>1,'𝜇'=>1,'𝜈'=>1,'𝜉'=>1,'𝜊'=>1,'𝜋'=>1,'𝜌'=>1,'𝜍'=>1,'𝜎'=>1,'𝜏'=>1,'𝜐'=>1,'𝜑'=>1,'𝜒'=>1,'𝜓'=>1,'𝜔'=>1,'𝜕'=>1,'𝜖'=>1,'𝜗'=>1,'𝜘'=>1,'𝜙'=>1,'𝜚'=>1,'𝜛'=>1,'𝜜'=>1,'𝜝'=>1,'𝜞'=>1,'𝜟'=>1,'𝜠'=>1,'𝜡'=>1,'𝜢'=>1,'𝜣'=>1,'𝜤'=>1,'𝜥'=>1,'𝜦'=>1,'𝜧'=>1,'𝜨'=>1,'𝜩'=>1,'𝜪'=>1,'𝜫'=>1,'𝜬'=>1,'𝜭'=>1,'𝜮'=>1,'𝜯'=>1,'𝜰'=>1,'𝜱'=>1,'𝜲'=>1,'𝜳'=>1,'𝜴'=>1,'𝜵'=>1,'𝜶'=>1,'𝜷'=>1,'𝜸'=>1,'𝜹'=>1,'𝜺'=>1,'𝜻'=>1,'𝜼'=>1,'𝜽'=>1,'𝜾'=>1,'𝜿'=>1,'𝝀'=>1,'𝝁'=>1,'𝝂'=>1,'𝝃'=>1,'𝝄'=>1,'𝝅'=>1,'𝝆'=>1,'𝝇'=>1,'𝝈'=>1,'𝝉'=>1,'𝝊'=>1,'𝝋'=>1,'𝝌'=>1,'𝝍'=>1,'𝝎'=>1,'𝝏'=>1,'𝝐'=>1,'𝝑'=>1,'𝝒'=>1,'𝝓'=>1,'𝝔'=>1,'𝝕'=>1,'𝝖'=>1,'𝝗'=>1,'𝝘'=>1,'𝝙'=>1,'𝝚'=>1,'𝝛'=>1,'𝝜'=>1,'𝝝'=>1,'𝝞'=>1,'𝝟'=>1,'𝝠'=>1,'𝝡'=>1,'𝝢'=>1,'𝝣'=>1,'𝝤'=>1,'𝝥'=>1,'𝝦'=>1,'𝝧'=>1,'𝝨'=>1,'𝝩'=>1,'𝝪'=>1,'𝝫'=>1,'𝝬'=>1,'𝝭'=>1,'𝝮'=>1,'𝝯'=>1,'𝝰'=>1,'𝝱'=>1,'𝝲'=>1,'𝝳'=>1,'𝝴'=>1,'𝝵'=>1,'𝝶'=>1,'𝝷'=>1,'𝝸'=>1,'𝝹'=>1,'𝝺'=>1,'𝝻'=>1,'𝝼'=>1,'𝝽'=>1,'𝝾'=>1,'𝝿'=>1,'𝞀'=>1,'𝞁'=>1,'𝞂'=>1,'𝞃'=>1,'𝞄'=>1,'𝞅'=>1,'𝞆'=>1,'𝞇'=>1,'𝞈'=>1,'𝞉'=>1,'𝞊'=>1,'𝞋'=>1,'𝞌'=>1,'𝞍'=>1,'𝞎'=>1,'𝞏'=>1,'𝞐'=>1,'𝞑'=>1,'𝞒'=>1,'𝞓'=>1,'𝞔'=>1,'𝞕'=>1,'𝞖'=>1,'𝞗'=>1,'𝞘'=>1,'𝞙'=>1,'𝞚'=>1,'𝞛'=>1,'𝞜'=>1,'𝞝'=>1,'𝞞'=>1,'𝞟'=>1,'𝞠'=>1,'𝞡'=>1,'𝞢'=>1,'𝞣'=>1,'𝞤'=>1,'𝞥'=>1,'𝞦'=>1,'𝞧'=>1,'𝞨'=>1,'𝞩'=>1,'𝞪'=>1,'𝞫'=>1,'𝞬'=>1,'𝞭'=>1,'𝞮'=>1,'𝞯'=>1,'𝞰'=>1,'𝞱'=>1,'𝞲'=>1,'𝞳'=>1,'𝞴'=>1,'𝞵'=>1,'𝞶'=>1,'𝞷'=>1,'𝞸'=>1,'𝞹'=>1,'𝞺'=>1,'𝞻'=>1,'𝞼'=>1,'𝞽'=>1,'𝞾'=>1,'𝞿'=>1,'𝟀'=>1,'𝟁'=>1,'𝟂'=>1,'𝟃'=>1,'𝟄'=>1,'𝟅'=>1,'𝟆'=>1,'𝟇'=>1,'𝟈'=>1,'𝟉'=>1,'𝟊'=>1,'𝟋'=>1,'𝟎'=>1,'𝟏'=>1,'𝟐'=>1,'𝟑'=>1,'𝟒'=>1,'𝟓'=>1,'𝟔'=>1,'𝟕'=>1,'𝟖'=>1,'𝟗'=>1,'𝟘'=>1,'𝟙'=>1,'𝟚'=>1,'𝟛'=>1,'𝟜'=>1,'𝟝'=>1,'𝟞'=>1,'𝟟'=>1,'𝟠'=>1,'𝟡'=>1,'𝟢'=>1,'𝟣'=>1,'𝟤'=>1,'𝟥'=>1,'𝟦'=>1,'𝟧'=>1,'𝟨'=>1,'𝟩'=>1,'𝟪'=>1,'𝟫'=>1,'𝟬'=>1,'𝟭'=>1,'𝟮'=>1,'𝟯'=>1,'𝟰'=>1,'𝟱'=>1,'𝟲'=>1,'𝟳'=>1,'𝟴'=>1,'𝟵'=>1,'𝟶'=>1,'𝟷'=>1,'𝟸'=>1,'𝟹'=>1,'𝟺'=>1,'𝟻'=>1,'𝟼'=>1,'𝟽'=>1,'𝟾'=>1,'𝟿'=>1,'丽'=>1,'丸'=>1,'乁'=>1,'𠄢'=>1,'你'=>1,'侮'=>1,'侻'=>1,'倂'=>1,'偺'=>1,'備'=>1,'僧'=>1,'像'=>1,'㒞'=>1,'𠘺'=>1,'免'=>1,'兔'=>1,'兤'=>1,'具'=>1,'𠔜'=>1,'㒹'=>1,'內'=>1,'再'=>1,'𠕋'=>1,'冗'=>1,'冤'=>1,'仌'=>1,'冬'=>1,'况'=>1,'𩇟'=>1,'凵'=>1,'刃'=>1,'㓟'=>1,'刻'=>1,'剆'=>1,'割'=>1,'剷'=>1,'㔕'=>1,'勇'=>1,'勉'=>1,'勤'=>1,'勺'=>1,'包'=>1,'匆'=>1,'北'=>1,'卉'=>1,'卑'=>1,'博'=>1,'即'=>1,'卽'=>1,'卿'=>1,'卿'=>1,'卿'=>1,'𠨬'=>1,'灰'=>1,'及'=>1,'叟'=>1,'𠭣'=>1,'叫'=>1,'叱'=>1,'吆'=>1,'咞'=>1,'吸'=>1,'呈'=>1,'周'=>1,'咢'=>1,'哶'=>1,'唐'=>1,'啓'=>1,'啣'=>1,'善'=>1,'善'=>1,'喙'=>1,'喫'=>1,'喳'=>1,'嗂'=>1,'圖'=>1,'嘆'=>1,'圗'=>1,'噑'=>1,'噴'=>1,'切'=>1,'壮'=>1,'城'=>1,'埴'=>1,'堍'=>1,'型'=>1,'堲'=>1,'報'=>1,'墬'=>1,'𡓤'=>1,'売'=>1,'壷'=>1,'夆'=>1,'多'=>1,'夢'=>1,'奢'=>1,'𡚨'=>1,'𡛪'=>1,'姬'=>1,'娛'=>1,'娧'=>1,'姘'=>1,'婦'=>1,'㛮'=>1,'㛼'=>1,'嬈'=>1,'嬾'=>1,'嬾'=>1,'𡧈'=>1,'寃'=>1,'寘'=>1,'寧'=>1,'寳'=>1,'𡬘'=>1,'寿'=>1,'将'=>1,'当'=>1,'尢'=>1,'㞁'=>1,'屠'=>1,'屮'=>1,'峀'=>1,'岍'=>1,'𡷤'=>1,'嵃'=>1,'𡷦'=>1,'嵮'=>1,'嵫'=>1,'嵼'=>1,'巡'=>1,'巢'=>1,'㠯'=>1,'巽'=>1,'帨'=>1,'帽'=>1,'幩'=>1,'㡢'=>1,'𢆃'=>1,'㡼'=>1,'庰'=>1,'庳'=>1,'庶'=>1,'廊'=>1,'𪎒'=>1,'廾'=>1,'𢌱'=>1,'𢌱'=>1,'舁'=>1,'弢'=>1,'弢'=>1,'㣇'=>1,'𣊸'=>1,'𦇚'=>1,'形'=>1,'彫'=>1,'㣣'=>1,'徚'=>1,'忍'=>1,'志'=>1,'忹'=>1,'悁'=>1,'㤺'=>1,'㤜'=>1,'悔'=>1,'𢛔'=>1,'惇'=>1,'慈'=>1,'慌'=>1,'慎'=>1,'慌'=>1,'慺'=>1,'憎'=>1,'憲'=>1,'憤'=>1,'憯'=>1,'懞'=>1,'懲'=>1,'懶'=>1,'成'=>1,'戛'=>1,'扝'=>1,'抱'=>1,'拔'=>1,'捐'=>1,'𢬌'=>1,'挽'=>1,'拼'=>1,'捨'=>1,'掃'=>1,'揤'=>1,'𢯱'=>1,'搢'=>1,'揅'=>1,'掩'=>1,'㨮'=>1,'摩'=>1,'摾'=>1,'撝'=>1,'摷'=>1,'㩬'=>1,'敏'=>1,'敬'=>1,'𣀊'=>1,'旣'=>1,'書'=>1,'晉'=>1,'㬙'=>1,'暑'=>1,'㬈'=>1,'㫤'=>1,'冒'=>1,'冕'=>1,'最'=>1,'暜'=>1,'肭'=>1,'䏙'=>1,'朗'=>1,'望'=>1,'朡'=>1,'杞'=>1,'杓'=>1,'𣏃'=>1,'㭉'=>1,'柺'=>1,'枅'=>1,'桒'=>1,'梅'=>1,'𣑭'=>1,'梎'=>1,'栟'=>1,'椔'=>1,'㮝'=>1,'楂'=>1,'榣'=>1,'槪'=>1,'檨'=>1,'𣚣'=>1,'櫛'=>1,'㰘'=>1,'次'=>1,'𣢧'=>1,'歔'=>1,'㱎'=>1,'歲'=>1,'殟'=>1,'殺'=>1,'殻'=>1,'𣪍'=>1,'𡴋'=>1,'𣫺'=>1,'汎'=>1,'𣲼'=>1,'沿'=>1,'泍'=>1,'汧'=>1,'洖'=>1,'派'=>1,'海'=>1,'流'=>1,'浩'=>1,'浸'=>1,'涅'=>1,'𣴞'=>1,'洴'=>1,'港'=>1,'湮'=>1,'㴳'=>1,'滋'=>1,'滇'=>1,'𣻑'=>1,'淹'=>1,'潮'=>1,'𣽞'=>1,'𣾎'=>1,'濆'=>1,'瀹'=>1,'瀞'=>1,'瀛'=>1,'㶖'=>1,'灊'=>1,'災'=>1,'灷'=>1,'炭'=>1,'𠔥'=>1,'煅'=>1,'𤉣'=>1,'熜'=>1,'𤎫'=>1,'爨'=>1,'爵'=>1,'牐'=>1,'𤘈'=>1,'犀'=>1,'犕'=>1,'𤜵'=>1,'𤠔'=>1,'獺'=>1,'王'=>1,'㺬'=>1,'玥'=>1,'㺸'=>1,'㺸'=>1,'瑇'=>1,'瑜'=>1,'瑱'=>1,'璅'=>1,'瓊'=>1,'㼛'=>1,'甤'=>1,'𤰶'=>1,'甾'=>1,'𤲒'=>1,'異'=>1,'𢆟'=>1,'瘐'=>1,'𤾡'=>1,'𤾸'=>1,'𥁄'=>1,'㿼'=>1,'䀈'=>1,'直'=>1,'𥃳'=>1,'𥃲'=>1,'𥄙'=>1,'𥄳'=>1,'眞'=>1,'真'=>1,'真'=>1,'睊'=>1,'䀹'=>1,'瞋'=>1,'䁆'=>1,'䂖'=>1,'𥐝'=>1,'硎'=>1,'碌'=>1,'磌'=>1,'䃣'=>1,'𥘦'=>1,'祖'=>1,'𥚚'=>1,'𥛅'=>1,'福'=>1,'秫'=>1,'䄯'=>1,'穀'=>1,'穊'=>1,'穏'=>1,'𥥼'=>1,'𥪧'=>1,'𥪧'=>1,'竮'=>1,'䈂'=>1,'𥮫'=>1,'篆'=>1,'築'=>1,'䈧'=>1,'𥲀'=>1,'糒'=>1,'䊠'=>1,'糨'=>1,'糣'=>1,'紀'=>1,'𥾆'=>1,'絣'=>1,'䌁'=>1,'緇'=>1,'縂'=>1,'繅'=>1,'䌴'=>1,'𦈨'=>1,'𦉇'=>1,'䍙'=>1,'𦋙'=>1,'罺'=>1,'𦌾'=>1,'羕'=>1,'翺'=>1,'者'=>1,'𦓚'=>1,'𦔣'=>1,'聠'=>1,'𦖨'=>1,'聰'=>1,'𣍟'=>1,'䏕'=>1,'育'=>1,'脃'=>1,'䐋'=>1,'脾'=>1,'媵'=>1,'𦞧'=>1,'𦞵'=>1,'𣎓'=>1,'𣎜'=>1,'舁'=>1,'舄'=>1,'辞'=>1,'䑫'=>1,'芑'=>1,'芋'=>1,'芝'=>1,'劳'=>1,'花'=>1,'芳'=>1,'芽'=>1,'苦'=>1,'𦬼'=>1,'若'=>1,'茝'=>1,'荣'=>1,'莭'=>1,'茣'=>1,'莽'=>1,'菧'=>1,'著'=>1,'荓'=>1,'菊'=>1,'菌'=>1,'菜'=>1,'𦰶'=>1,'𦵫'=>1,'𦳕'=>1,'䔫'=>1,'蓱'=>1,'蓳'=>1,'蔖'=>1,'𧏊'=>1,'蕤'=>1,'𦼬'=>1,'䕝'=>1,'䕡'=>1,'𦾱'=>1,'𧃒'=>1,'䕫'=>1,'虐'=>1,'虜'=>1,'虧'=>1,'虩'=>1,'蚩'=>1,'蚈'=>1,'蜎'=>1,'蛢'=>1,'蝹'=>1,'蜨'=>1,'蝫'=>1,'螆'=>1,'䗗'=>1,'蟡'=>1,'蠁'=>1,'䗹'=>1,'衠'=>1,'衣'=>1,'𧙧'=>1,'裗'=>1,'裞'=>1,'䘵'=>1,'裺'=>1,'㒻'=>1,'𧢮'=>1,'𧥦'=>1,'䚾'=>1,'䛇'=>1,'誠'=>1,'諭'=>1,'變'=>1,'豕'=>1,'𧲨'=>1,'貫'=>1,'賁'=>1,'贛'=>1,'起'=>1,'𧼯'=>1,'𠠄'=>1,'跋'=>1,'趼'=>1,'跰'=>1,'𠣞'=>1,'軔'=>1,'輸'=>1,'𨗒'=>1,'𨗭'=>1,'邔'=>1,'郱'=>1,'鄑'=>1,'𨜮'=>1,'鄛'=>1,'鈸'=>1,'鋗'=>1,'鋘'=>1,'鉼'=>1,'鏹'=>1,'鐕'=>1,'𨯺'=>1,'開'=>1,'䦕'=>1,'閷'=>1,'𨵷'=>1,'䧦'=>1,'雃'=>1,'嶲'=>1,'霣'=>1,'𩅅'=>1,'𩈚'=>1,'䩮'=>1,'䩶'=>1,'韠'=>1,'𩐊'=>1,'䪲'=>1,'𩒖'=>1,'頋'=>1,'頋'=>1,'頩'=>1,'𩖶'=>1,'飢'=>1,'䬳'=>1,'餩'=>1,'馧'=>1,'駂'=>1,'駾'=>1,'䯎'=>1,'𩬰'=>1,'鬒'=>1,'鱀'=>1,'鳽'=>1,'䳎'=>1,'䳭'=>1,'鵧'=>1,'𪃎'=>1,'䳸'=>1,'𪄅'=>1,'𪈎'=>1,'𪊑'=>1,'麻'=>1,'䵖'=>1,'黹'=>1,'黾'=>1,'鼅'=>1,'鼏'=>1,'鼖'=>1,'鼻'=>1,'𪘀'=>1,'̀'=>0,'́'=>0,'̂'=>0,'̃'=>0,'̄'=>0,'̆'=>0,'̇'=>0,'̈'=>0,'̉'=>0,'̊'=>0,'̋'=>0,'̌'=>0,'̏'=>0,'̑'=>0,'̓'=>0,'̔'=>0,'̛'=>0,'̣'=>0,'̤'=>0,'̥'=>0,'̦'=>0,'̧'=>0,'̨'=>0,'̭'=>0,'̮'=>0,'̰'=>0,'̱'=>0,'̸'=>0,'͂'=>0,'ͅ'=>0,'ٓ'=>0,'ٔ'=>0,'ٕ'=>0,'़'=>0,'া'=>0,'ৗ'=>0,'ା'=>0,'ୖ'=>0,'ୗ'=>0,'ா'=>0,'ௗ'=>0,'ౖ'=>0,'ೂ'=>0,'ೕ'=>0,'ೖ'=>0,'ാ'=>0,'ൗ'=>0,'්'=>0,'ා'=>0,'ෟ'=>0,'ီ'=>0,'ᅡ'=>0,'ᅢ'=>0,'ᅣ'=>0,'ᅤ'=>0,'ᅥ'=>0,'ᅦ'=>0,'ᅧ'=>0,'ᅨ'=>0,'ᅩ'=>0,'ᅪ'=>0,'ᅫ'=>0,'ᅬ'=>0,'ᅭ'=>0,'ᅮ'=>0,'ᅯ'=>0,'ᅰ'=>0,'ᅱ'=>0,'ᅲ'=>0,'ᅳ'=>0,'ᅴ'=>0,'ᅵ'=>0,'ᆨ'=>0,'ᆩ'=>0,'ᆪ'=>0,'ᆫ'=>0,'ᆬ'=>0,'ᆭ'=>0,'ᆮ'=>0,'ᆯ'=>0,'ᆰ'=>0,'ᆱ'=>0,'ᆲ'=>0,'ᆳ'=>0,'ᆴ'=>0,'ᆵ'=>0,'ᆶ'=>0,'ᆷ'=>0,'ᆸ'=>0,'ᆹ'=>0,'ᆺ'=>0,'ᆻ'=>0,'ᆼ'=>0,'ᆽ'=>0,'ᆾ'=>0,'ᆿ'=>0,'ᇀ'=>0,'ᇁ'=>0,'ᇂ'=>0,'ᬵ'=>0,'゙'=>0,'゚'=>0); diff --git a/phpBB/includes/utf/data/utf_normalizer_common.php b/phpBB/includes/utf/data/utf_normalizer_common.php index befc17d410..2eb7feac69 100644 --- a/phpBB/includes/utf/data/utf_normalizer_common.php +++ b/phpBB/includes/utf/data/utf_normalizer_common.php @@ -1,4 +1,4 @@ <?php $GLOBALS['utf_jamo_index']=array('ᄀ'=>44032,'ᄁ'=>44620,'ᄂ'=>45208,'ᄃ'=>45796,'ᄄ'=>46384,'ᄅ'=>46972,'ᄆ'=>47560,'ᄇ'=>48148,'ᄈ'=>48736,'ᄉ'=>49324,'ᄊ'=>49912,'ᄋ'=>50500,'ᄌ'=>51088,'ᄍ'=>51676,'ᄎ'=>52264,'ᄏ'=>52852,'ᄐ'=>53440,'ᄑ'=>54028,'ᄒ'=>54616,'ᅡ'=>0,'ᅢ'=>28,'ᅣ'=>56,'ᅤ'=>84,'ᅥ'=>112,'ᅦ'=>140,'ᅧ'=>168,'ᅨ'=>196,'ᅩ'=>224,'ᅪ'=>252,'ᅫ'=>280,'ᅬ'=>308,'ᅭ'=>336,'ᅮ'=>364,'ᅯ'=>392,'ᅰ'=>420,'ᅱ'=>448,'ᅲ'=>476,'ᅳ'=>504,'ᅴ'=>532,'ᅵ'=>560,'ᆧ'=>0,'ᆨ'=>1,'ᆩ'=>2,'ᆪ'=>3,'ᆫ'=>4,'ᆬ'=>5,'ᆭ'=>6,'ᆮ'=>7,'ᆯ'=>8,'ᆰ'=>9,'ᆱ'=>10,'ᆲ'=>11,'ᆳ'=>12,'ᆴ'=>13,'ᆵ'=>14,'ᆶ'=>15,'ᆷ'=>16,'ᆸ'=>17,'ᆹ'=>18,'ᆺ'=>19,'ᆻ'=>20,'ᆼ'=>21,'ᆽ'=>22,'ᆾ'=>23,'ᆿ'=>24,'ᇀ'=>25,'ᇁ'=>26,'ᇂ'=>27); $GLOBALS['utf_jamo_type']=array('ᄀ'=>0,'ᄁ'=>0,'ᄂ'=>0,'ᄃ'=>0,'ᄄ'=>0,'ᄅ'=>0,'ᄆ'=>0,'ᄇ'=>0,'ᄈ'=>0,'ᄉ'=>0,'ᄊ'=>0,'ᄋ'=>0,'ᄌ'=>0,'ᄍ'=>0,'ᄎ'=>0,'ᄏ'=>0,'ᄐ'=>0,'ᄑ'=>0,'ᄒ'=>0,'ᅡ'=>1,'ᅢ'=>1,'ᅣ'=>1,'ᅤ'=>1,'ᅥ'=>1,'ᅦ'=>1,'ᅧ'=>1,'ᅨ'=>1,'ᅩ'=>1,'ᅪ'=>1,'ᅫ'=>1,'ᅬ'=>1,'ᅭ'=>1,'ᅮ'=>1,'ᅯ'=>1,'ᅰ'=>1,'ᅱ'=>1,'ᅲ'=>1,'ᅳ'=>1,'ᅴ'=>1,'ᅵ'=>1,'ᆧ'=>2,'ᆨ'=>2,'ᆩ'=>2,'ᆪ'=>2,'ᆫ'=>2,'ᆬ'=>2,'ᆭ'=>2,'ᆮ'=>2,'ᆯ'=>2,'ᆰ'=>2,'ᆱ'=>2,'ᆲ'=>2,'ᆳ'=>2,'ᆴ'=>2,'ᆵ'=>2,'ᆶ'=>2,'ᆷ'=>2,'ᆸ'=>2,'ᆹ'=>2,'ᆺ'=>2,'ᆻ'=>2,'ᆼ'=>2,'ᆽ'=>2,'ᆾ'=>2,'ᆿ'=>2,'ᇀ'=>2,'ᇁ'=>2,'ᇂ'=>2); -$GLOBALS['utf_combining_class']=array('̀'=>230,'́'=>230,'̂'=>230,'̃'=>230,'̄'=>230,'̅'=>230,'̆'=>230,'̇'=>230,'̈'=>230,'̉'=>230,'̊'=>230,'̋'=>230,'̌'=>230,'̍'=>230,'̎'=>230,'̏'=>230,'̐'=>230,'̑'=>230,'̒'=>230,'̓'=>230,'̔'=>230,'̕'=>232,'̖'=>220,'̗'=>220,'̘'=>220,'̙'=>220,'̚'=>232,'̛'=>216,'̜'=>220,'̝'=>220,'̞'=>220,'̟'=>220,'̠'=>220,'̡'=>202,'̢'=>202,'̣'=>220,'̤'=>220,'̥'=>220,'̦'=>220,'̧'=>202,'̨'=>202,'̩'=>220,'̪'=>220,'̫'=>220,'̬'=>220,'̭'=>220,'̮'=>220,'̯'=>220,'̰'=>220,'̱'=>220,'̲'=>220,'̳'=>220,'̴'=>1,'̵'=>1,'̶'=>1,'̷'=>1,'̸'=>1,'̹'=>220,'̺'=>220,'̻'=>220,'̼'=>220,'̽'=>230,'̾'=>230,'̿'=>230,'̀'=>230,'́'=>230,'͂'=>230,'̓'=>230,'̈́'=>230,'ͅ'=>240,'͆'=>230,'͇'=>220,'͈'=>220,'͉'=>220,'͊'=>230,'͋'=>230,'͌'=>230,'͍'=>220,'͎'=>220,'͐'=>230,'͑'=>230,'͒'=>230,'͓'=>220,'͔'=>220,'͕'=>220,'͖'=>220,'͗'=>230,'͘'=>232,'͙'=>220,'͚'=>220,'͛'=>230,'͜'=>233,'͝'=>234,'͞'=>234,'͟'=>233,'͠'=>234,'͡'=>234,'͢'=>233,'ͣ'=>230,'ͤ'=>230,'ͥ'=>230,'ͦ'=>230,'ͧ'=>230,'ͨ'=>230,'ͩ'=>230,'ͪ'=>230,'ͫ'=>230,'ͬ'=>230,'ͭ'=>230,'ͮ'=>230,'ͯ'=>230,'҃'=>230,'҄'=>230,'҅'=>230,'҆'=>230,'֑'=>220,'֒'=>230,'֓'=>230,'֔'=>230,'֕'=>230,'֖'=>220,'֗'=>230,'֘'=>230,'֙'=>230,'֚'=>222,'֛'=>220,'֜'=>230,'֝'=>230,'֞'=>230,'֟'=>230,'֠'=>230,'֡'=>230,'֢'=>220,'֣'=>220,'֤'=>220,'֥'=>220,'֦'=>220,'֧'=>220,'֨'=>230,'֩'=>230,'֪'=>220,'֫'=>230,'֬'=>230,'֭'=>222,'֮'=>228,'֯'=>230,'ְ'=>10,'ֱ'=>11,'ֲ'=>12,'ֳ'=>13,'ִ'=>14,'ֵ'=>15,'ֶ'=>16,'ַ'=>17,'ָ'=>18,'ֹ'=>19,'ֺ'=>19,'ֻ'=>20,'ּ'=>21,'ֽ'=>22,'ֿ'=>23,'ׁ'=>24,'ׂ'=>25,'ׄ'=>230,'ׅ'=>220,'ׇ'=>18,'ؐ'=>230,'ؑ'=>230,'ؒ'=>230,'ؓ'=>230,'ؔ'=>230,'ؕ'=>230,'ً'=>27,'ٌ'=>28,'ٍ'=>29,'َ'=>30,'ُ'=>31,'ِ'=>32,'ّ'=>33,'ْ'=>34,'ٓ'=>230,'ٔ'=>230,'ٕ'=>220,'ٖ'=>220,'ٗ'=>230,'٘'=>230,'ٙ'=>230,'ٚ'=>230,'ٛ'=>230,'ٜ'=>220,'ٝ'=>230,'ٞ'=>230,'ٰ'=>35,'ۖ'=>230,'ۗ'=>230,'ۘ'=>230,'ۙ'=>230,'ۚ'=>230,'ۛ'=>230,'ۜ'=>230,'۟'=>230,'۠'=>230,'ۡ'=>230,'ۢ'=>230,'ۣ'=>220,'ۤ'=>230,'ۧ'=>230,'ۨ'=>230,'۪'=>220,'۫'=>230,'۬'=>230,'ۭ'=>220,'ܑ'=>36,'ܰ'=>230,'ܱ'=>220,'ܲ'=>230,'ܳ'=>230,'ܴ'=>220,'ܵ'=>230,'ܶ'=>230,'ܷ'=>220,'ܸ'=>220,'ܹ'=>220,'ܺ'=>230,'ܻ'=>220,'ܼ'=>220,'ܽ'=>230,'ܾ'=>220,'ܿ'=>230,'݀'=>230,'݁'=>230,'݂'=>220,'݃'=>230,'݄'=>220,'݅'=>230,'݆'=>220,'݇'=>230,'݈'=>220,'݉'=>230,'݊'=>230,'߫'=>230,'߬'=>230,'߭'=>230,'߮'=>230,'߯'=>230,'߰'=>230,'߱'=>230,'߲'=>220,'߳'=>230,'़'=>7,'्'=>9,'॑'=>230,'॒'=>220,'॓'=>230,'॔'=>230,'়'=>7,'্'=>9,'਼'=>7,'੍'=>9,'઼'=>7,'્'=>9,'଼'=>7,'୍'=>9,'்'=>9,'్'=>9,'ౕ'=>84,'ౖ'=>91,'಼'=>7,'್'=>9,'്'=>9,'්'=>9,'ุ'=>103,'ู'=>103,'ฺ'=>9,'่'=>107,'้'=>107,'๊'=>107,'๋'=>107,'ຸ'=>118,'ູ'=>118,'່'=>122,'້'=>122,'໊'=>122,'໋'=>122,'༘'=>220,'༙'=>220,'༵'=>220,'༷'=>220,'༹'=>216,'ཱ'=>129,'ི'=>130,'ུ'=>132,'ེ'=>130,'ཻ'=>130,'ོ'=>130,'ཽ'=>130,'ྀ'=>130,'ྂ'=>230,'ྃ'=>230,'྄'=>9,'྆'=>230,'྇'=>230,'࿆'=>220,'့'=>7,'္'=>9,'፟'=>230,'᜔'=>9,'᜴'=>9,'្'=>9,'៝'=>230,'ᢩ'=>228,'᤹'=>222,'᤺'=>230,'᤻'=>220,'ᨗ'=>230,'ᨘ'=>220,'᬴'=>7,'᭄'=>9,'᭫'=>230,'᭬'=>220,'᭭'=>230,'᭮'=>230,'᭯'=>230,'᭰'=>230,'᭱'=>230,'᭲'=>230,'᭳'=>230,'᷀'=>230,'᷁'=>230,'᷂'=>220,'᷃'=>230,'᷄'=>230,'᷅'=>230,'᷆'=>230,'᷇'=>230,'᷈'=>230,'᷉'=>230,'᷊'=>220,'᷾'=>230,'᷿'=>220,'⃐'=>230,'⃑'=>230,'⃒'=>1,'⃓'=>1,'⃔'=>230,'⃕'=>230,'⃖'=>230,'⃗'=>230,'⃘'=>1,'⃙'=>1,'⃚'=>1,'⃛'=>230,'⃜'=>230,'⃡'=>230,'⃥'=>1,'⃦'=>1,'⃧'=>230,'⃨'=>220,'⃩'=>230,'⃪'=>1,'⃫'=>1,'⃬'=>220,'⃭'=>220,'⃮'=>220,'⃯'=>220,'〪'=>218,'〫'=>228,'〬'=>232,'〭'=>222,'〮'=>224,'〯'=>224,'゙'=>8,'゚'=>8,'꠆'=>9,'ﬞ'=>26,'︠'=>230,'︡'=>230,'︢'=>230,'︣'=>230,'𐨍'=>220,'𐨏'=>230,'𐨸'=>230,'𐨹'=>1,'𐨺'=>220,'𐨿'=>9,'𝅥'=>216,'𝅦'=>216,'𝅧'=>1,'𝅨'=>1,'𝅩'=>1,'𝅭'=>226,'𝅮'=>216,'𝅯'=>216,'𝅰'=>216,'𝅱'=>216,'𝅲'=>216,'𝅻'=>220,'𝅼'=>220,'𝅽'=>220,'𝅾'=>220,'𝅿'=>220,'𝆀'=>220,'𝆁'=>220,'𝆂'=>220,'𝆅'=>230,'𝆆'=>230,'𝆇'=>230,'𝆈'=>230,'𝆉'=>230,'𝆊'=>220,'𝆋'=>220,'𝆪'=>230,'𝆫'=>230,'𝆬'=>230,'𝆭'=>230,'𝉂'=>230,'𝉃'=>230,'𝉄'=>230);
\ No newline at end of file +$GLOBALS['utf_combining_class']=array('̀'=>230,'́'=>230,'̂'=>230,'̃'=>230,'̄'=>230,'̅'=>230,'̆'=>230,'̇'=>230,'̈'=>230,'̉'=>230,'̊'=>230,'̋'=>230,'̌'=>230,'̍'=>230,'̎'=>230,'̏'=>230,'̐'=>230,'̑'=>230,'̒'=>230,'̓'=>230,'̔'=>230,'̕'=>232,'̖'=>220,'̗'=>220,'̘'=>220,'̙'=>220,'̚'=>232,'̛'=>216,'̜'=>220,'̝'=>220,'̞'=>220,'̟'=>220,'̠'=>220,'̡'=>202,'̢'=>202,'̣'=>220,'̤'=>220,'̥'=>220,'̦'=>220,'̧'=>202,'̨'=>202,'̩'=>220,'̪'=>220,'̫'=>220,'̬'=>220,'̭'=>220,'̮'=>220,'̯'=>220,'̰'=>220,'̱'=>220,'̲'=>220,'̳'=>220,'̴'=>1,'̵'=>1,'̶'=>1,'̷'=>1,'̸'=>1,'̹'=>220,'̺'=>220,'̻'=>220,'̼'=>220,'̽'=>230,'̾'=>230,'̿'=>230,'̀'=>230,'́'=>230,'͂'=>230,'̓'=>230,'̈́'=>230,'ͅ'=>240,'͆'=>230,'͇'=>220,'͈'=>220,'͉'=>220,'͊'=>230,'͋'=>230,'͌'=>230,'͍'=>220,'͎'=>220,'͐'=>230,'͑'=>230,'͒'=>230,'͓'=>220,'͔'=>220,'͕'=>220,'͖'=>220,'͗'=>230,'͘'=>232,'͙'=>220,'͚'=>220,'͛'=>230,'͜'=>233,'͝'=>234,'͞'=>234,'͟'=>233,'͠'=>234,'͡'=>234,'͢'=>233,'ͣ'=>230,'ͤ'=>230,'ͥ'=>230,'ͦ'=>230,'ͧ'=>230,'ͨ'=>230,'ͩ'=>230,'ͪ'=>230,'ͫ'=>230,'ͬ'=>230,'ͭ'=>230,'ͮ'=>230,'ͯ'=>230,'҃'=>230,'҄'=>230,'҅'=>230,'҆'=>230,'֑'=>220,'֒'=>230,'֓'=>230,'֔'=>230,'֕'=>230,'֖'=>220,'֗'=>230,'֘'=>230,'֙'=>230,'֚'=>222,'֛'=>220,'֜'=>230,'֝'=>230,'֞'=>230,'֟'=>230,'֠'=>230,'֡'=>230,'֢'=>220,'֣'=>220,'֤'=>220,'֥'=>220,'֦'=>220,'֧'=>220,'֨'=>230,'֩'=>230,'֪'=>220,'֫'=>230,'֬'=>230,'֭'=>222,'֮'=>228,'֯'=>230,'ְ'=>10,'ֱ'=>11,'ֲ'=>12,'ֳ'=>13,'ִ'=>14,'ֵ'=>15,'ֶ'=>16,'ַ'=>17,'ָ'=>18,'ֹ'=>19,'ֺ'=>19,'ֻ'=>20,'ּ'=>21,'ֽ'=>22,'ֿ'=>23,'ׁ'=>24,'ׂ'=>25,'ׄ'=>230,'ׅ'=>220,'ׇ'=>18,'ؐ'=>230,'ؑ'=>230,'ؒ'=>230,'ؓ'=>230,'ؔ'=>230,'ؕ'=>230,'ً'=>27,'ٌ'=>28,'ٍ'=>29,'َ'=>30,'ُ'=>31,'ِ'=>32,'ّ'=>33,'ْ'=>34,'ٓ'=>230,'ٔ'=>230,'ٕ'=>220,'ٖ'=>220,'ٗ'=>230,'٘'=>230,'ٙ'=>230,'ٚ'=>230,'ٛ'=>230,'ٜ'=>220,'ٝ'=>230,'ٞ'=>230,'ٰ'=>35,'ۖ'=>230,'ۗ'=>230,'ۘ'=>230,'ۙ'=>230,'ۚ'=>230,'ۛ'=>230,'ۜ'=>230,'۟'=>230,'۠'=>230,'ۡ'=>230,'ۢ'=>230,'ۣ'=>220,'ۤ'=>230,'ۧ'=>230,'ۨ'=>230,'۪'=>220,'۫'=>230,'۬'=>230,'ۭ'=>220,'ܑ'=>36,'ܰ'=>230,'ܱ'=>220,'ܲ'=>230,'ܳ'=>230,'ܴ'=>220,'ܵ'=>230,'ܶ'=>230,'ܷ'=>220,'ܸ'=>220,'ܹ'=>220,'ܺ'=>230,'ܻ'=>220,'ܼ'=>220,'ܽ'=>230,'ܾ'=>220,'ܿ'=>230,'݀'=>230,'݁'=>230,'݂'=>220,'݃'=>230,'݄'=>220,'݅'=>230,'݆'=>220,'݇'=>230,'݈'=>220,'݉'=>230,'݊'=>230,'߫'=>230,'߬'=>230,'߭'=>230,'߮'=>230,'߯'=>230,'߰'=>230,'߱'=>230,'߲'=>220,'߳'=>230,'़'=>7,'्'=>9,'॑'=>230,'॒'=>220,'॓'=>230,'॔'=>230,'়'=>7,'্'=>9,'਼'=>7,'੍'=>9,'઼'=>7,'્'=>9,'଼'=>7,'୍'=>9,'்'=>9,'్'=>9,'ౕ'=>84,'ౖ'=>91,'಼'=>7,'್'=>9,'്'=>9,'්'=>9,'ุ'=>103,'ู'=>103,'ฺ'=>9,'่'=>107,'้'=>107,'๊'=>107,'๋'=>107,'ຸ'=>118,'ູ'=>118,'່'=>122,'້'=>122,'໊'=>122,'໋'=>122,'༘'=>220,'༙'=>220,'༵'=>220,'༷'=>220,'༹'=>216,'ཱ'=>129,'ི'=>130,'ུ'=>132,'ེ'=>130,'ཻ'=>130,'ོ'=>130,'ཽ'=>130,'ྀ'=>130,'ྂ'=>230,'ྃ'=>230,'྄'=>9,'྆'=>230,'྇'=>230,'࿆'=>220,'့'=>7,'္'=>9,'፟'=>230,'᜔'=>9,'᜴'=>9,'្'=>9,'៝'=>230,'ᢩ'=>228,'᤹'=>222,'᤺'=>230,'᤻'=>220,'ᨗ'=>230,'ᨘ'=>220,'᬴'=>7,'᭄'=>9,'᭫'=>230,'᭬'=>220,'᭭'=>230,'᭮'=>230,'᭯'=>230,'᭰'=>230,'᭱'=>230,'᭲'=>230,'᭳'=>230,'᷀'=>230,'᷁'=>230,'᷂'=>220,'᷃'=>230,'᷄'=>230,'᷅'=>230,'᷆'=>230,'᷇'=>230,'᷈'=>230,'᷉'=>230,'᷊'=>220,'᷾'=>230,'᷿'=>220,'⃐'=>230,'⃑'=>230,'⃒'=>1,'⃓'=>1,'⃔'=>230,'⃕'=>230,'⃖'=>230,'⃗'=>230,'⃘'=>1,'⃙'=>1,'⃚'=>1,'⃛'=>230,'⃜'=>230,'⃡'=>230,'⃥'=>1,'⃦'=>1,'⃧'=>230,'⃨'=>220,'⃩'=>230,'⃪'=>1,'⃫'=>1,'⃬'=>220,'⃭'=>220,'⃮'=>220,'⃯'=>220,'〪'=>218,'〫'=>228,'〬'=>232,'〭'=>222,'〮'=>224,'〯'=>224,'゙'=>8,'゚'=>8,'꠆'=>9,'ﬞ'=>26,'︠'=>230,'︡'=>230,'︢'=>230,'︣'=>230,'𐨍'=>220,'𐨏'=>230,'𐨸'=>230,'𐨹'=>1,'𐨺'=>220,'𐨿'=>9,'𝅥'=>216,'𝅦'=>216,'𝅧'=>1,'𝅨'=>1,'𝅩'=>1,'𝅭'=>226,'𝅮'=>216,'𝅯'=>216,'𝅰'=>216,'𝅱'=>216,'𝅲'=>216,'𝅻'=>220,'𝅼'=>220,'𝅽'=>220,'𝅾'=>220,'𝅿'=>220,'𝆀'=>220,'𝆁'=>220,'𝆂'=>220,'𝆅'=>230,'𝆆'=>230,'𝆇'=>230,'𝆈'=>230,'𝆉'=>230,'𝆊'=>220,'𝆋'=>220,'𝆪'=>230,'𝆫'=>230,'𝆬'=>230,'𝆭'=>230,'𝉂'=>230,'𝉃'=>230,'𝉄'=>230); diff --git a/phpBB/includes/utf/utf_normalizer.php b/phpBB/includes/utf/utf_normalizer.php index a77952499a..bbb23a6617 100644 --- a/phpBB/includes/utf/utf_normalizer.php +++ b/phpBB/includes/utf/utf_normalizer.php @@ -1,10 +1,13 @@ <?php /** * -* @package utf -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -63,8 +66,6 @@ define('UNICODE_JAMO_T', 2); /** * Unicode normalization routines -* -* @package utf */ class utf_normalizer { @@ -77,7 +78,7 @@ class utf_normalizer * @param string &$str The dirty string * @return string The same string, all shiny and cleaned-up */ - function cleanup(&$str) + static function cleanup(&$str) { // The string below is the list of all autorized characters, sorted by frequency in latin text $pos = strspn($str, "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x0D"); @@ -119,7 +120,7 @@ class utf_normalizer * @param string &$str Unchecked UTF string * @return string The string, validated and in normal form */ - function nfc(&$str) + static function nfc(&$str) { $pos = strspn($str, UTF8_ASCII_RANGE); $len = strlen($str); @@ -151,7 +152,7 @@ class utf_normalizer * @param string &$str Unchecked UTF string * @return string The string, validated and in normal form */ - function nfkc(&$str) + static function nfkc(&$str) { $pos = strspn($str, UTF8_ASCII_RANGE); $len = strlen($str); @@ -183,7 +184,7 @@ class utf_normalizer * @param string &$str Unchecked UTF string * @return string The string, validated and in normal form */ - function nfd(&$str) + static function nfd(&$str) { $pos = strspn($str, UTF8_ASCII_RANGE); $len = strlen($str); @@ -209,7 +210,7 @@ class utf_normalizer * @param string &$str Unchecked UTF string * @return string The string, validated and in normal form */ - function nfkd(&$str) + static function nfkd(&$str) { $pos = strspn($str, UTF8_ASCII_RANGE); $len = strlen($str); @@ -242,7 +243,7 @@ class utf_normalizer * * @access private */ - function recompose($str, $pos, $len, &$qc, &$decomp_map) + static function recompose($str, $pos, $len, &$qc, &$decomp_map) { global $utf_combining_class, $utf_canonical_comp, $utf_jamo_type, $utf_jamo_index; @@ -480,7 +481,6 @@ class utf_normalizer continue; } - // STEP 1: Decompose current char // We have found a character that is either: @@ -528,7 +528,6 @@ class utf_normalizer $utf_seq = array($utf_char); } - // STEP 2: Capture the starter // Check out the combining class of the first character of the UTF sequence @@ -684,7 +683,6 @@ class utf_normalizer } } - // STEP 3: Capture following combining modifiers while ($pos < $len) @@ -753,7 +751,6 @@ class utf_normalizer } } - // STEP 4: Sort and combine // Here we sort... @@ -944,7 +941,7 @@ class utf_normalizer * * @access private */ - function decompose($str, $pos, $len, &$decomp_map) + static function decompose($str, $pos, $len, &$decomp_map) { global $utf_combining_class; @@ -992,7 +989,6 @@ class utf_normalizer $tmp_pos = $last_cc = $sort = $dump = 0; $utf_sort = array(); - // Main loop do { @@ -1048,7 +1044,6 @@ class utf_normalizer continue; } - // STEP 1: Decide what to do with current char // Now, in that order: @@ -1512,5 +1507,3 @@ class utf_normalizer return $str; } } - -?>
\ No newline at end of file diff --git a/phpBB/includes/utf/utf_tools.php b/phpBB/includes/utf/utf_tools.php index 6f3ac93305..e60a40a195 100644 --- a/phpBB/includes/utf/utf_tools.php +++ b/phpBB/includes/utf/utf_tools.php @@ -1,10 +1,13 @@ <?php /** * -* @package utf -* @version $Id$ -* @copyright (c) 2006 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* 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. * */ @@ -24,7 +27,6 @@ setlocale(LC_CTYPE, 'C'); * Whenever possible, these functions will try to use PHP's built-in functions or * extensions, otherwise they will default to custom routines. * -* @package utf */ if (!extension_loaded('xml')) @@ -109,70 +111,26 @@ if (extension_loaded('mbstring')) /** * UTF-8 aware alternative to strrpos * Find position of last occurrence of a char in a string - * - * Notes: - * - offset for mb_strrpos was added in 5.2.0, we emulate if it is lower */ - if (version_compare(PHP_VERSION, '5.2.0', '>=')) + /** + * UTF-8 aware alternative to strrpos + * @ignore + */ + function utf8_strrpos($str, $needle, $offset = null) { - /** - * UTF-8 aware alternative to strrpos - * @ignore - */ - function utf8_strrpos($str, $needle, $offset = null) + // Emulate behaviour of strrpos rather than raising warning + if (empty($str)) { - // Emulate behaviour of strrpos rather than raising warning - if (empty($str)) - { - return false; - } + return false; + } - if (is_null($offset)) - { - return mb_strrpos($str, $needle); - } - else - { - return mb_strrpos($str, $needle, $offset); - } + if (is_null($offset)) + { + return mb_strrpos($str, $needle); } - } - else - { - /** - * UTF-8 aware alternative to strrpos - * @ignore - */ - function utf8_strrpos($str, $needle, $offset = null) + else { - // offset for mb_strrpos was added in 5.2.0 - if (is_null($offset)) - { - // Emulate behaviour of strrpos rather than raising warning - if (empty($str)) - { - return false; - } - - return mb_strrpos($str, $needle); - } - else - { - if (!is_int($offset)) - { - trigger_error('utf8_strrpos expects parameter 3 to be long', E_USER_ERROR); - return false; - } - - $str = mb_substr($str, $offset); - - if (false !== ($pos = mb_strrpos($str, $needle))) - { - return $pos + $offset; - } - - return false; - } + return mb_strrpos($str, $needle, $offset); } } @@ -576,7 +534,7 @@ else return ''; } - $lx = (int)((-$length) / 65535); + $lx = (int) ((-$length) / 65535); $ly = (-$length) % 65535; // negative length requires ... capture everything @@ -1756,49 +1714,106 @@ function utf8_case_fold_nfc($text, $option = 'full') return $text; } -/** -* A wrapper function for the normalizer which takes care of including the class if required and modifies the passed strings -* to be in NFC (Normalization Form Composition). -* -* @param mixed $strings a string or an array of strings to normalize -* @return mixed the normalized content, preserving array keys if array given. -*/ -function utf8_normalize_nfc($strings) +if (extension_loaded('intl')) { - if (empty($strings)) + /** + * wrapper around PHP's native normalizer from intl + * previously a PECL extension, included in the core since PHP 5.3.0 + * http://php.net/manual/en/normalizer.normalize.php + * + * @param mixed $strings a string or an array of strings to normalize + * @return mixed the normalized content, preserving array keys if array given. + */ + function utf8_normalize_nfc($strings) { - return $strings; - } + if (empty($strings)) + { + return $strings; + } - if (!class_exists('utf_normalizer')) - { - global $phpbb_root_path, $phpEx; - include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx); - } + if (!is_array($strings)) + { + if (Normalizer::isNormalized($strings)) + { + return $strings; + } + return (string) Normalizer::normalize($strings); + } + else + { + foreach ($strings as $key => $string) + { + if (is_array($string)) + { + foreach ($string as $_key => $_string) + { + if (Normalizer::isNormalized($strings[$key][$_key])) + { + continue; + } + $strings[$key][$_key] = (string) Normalizer::normalize($strings[$key][$_key]); + } + } + else + { + if (Normalizer::isNormalized($strings[$key])) + { + continue; + } + $strings[$key] = (string) Normalizer::normalize($strings[$key]); + } + } + } - if (!is_array($strings)) - { - utf_normalizer::nfc($strings); + return $strings; } - else if (is_array($strings)) +} +else +{ + /** + * A wrapper function for the normalizer which takes care of including the class if + * required and modifies the passed strings to be in NFC (Normalization Form Composition). + * + * @param mixed $strings a string or an array of strings to normalize + * @return mixed the normalized content, preserving array keys if array given. + */ + function utf8_normalize_nfc($strings) { - foreach ($strings as $key => $string) + if (empty($strings)) + { + return $strings; + } + + if (!class_exists('utf_normalizer')) + { + global $phpbb_root_path, $phpEx; + include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx); + } + + if (!is_array($strings)) + { + utf_normalizer::nfc($strings); + } + else if (is_array($strings)) { - if (is_array($string)) + foreach ($strings as $key => $string) { - foreach ($string as $_key => $_string) + if (is_array($string)) { - utf_normalizer::nfc($strings[$key][$_key]); + foreach ($string as $_key => $_string) + { + utf_normalizer::nfc($strings[$key][$_key]); + } + } + else + { + utf_normalizer::nfc($strings[$key]); } - } - else - { - utf_normalizer::nfc($strings[$key]); } } - } - return $strings; + return $strings; + } } /** @@ -1921,7 +1936,7 @@ function utf8_wordwrap($string, $width = 75, $break = "\n", $cut = false) * UTF8-safe basename() function * * basename() has some limitations and is dependent on the locale setting -* according to the PHP manual. Therefore we provide our own locale independant +* according to the PHP manual. Therefore we provide our own locale independent * basename function. * * @param string $filename The filename basename() should be applied to @@ -1991,5 +2006,3 @@ function utf8_str_replace($search, $replace, $subject) return $subject; } - -?>
\ No newline at end of file |