OSDN Git Service

MERGE: リビジョン1826。プラグインイベント「ForceLocale」の新設。
authorsakamocchi <o-takashi@sakamocchi.jp>
Sat, 5 May 2012 04:02:51 +0000 (13:02 +0900)
committersakamocchi <o-takashi@sakamocchi.jp>
Sat, 5 May 2012 04:02:51 +0000 (13:02 +0900)
現在のロケールと文字符号化方式をプラグインから強制するためのイベントとして、ForceLocaleを新設した。これにより、従来はイベント「PreSendContentType」を利用して指定していたユーザーエージェント(ウェブブラウザー)への出力文字符号化方式は非推奨となる。

従来はプラグイン側でバッファリングして入出力文字列の文字符号化方式を変換していたが、イベント「ForceLocale」を用いることでNucleusCMSのコア側でこの変換を行う。すなわち、i18n::get_current_charset()で参照できる内部処理の既定の文字符号化方式と、i18n::get_forced_charset()で参照できるユーザーエージェントのための文字符号化方式の間の変換を自動で行うようになる。

イベント「PreSendContentType」を用いて携帯端末用に文字符号化方式を変換するようなプラグインは書き換えを推奨する。

イベント「ForceLocale」の仕様やプラグイン例のコードは、以下のコメントを参照して欲しい。

Revision 1826:
ADD: new plugin event 'ForceLocale' to force locale and character set
for output/input

With this commit, plugins can force Nucleus CMS to convert between its
default locale/character set and forced locale/character set.

Then these two compatibilities are lost:
1. The 'charset' argument of sendContentType() do nothing and
deprecated.
2. The 'charset' argument for plugin event 'PreSendContentType' is
removed. The Plugins to use this must be rewritted.

Specifications:
1. Forced locale should be within available locales under
/nucleus/locales.
2. Forced locale is ignored when member is logging-in.
3. Forced character set is used output/input conversion to/from user
agent with to i18n::get_forced_locale() and i18n::get_forced_charset().
4. On the other hand, Nucleus CMS consistently use
i18n::get_current_charset() for inner processing.
5. The conversion of character set from current to forced is done by
i18n::convert_handler() registerd with ob_start() in sendContentType().
6. The conversion of character set from forced to current is done by
i18n::convert_array() in globalfunctions.php

Plugin sample:
<?php
class NP_ForceLocale extends NucleusPlugin
{
public function getName()
{
return 'ForceLocale';
}
...
public function getEventList()
{
return array('ForceLocale');
}
...
public function event_ForceLocale($data)
{
/*
 * plugins decide which locale and charset to be forced here
 * then set them to $data.
 */
$data['locale'] = 'hu_Latn_HU';
$data['charset'] = 'ISO-8859-2';
return;
}
...
}

nucleus/libs/globalfunctions.php
nucleus/libs/i18n.php

index c31cff5..5a25356 100644 (file)
@@ -100,7 +100,7 @@ if ( !headers_sent() )
 }\r
 \r
 \r
-/* FIXME: This is for compatibility since 4.0, should be obsoleted at future release. */\r
+/* TODO: This is for compatibility since 4.0, should be obsoleted at future release. */\r
 if ( !isset($DIR_LOCALES) )\r
 {\r
        $DIR_LOCALES = $DIR_NUCLEUS . 'locales/';\r
@@ -121,7 +121,7 @@ if ( !i18n::init('UTF-8', $DIR_LOCALES) )
        exit('Fail to initialize i18n class.');\r
 }\r
 \r
-/* FIXME: This is just for compatibility since 4.0, should be obsoleted at future release. */\r
+/* TODO: This is just for compatibility since 4.0, should be obsoleted at future release. */\r
 define('_CHARSET', i18n::get_current_charset());\r
 \r
 \r
@@ -171,9 +171,47 @@ if ( $MYSQL_HANDLER[0] == '' )
 DB::setConnectionInfo($MYSQL_HANDLER[1], $MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD, $MYSQL_DATABASE);\r
 \r
 \r
+/* force locale or charset */\r
+$locale = '';\r
+$charset = i18n::get_current_charset();\r
+\r
+$data = array(\r
+       'locale'        => &$locale,\r
+       'charset'       => &$charset\r
+);\r
+$manager->notify('ForceLocale', $data);\r
+\r
+if ( $data['locale'] !== '' )\r
+{\r
+       i18n::set_forced_locale($data['locale']);\r
+}\r
+if ( $data['charset'] !== '' )\r
+{\r
+       i18n::set_forced_charset($data['charset']);\r
+}\r
+unset($locale);\r
+unset($charset);\r
+\r
+\r
+/* convert forced charset to current charset */\r
+if ( i18n::get_forced_charset() != i18n::get_current_charset() )\r
+{\r
+       $_POST          = i18n::convert_array($_POST, i18n::get_forced_charset());\r
+       $_GET           = i18n::convert_array($_GET, i18n::get_forced_charset());\r
+       $_REQUEST       = i18n::convert_array($_REQUEST, i18n::get_forced_charset());\r
+       $_COOKIE        = i18n::convert_array($_COOKIE, i18n::get_forced_charset());\r
+       $_FILES         = i18n::convert_array($_FILES, i18n::get_forced_charset());\r
+       \r
+       if ( session_id() !== '' )\r
+       {\r
+               $_SESSION = i18n::convert_array($_SESSION, i18n::get_forced_charset());\r
+       }\r
+}\r
+\r
+\r
 /* sanitize option */\r
-$bLoggingSanitizedResult=0;\r
-$bSanitizeAndContinue=0;\r
+$bLoggingSanitizedResult = 0;\r
+$bSanitizeAndContinue = 0;\r
 $orgRequestURI = serverVar('REQUEST_URI');\r
 sanitizeParams();\r
 \r
@@ -211,23 +249,12 @@ $startpos = intRequestVar('startpos');
 $errormessage = '';\r
 $error         = '';\r
 $special       = requestVar('special');\r
-$virtualpath = ((getVar('virtualpath') != null) ? getVar('virtualpath') : serverVar('PATH_INFO'));\r
+$virtualpath = ((getVar('virtualpath') != NULL) ? getVar('virtualpath') : serverVar('PATH_INFO'));\r
 \r
 \r
 /* read config */\r
 getConfig();\r
 \r
-/* FIXME: This is for backward compatibility, should be obsoleted near future. */\r
-if ( !preg_match('#^(.+)_(.+)_(.+)$#', $CONF['Locale'])\r
-  && ($CONF['Locale'] = i18n::convert_old_language_file_name_to_locale($CONF['Locale'])) === FALSE )\r
-{\r
-       $CONF['Locale'] = 'en_Latn_US';\r
-}\r
-if ( !array_key_exists('Language', $CONF) )\r
-{\r
-       $CONF['Language'] = i18n::convert_locale_to_old_language_file_name($CONF['Locale']);\r
-}\r
-$locale = $CONF['Locale'];\r
 \r
 /* Properly set $CONF['Self'] and others if it's not set...\r
  * usually when we are access from admin menu\r
@@ -242,13 +269,13 @@ if ( !array_key_exists('Self', $CONF) )
        }\r
 }\r
 \r
-$CONF['ItemURL']       = $CONF['Self'];\r
-$CONF['ArchiveURL']    = $CONF['Self'];\r
-$CONF['ArchiveListURL'] = $CONF['Self'];\r
-$CONF['MemberURL']     = $CONF['Self'];\r
-$CONF['SearchURL']     = $CONF['Self'];\r
-$CONF['BlogURL']       = $CONF['Self'];\r
-$CONF['CategoryURL'] = $CONF['Self'];\r
+$CONF['ItemURL']               = $CONF['Self'];\r
+$CONF['ArchiveURL']            = $CONF['Self'];\r
+$CONF['ArchiveListURL']        = $CONF['Self'];\r
+$CONF['MemberURL']             = $CONF['Self'];\r
+$CONF['SearchURL']             = $CONF['Self'];\r
+$CONF['BlogURL']               = $CONF['Self'];\r
+$CONF['CategoryURL']   = $CONF['Self'];\r
 \r
 /*\r
  *switch URLMode back to normal when $CONF['Self'] ends in .php\r
@@ -287,14 +314,39 @@ else
        $member->cookielogin();\r
 }\r
 \r
+\r
+/* TODO: This is for backward compatibility, should be obsoleted near future. */\r
+if ( !preg_match('#^(.+)_(.+)_(.+)$#', $CONF['Locale'])\r
+  && ($CONF['Locale'] = i18n::convert_old_language_file_name_to_locale($CONF['Locale'])) === FALSE )\r
+{\r
+       $CONF['Locale'] = 'en_Latn_US';\r
+}\r
+if ( !array_key_exists('Language', $CONF) )\r
+{\r
+       $CONF['Language'] = i18n::convert_locale_to_old_language_file_name($CONF['Locale']);\r
+}\r
+$locale = $CONF['Locale'];\r
+\r
+\r
 /* NOTE: include translation file and set locale */\r
-if ( $member->isLoggedIn() && $member->getLocale())\r
+if ( $member->isLoggedIn() )\r
 {\r
-       $locale = $member->getLocale();\r
+       if ( $member->getLocale() )\r
+       {\r
+               $locale = $member->getLocale();\r
+       }\r
+}\r
+else\r
+{\r
+       if ( i18n::get_forced_locale() !== '' )\r
+       {\r
+               $locale = i18n::get_forced_locale();\r
+       }\r
 }\r
 include_translation($locale);\r
 i18n::set_current_locale($locale);\r
 \r
+\r
 /* login completed */\r
 $manager->notify('PostAuthentication', array('loggedIn' => $member->isLoggedIn() ) );\r
 \r
@@ -734,51 +786,72 @@ function startUpError($msg, $title)
        }\r
 \r
 \r
-       /**\r
-        * TODO: This function should be changed to send_content_type() per the Coding Guidelines. Ensure this change is compatible with rest of core.\r
-        *\r
-        * This function sends the Content-Type header if headers have not already been sent\r
-        * It also determines if the browser can accept application/xhtml+xml and sends it only to those that can.\r
-        * @param string $content_type\r
-        * @param string $page_type\r
-        * @param string $charset Deprecated. This has no meaning.\r
-        */\r
-       function sendContentType($content_type, $page_type = '', $charset = _CHARSET)\r
+/**\r
+ * sendContentType()\r
+ * This function sends the Content-Type header if headers have not already been sent\r
+ * It also determines if the browser can accept application/xhtml+xml and sends it only to those that can.\r
+ * \r
+ * if content type is application/xhtml+xml, only send it to browsers\r
+ * that can handle it (IE6 cannot). Otherwise, send text/html\r
+ *\r
+ * v2.5:\r
+ * For admin area pages, keep sending text/html (unless it's a debug version)\r
+ * application/xhtml+xml still causes too much problems with the javascript implementations\r
+ *\r
+ * v3.3:\r
+ * ($CONF['UsingAdminArea'] && !$CONF['debug']) gets removed,\r
+ * application/xhtml+xml seems to be working, so we're going to use it if we can.\r
+ * \r
+ * @param      string  $content_type   MIME media type registered to IANA, http://www.iana.org/assignments/media-types/index.html\r
+ * @param      string  $page_type              \r
+ * @param      string  $charset                Deprecated. This has no meaning.\r
+ * @return     void\r
+ * \r
+ */\r
+function sendContentType($content_type, $page_type = '', $charset = '')\r
+{\r
+       global $manager, $CONF;\r
+       \r
+       if ( headers_sent() )\r
        {\r
-               global $manager, $CONF;\r
-               \r
-               if ( !headers_sent() )\r
-               {\r
-                       // if content type is application/xhtml+xml, only send it to browsers\r
-                       // that can handle it (IE6 cannot). Otherwise, send text/html\r
-\r
-                       // v2.5: For admin area pages, keep sending text/html (unless it's a debug version)\r
-                       //       application/xhtml+xml still causes too much problems with the javascript implementations\r
-\r
-                       // v3.3: ($CONF['UsingAdminArea'] && !$CONF['debug']) gets removed,\r
-                       //       application/xhtml+xml seems to be working, so we're going to use it if we can.\r
-\r
-                       if ( ($content_type == 'application/xhtml+xml')\r
-                               && (!stristr(serverVar('HTTP_ACCEPT'), 'application/xhtml+xml') ) )\r
-                       {\r
-                               $content_type = 'text/html';\r
-                       } // end if\r
-\r
-                       $manager->notify(\r
-                               'PreSendContentType',\r
-                               array(\r
-                                       'contentType' => &$content_type,\r
-                                       'charset' => i18n::get_current_charset(),\r
-                                       'pageType' => $page_type\r
-                               )\r
-                       );\r
-\r
-                       // strip strange characters\r
-                       $content_type = preg_replace('|[^a-z0-9-+./]|i', '', $content_type);\r
-                       header('Content-Type: ' . $content_type . '; charset=' . i18n::get_current_charset());\r
-               } // end if\r
-\r
+               return;\r
+       }\r
+       \r
+       /* NOTE: MIME Media Type */\r
+       if ( ($content_type == 'application/xhtml+xml')\r
+               && (!stristr(serverVar('HTTP_ACCEPT'), 'application/xhtml+xml') ) )\r
+       {\r
+               $content_type = 'text/html';\r
+       }\r
+       \r
+       /* NOTE: generate event */\r
+       $data = array(\r
+               'pageType'              =>  $page_type,\r
+               'contentType'   => &$content_type\r
+       );\r
+       $manager->notify('PreSendContentType', $data);\r
+       \r
+       /* NOTE: confirm MIME Media Type */\r
+       $content_type = preg_replace('#[^a-zA-Z0-9-+./]#', '', $content_type);\r
+       \r
+       /* NOTE: confirm character set */\r
+       $charset = i18n::get_current_charset();\r
+       if ( i18n::get_forced_charset() !== '' )\r
+       {\r
+               $charset = i18n::get_forced_charset();\r
        }\r
+       \r
+       /* NOTE: send HTTP 1.1 header */\r
+       header("Content-Type: {$content_type}; charset={$charset}");\r
+       \r
+       /* NOTE: set handler for translating character set */\r
+       if ( $charset != i18n::get_current_charset() )\r
+       {\r
+               ob_start(array('i18n', 'convert_handler'));\r
+       }\r
+       \r
+       return;\r
+}\r
 \r
 \r
        /**\r
@@ -1583,52 +1656,42 @@ function checkVars($aVars) {
 \r
 \r
 /**\r
+ * sanitizeParams()\r
  * Sanitize parameters such as $_GET and $_SERVER['REQUEST_URI'] etc.\r
- * to avoid XSS\r
+ * to avoid XSS.\r
+ * \r
+ * @param      void\r
+ * @return     void\r
  */\r
 function sanitizeParams()\r
 {\r
-    global $HTTP_SERVER_VARS;\r
-\r
-    $array = array();\r
-    $str = '';\r
-    $frontParam = '';\r
-\r
-    // REQUEST_URI of $HTTP_SERVER_VARS\r
-    $str =& $HTTP_SERVER_VARS["REQUEST_URI"];\r
-    serverStringToArray($str, $array, $frontParam);\r
-    sanitizeArray($array);\r
-    arrayToServerString($array, $frontParam, $str);\r
-\r
-    // QUERY_STRING of $HTTP_SERVER_VARS\r
-    $str =& $HTTP_SERVER_VARS["QUERY_STRING"];\r
-    serverStringToArray($str, $array, $frontParam);\r
-    sanitizeArray($array);\r
-    arrayToServerString($array, $frontParam, $str);\r
-\r
-    if (phpversion() >= '4.1.0') {\r
-        // REQUEST_URI of $_SERVER\r
-        $str =& $_SERVER["REQUEST_URI"];\r
-        serverStringToArray($str, $array, $frontParam);\r
-        sanitizeArray($array);\r
-        arrayToServerString($array, $frontParam, $str);\r
-\r
-        // QUERY_STRING of $_SERVER\r
-        $str =& $_SERVER["QUERY_STRING"];\r
-        serverStringToArray($str, $array, $frontParam);\r
-        sanitizeArray($array);\r
-        arrayToServerString($array, $frontParam, $str);\r
-    }\r
-\r
-    // $_GET\r
-    convArrayForSanitizing($_GET, $array);\r
-    sanitizeArray($array);\r
-    revertArrayForSanitizing($array, $_GET);\r
-\r
-    // $_REQUEST (only GET param)\r
-    convArrayForSanitizing($_REQUEST, $array);\r
-    sanitizeArray($array);\r
-    revertArrayForSanitizing($array, $_REQUEST);\r
+       $array = array();\r
+       $str = '';\r
+       $frontParam = '';\r
+       \r
+       // REQUEST_URI of $_SERVER\r
+       $str =& $_SERVER["REQUEST_URI"];\r
+       serverStringToArray($str, $array, $frontParam);\r
+       sanitizeArray($array);\r
+       arrayToServerString($array, $frontParam, $str);\r
+       \r
+       // QUERY_STRING of $_SERVER\r
+       $str =& $_SERVER["QUERY_STRING"];\r
+       serverStringToArray($str, $array, $frontParam);\r
+       sanitizeArray($array);\r
+       arrayToServerString($array, $frontParam, $str);\r
+       \r
+       // $_GET\r
+       convArrayForSanitizing($_GET, $array);\r
+       sanitizeArray($array);\r
+       revertArrayForSanitizing($array, $_GET);\r
+       \r
+       // $_REQUEST (only GET param)\r
+       convArrayForSanitizing($_REQUEST, $array);\r
+       sanitizeArray($array);\r
+       revertArrayForSanitizing($array, $_REQUEST);\r
+       \r
+       return;\r
 }\r
 \r
 /**\r
@@ -1829,55 +1892,85 @@ function _addInputTags(&$keys,$prefix=''){
  * Convert the server string such as $_SERVER['REQUEST_URI']\r
  * to arry like arry['blogid']=1 and array['page']=2 etc.\r
  * \r
- * @param      string  $str            string\r
- * @param      string  $array          \r
- * @param      string  $frontParam     \r
+ * @param      string   $uri                           string\r
+ * @param      string  &$query_elements        elements of query according to application/x-www-form-urlencoded\r
+ * @param      string  &$hier_part                     hierarchical part includes path\r
+ * \r
+ * NOTE:\r
+ * RFC 3986: Uniform Resource Identifiers (URI): Generic Syntax\r
+ * 3.  Syntax Components\r
+ * http://www.ietf.org/rfc/rfc3986.txt\r
+ * \r
+ * Hypertext Markup Language - 2.0\r
+ * 8.2.1. The form-urlencoded Media Type\r
+ * http://tools.ietf.org/html/rfc1866#section-8.2.1\r
+ * \r
+ * $_SERVER > Language Reference > Predefined Variables > PHP Manual\r
+ * http://www.php.net/manual/en/reserved.variables.server.php\r
  */\r
-function serverStringToArray($str, &$array, &$frontParam)\r
+function serverStringToArray($uri, &$query_elements, &$hier_part)\r
 {\r
        // init param\r
-       $array = array();\r
-       $frontParam = "";\r
+       $query_elements = array();\r
+       $hier_part = "";\r
        \r
-       // split front param, e.g. /index.php, and others, e.g. blogid=1&page=2\r
-       if ( i18n::strpos($str, "?") > 0 )\r
+       // split hierarchical part, e.g. /index.php, query and fragment, e.g. blogid=1&page=2#section1\r
+       if ( i18n::strpos($uri, "?") > 0 )\r
        {\r
-               list($frontParam, $args) = preg_split("#\?#", $str, 2);\r
+               list($hier_part, $query_and_fragment) = preg_split("#\?#", $uri, 2);\r
        }\r
        else\r
        {\r
-               $args = $str;\r
-               $frontParam = "";\r
+               $query_and_fragment = $uri;\r
+               $hier_part = '';\r
        }\r
        \r
-       // If there is no args like blogid=1&page=2, return\r
-       if ( i18n::strpos($str, "=") == FALSE && !i18n::strlen($frontParam) )\r
+       // If there is no query like blogid=1&page=2, return\r
+       if ( i18n::strpos($uri, "=") == FALSE && !i18n::strlen($hier_part) )\r
        {\r
-               $frontParam = $str;\r
+               $hier_part = $uri;\r
                return;\r
        }\r
        \r
-       $array = preg_split("#&#", $args);\r
+       $query_elements = preg_split("#&#", $query_and_fragment);\r
        return;\r
 }\r
 \r
 /**\r
+ * arrayToServerString()\r
  * Convert array like array['blogid'] to server string\r
  * such as $_SERVER['REQUEST_URI']\r
+ * \r
+ * @param      array    $query_elements        elements of query according to application/x-www-form-urlencoded\r
+ * @param      string   $hier_part                     hier-part defined in RFC3986\r
+ * @param      string  &$uri                           return value\r
+ * @return     void\r
+ * \r
+ * NOTE:\r
+ * RFC 3986: Uniform Resource Identifiers (URI): Generic Syntax\r
+ * 3.  Syntax Components\r
+ * http://www.ietf.org/rfc/rfc3986.txt\r
+ * \r
+ * Hypertext Markup Language - 2.0\r
+ * 8.2.1. The form-urlencoded Media Type\r
+ * http://tools.ietf.org/html/rfc1866#section-8.2.1\r
+ * \r
+ * $_SERVER > Language Reference > Predefined Variables > PHP Manual\r
+ * http://www.php.net/manual/en/reserved.variables.server.php\r
  */\r
-function arrayToServerString($array, $frontParam, &$str)\r
+function arrayToServerString($query_elements, $hier_part, &$uri)\r
 {\r
-       if ( i18n::strpos($str, "?") !== FALSE )\r
+       if ( i18n::strpos($uri, "?") !== FALSE )\r
        {\r
-               $str = $frontParam . "?";\r
+               $uri = $hier_part . "?";\r
        }\r
        else\r
        {\r
-               $str = $frontParam;\r
+               $uri = $hier_part;\r
        }\r
-       if ( count($array) )\r
+       if ( count($query_elements) > 0 )\r
        {\r
-               $str .= implode("&", $array);\r
+               $uri .= implode("&", $query_elements);\r
        }\r
        return;\r
 }\r
@@ -1889,7 +1982,7 @@ function arrayToServerString($array, $frontParam, &$str)
  * - check key if it inclues " (double quote),  remove from array\r
  * - check value if it includes \ (escape sequece), remove remaining string\r
  * \r
- * @param      array   &$array \r
+ * @param      array   &$array elements of query according to application/x-www-form-urlencoded\r
  * @return     void\r
  */\r
 function sanitizeArray(&$array)\r
@@ -1911,6 +2004,7 @@ function sanitizeArray(&$array)
                {\r
                        $val = stripslashes($val);\r
                }\r
+               \r
                // note that we must use addslashes here because this function is called before the db connection is made\r
                // and sql_real_escape_string needs a db connection\r
                $val = addslashes($val);\r
@@ -1919,7 +2013,7 @@ function sanitizeArray(&$array)
                if ( !in_array($key, $excludeListForSanitization) )\r
                {\r
                        // check value\r
-                       if ( i18n::strpos($val, '\\') )\r
+                       if ( i18n::strpos($val, '\\') > 0 )\r
                        {\r
                                list($val, $tmp) = preg_split('#\\\\#', $val);\r
                        }\r
@@ -1928,7 +2022,7 @@ function sanitizeArray(&$array)
                        $val = strtr($val, "\0\r\n<>'\"", "       ");\r
                        \r
                        // check key\r
-                       if ( preg_match('#\"#', $key) )\r
+                       if ( preg_match('#\"#', $key) > 0 )\r
                        {\r
                                unset($array[$k]);\r
                                continue;\r
@@ -1942,27 +2036,45 @@ function sanitizeArray(&$array)
 }\r
 \r
 /**\r
+ * convArrayForSanitizing()\r
  * Convert array for sanitizeArray function\r
+ * \r
+ * @param      string  $src    array to be sanitized\r
+ * @param      array   &$array array to be temporarily stored\r
+ * @return     void\r
  */\r
 function convArrayForSanitizing($src, &$array)\r
 {\r
-    $array = array();\r
-    foreach ($src as $key => $val) {\r
-        if (key_exists($key, $_GET)) {\r
-            array_push($array, sprintf("%s=%s", $key, $val));\r
-        }\r
-    }\r
+       $array = array();\r
+       foreach ( $src as $key => $val )\r
+       {\r
+               if ( !key_exists($key, $_GET) )\r
+               {\r
+                       continue;\r
+               }\r
+               $array[] = sprintf("%s=%s", $key, $val);\r
+               continue;\r
+       }\r
+       return;\r
 }\r
 \r
 /**\r
+ * revertArrayForSanitizing()\r
  * Revert array after sanitizeArray function\r
+ * \r
+ * @param      array   $array  element of query according to application/x-www-form-urlencoded\r
+ * @param      array   &$dst   combination of key and value\r
+ * @return     void\r
  */\r
 function revertArrayForSanitizing($array, &$dst)\r
 {\r
-    foreach ($array as $v) {\r
-        list($key, $val) = preg_split("/=/", $v, 2);\r
-        $dst[$key] = $val;\r
-    }\r
+       foreach ( $array as $v )\r
+       {\r
+               list($key, $val) = preg_split("#=#", $v, 2);\r
+               $dst[$key] = $val;\r
+               continue;\r
+       }\r
+       return;\r
 }\r
 \r
 /**\r
index e717d8e..aebcc25 100644 (file)
@@ -20,13 +20,19 @@ class i18n
 {\r
        static private $mode = FALSE;\r
        \r
-       static private $charset = '';\r
-       static private $language = '';\r
-       static private $script = '';\r
-       static private $region = '';\r
+       static private $current_charset = '';\r
+       static private $current_language = '';\r
+       static private $current_script = '';\r
+       static private $current_region = '';\r
+       \r
        static private $locale_list = array();\r
        static private $timezone = 'UTC';\r
        \r
+       static private $forced_charset = '';\r
+       static private $forced_language = '';\r
+       static private $forced_script = '';\r
+       static private $forced_region = '';\r
+       \r
        /**\r
         * i18n::init\r
         * Initializing i18n class\r
@@ -68,7 +74,7 @@ class i18n
                         && iconv_set_encoding('output_encoding', $charset)\r
                         && iconv_set_encoding('internal_encoding', $charset) )\r
                        {\r
-                               self::$charset = $charset;\r
+                               self::$current_charset = $charset;\r
                                self::$mode = 'iconv';\r
                        }\r
                }\r
@@ -79,7 +85,7 @@ class i18n
                         && mb_internal_encoding($charset)\r
                         && mb_regex_encoding($charset) )\r
                        {\r
-                               self::$charset = $charset;\r
+                               self::$current_charset = $charset;\r
                                self::$mode = 'mbstring';\r
                        }\r
                }\r
@@ -110,7 +116,7 @@ class i18n
         */\r
        static public function get_current_charset()\r
        {\r
-               return self::$charset;\r
+               return self::$current_charset;\r
        }\r
        \r
        /**\r
@@ -131,9 +137,9 @@ class i18n
        {\r
                if ( preg_match('#^(.+)_(.+)_(.+)$#', $locale, $match) )\r
                {\r
-                       self::$language = $match[1];\r
-                       self::$script   = $match[2];\r
-                       self::$region   = $match[3];\r
+                       self::$current_language = $match[1];\r
+                       self::$current_script   = $match[2];\r
+                       self::$current_region   = $match[3];\r
                        return TRUE;\r
                }\r
                return FALSE;\r
@@ -149,11 +155,78 @@ class i18n
         */\r
        static public function get_current_locale()\r
        {\r
-               $elements = array(self::$language, self::$script, self::$region);\r
+               $elements = array(self::$current_language, self::$current_script, self::$current_region);\r
                return implode('_', $elements);\r
        }\r
        \r
        /**\r
+        * i18n::set_forced_locale()\r
+        * Set forced locale\r
+        * \r
+        * @static\r
+        * @param       string  $forced_locale\r
+        * @return      bool    TRUE/FALSE\r
+        * \r
+        */\r
+       static public function set_forced_locale($forced_locale)\r
+       {\r
+               if ( preg_match('#^(.+)_(.+)_(.+)$#', $forced_locale, $match) )\r
+               {\r
+                       self::$forced_language  = $match[1];\r
+                       self::$forced_script    = $match[2];\r
+                       self::$forced_region    = $match[3];\r
+                       return TRUE;\r
+               }\r
+               return FALSE;\r
+       }\r
+       \r
+       /**\r
+        * i18n::get_forced_locale\r
+        * Get forced locale\r
+        * \r
+        * @static\r
+        * @param       void\r
+        * @return      $forced_locale\r
+        */\r
+       static public function get_forced_locale()\r
+       {\r
+               if ( !self::$forced_language )\r
+               {\r
+                       return;\r
+               }\r
+               \r
+               $elements = array(self::$forced_language, self::$forced_script, self::$forced_region);\r
+               return implode('_', $elements);\r
+       }\r
+       \r
+       /**\r
+        * i18n::set_forced_charset\r
+        * return forced charset\r
+        * \r
+        * @static\r
+        * @param       void    $charset        forced character set\r
+        * @return      void\r
+        */\r
+       static public function set_forced_charset($forced_charset)\r
+       {\r
+               self::$forced_charset = $forced_charset;\r
+               return;\r
+       }\r
+       \r
+       /**\r
+        * i18n::get_forced_charset\r
+        * return forced charset\r
+        * \r
+        * @static\r
+        * @param       void\r
+        * @return      string  $charset        forced character set\r
+        */\r
+       static public function get_forced_charset()\r
+       {\r
+               return self::$forced_charset;\r
+       }\r
+       \r
+       /**\r
         * i18n::confirm_default_date_timezone\r
         * to avoid E_NOTICE or E_WARNING generated when every calling to a date/time function.\r
         * \r
@@ -205,10 +278,14 @@ class i18n
        {\r
                if ( $to == '' )\r
                {\r
-                       $to = self::$charset;\r
+                       $to = self::$current_charset;\r
                }\r
                \r
-               if ( self::$mode == 'iconv' )\r
+               if ( $from == $to )\r
+               {\r
+                       /* do nothing */\r
+               }\r
+               else if ( self::$mode == 'iconv' )\r
                {\r
                        $string = iconv($from, $to.'//TRANSLIT', $string);\r
                }\r
@@ -220,6 +297,51 @@ class i18n
        }\r
        \r
        /**\r
+        * i18n::convert_handler\r
+        * callable handler for character set converter\r
+        * \r
+        * @static\r
+        * @param       string  $string target string binary\r
+        * @return      void\r
+        */\r
+       static public function convert_handler($string)\r
+       {\r
+               return self::convert($string, self::$current_charset, self::$forced_charset);\r
+       }\r
+       \r
+       /**\r
+        * i18n::convert_array\r
+        * recursively converting array\r
+        * \r
+        * @static\r
+        * @param       array   $array  array to convert\r
+        * @return      void\r
+        */\r
+       static public function convert_array($array, $from, $to='')\r
+       {\r
+               if ( !is_array($array) )\r
+               {\r
+                       $array = self::convert($array, $from, $to);\r
+               }\r
+               else\r
+               {\r
+                       foreach ( $array as $key => $value )\r
+                       {\r
+                               if ( !is_array($value) )\r
+                               {\r
+                                       $array[$key] = self::convert($value, $from, $to);\r
+                               }\r
+                               else\r
+                               {\r
+                                       self::convert_array($array[$key]);\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               return $array;\r
+       }\r
+       \r
+       /**\r
         * i18n::strlen\r
         * strlen wrapper\r
         * \r
@@ -232,11 +354,11 @@ class i18n
                $length = 0;\r
                if ( self::$mode == 'iconv' )\r
                {\r
-                       $length = iconv_strlen($string, self::$charset);\r
+                       $length = iconv_strlen($string, self::$current_charset);\r
                }\r
                else if ( self::$mode == 'mbstring' )\r
                {\r
-                       $length = mb_strlen($string, self::$charset);\r
+                       $length = mb_strlen($string, self::$current_charset);\r
                }\r
                else\r
                {\r
@@ -260,11 +382,11 @@ class i18n
                $position = 0;\r
                if ( self::$mode == 'iconv' )\r
                {\r
-                       $position = iconv_strpos($haystack, $needle, $offset, self::$charset);\r
+                       $position = iconv_strpos($haystack, $needle, $offset, self::$current_charset);\r
                }\r
                else if ( self::$mode == 'mbstring' )\r
                {\r
-                       $position = mb_strpos($haystack, $needle, $offset, self::$charset);\r
+                       $position = mb_strpos($haystack, $needle, $offset, self::$current_charset);\r
                }\r
                else\r
                {\r
@@ -292,11 +414,11 @@ class i18n
                $position = 0;\r
                if ( self::$mode == 'iconv' )\r
                {\r
-                       $position = iconv_strrpos($haystack, $needle, self::$charset);\r
+                       $position = iconv_strrpos($haystack, $needle, self::$current_charset);\r
                }\r
                else if ( self::$mode == 'mbstring' )\r
                {\r
-                       $position = mb_strrpos($haystack, $needle, 0, self::$charset);\r
+                       $position = mb_strrpos($haystack, $needle, 0, self::$current_charset);\r
                }\r
                else\r
                {\r
@@ -325,11 +447,11 @@ class i18n
                $return = '';\r
                if ( self::$mode == 'iconv' )\r
                {\r
-                       $return = iconv_substr($string, $start, $length, self::$charset);\r
+                       $return = iconv_substr($string, $start, $length, self::$current_charset);\r
                }\r
                else if ( self::$mode == 'mbstring' )\r
                {\r
-                       $return = mb_substr($string, $start, $length, self::$charset);\r
+                       $return = mb_substr($string, $start, $length, self::$current_charset);\r
                }\r
                else\r
                {\r
@@ -473,7 +595,7 @@ class i18n
                {\r
                        if ( preg_match('#-#', $language) )\r
                        {\r
-                               if ( $target_locale . '.' . self::$charset == $locale )\r
+                               if ( $target_locale . '.' . self::$current_charset == $locale )\r
                                {\r
                                        $target_language = $language;\r
                                        break;\r