// vim: tabstop=2:shiftwidth=2
/**
- * NP_OpenId ($Revision: 1.2 $)
+ * NP_OpenId ($Revision: 1.3 $)
* by hsur ( http://blog.cles.jp/np_cles )
- * $Id: NP_OpenId.php,v 1.2 2008-06-07 19:33:43 hsur Exp $
+ * $Id: NP_OpenId.php,v 1.3 2008-06-10 14:35:12 hsur Exp $
*
*/
require_once 'cles/SQLStoreForNucleus.php';
require_once 'Auth/OpenID/SReg.php';
require_once 'Auth/OpenID/PAPE.php';
+require_once 'Jsphon.php';
class NP_OpenId extends NucleusPlugin {
return 'http://blog.cles.jp/np_cles/category/31/subcatid/21';
}
function getVersion() {
- return '1.1.0';
+ return '1.1.1';
}
function getMinNucleusVersion() {
return 330;
);
}
function getDescription() {
- return '[$Revision: 1.2 $]<br />Adds OpenID authentication to anonymous comment, to prevent robots from spamming.';
+ return '[$Revision: 1.3 $]<br />Adds OpenID authentication to anonymous comment, to prevent robots from spamming.';
}
function supportsFeature($what) {
switch ($what) {
@mkdir($store_path);
$this->store = new Auth_OpenID_FileStore($store_path);
*/
+ // include language file for this plugin
+ $language = ereg_replace( '[\\|/]', '', getLanguageName());
+ if (file_exists($this->getDirectory().'language/'.$language.'.php'))
+ @ include_once($this->getDirectory().'language/'.$language.'.php');
+ else
+ @ include_once($this->getDirectory().'language/english.php');
$this->store = new cles_SQLStoreForNucleus();
$this->consumer = new Auth_OpenID_Consumer($this->store);
break;
case 'updateProfile':
- $te = $this->_getTemplateEngine();
$aVars = array();
if( $this->isLoggedin() ){
$profile = array();
$aVars['email'] = requestVar('email');
$this->_doUpdateProfile($aVars);
- echo $te->fetchAndFill('updatesucceeded', $aVars, strtolower(__CLASS__));
+
+ $aVars['message'] = NP_OPENID_updateSucceeded;
+ $aVars['result'] = 'succeeded';
} else {
- $aVars['message'] = 'You aren\'t logged in.';
- echo $te->fetchAndFill('updatefailed', $aVars, strtolower(__CLASS__));
+ $aVars['message'] = NP_OPENID_notloggedin;
+ $aVars['result'] = 'failure';
}
+
+ // return JSON
+ if(_CHARSET != 'UTF-8') mb_convert_variables('UTF-8', _CHARSET, $aVars);
+ echo Jsphon::encode($aVars);
exit;
//break;
default:
$this->loggedinUser['nick'] = $profile['nick'];
$this->loggedinUser['email'] = $profile['email'];
-
- setcookie($CONF['CookiePrefix'] . 'comment_user', $this->loggedinUser['nick'], 0, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
- setcookie($CONF['CookiePrefix'] . 'comment_email', $this->loggedinUser['email'], 0, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
}
function _doLoginLocal($name){
function isLoggedin(){
global $CONF;
- if( $this->loggedinUser ) return true;
+ if( $this->loggedinUser['identity'] ) return true;
$cookie = cookieVar($CONF['CookiePrefix'] . NP_OPENID_AUTH_COOKIE);
if( ! $cookie ) return false;
$this->loggedinUser = array_merge($this->loggedinUser, unserialize($this->loggedinUser['sreg']));
setcookie($CONF['CookiePrefix'] . NP_OPENID_AUTH_COOKIE , $cookie, 0, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
- setcookie($CONF['CookiePrefix'] . 'comment_user', $this->loggedinUser['nick'], 0, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
- setcookie($CONF['CookiePrefix'] . 'comment_email', $this->loggedinUser['email'], 0, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
return true;
}
global $CONF;
$this->loggedinUser = null;
setcookie($CONF['CookiePrefix'] . NP_OPENID_AUTH_COOKIE, '', 0, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
- setcookie($CONF['CookiePrefix'] . 'comment_user', '', 0, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
- setcookie($CONF['CookiePrefix'] . 'comment_email', '', 0, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
return true;
}
return $this->templateEngine;
}
-}
+}
\ No newline at end of file
-<!-- $Id: help.html,v 1.2 2008-06-07 19:33:43 hsur Exp $ -->
+<!-- $Id: help.html,v 1.3 2008-06-10 14:35:11 hsur Exp $ -->
<h3>バージョン履歴</h3>
<ul>
<li> [Changed] テンプレートをプラグインオプションから、ファイルベースに変更</li>
<li> [Changed] Profileの変更にYUIを使うようにした</li>
<li> [Fixed] テーブルの作成に失敗する問題に対応</li>
+ <li> [Fixed] XSSが発生する問題を解決(v1.1.1, 2008/06/10)</li>
+ <li> [Fixed] 不必要なCookieを使わないようにした(v1.1.1, 2008/06/10)</li>
</ul>
--- /dev/null
+<?php
+
+define('NP_OPENID_updateSucceeded', 'Thanks, your profile have been updated.');
+define('NP_OPENID_notloggedin', 'You are not logged in.');
--- /dev/null
+<?php
+
+define('NP_OPENID_updateSucceeded', '¥×¥í¥Õ¥£¡¼¥ë¤Î¹¹¿·¤¬´°Î»¤·¤Þ¤·¤¿¡£');
+define('NP_OPENID_notloggedin', '¥í¥°¥¤¥ó¤·¤Æ¤¤¤Þ¤»¤ó¡£');
--- /dev/null
+<?php
+
+define('NP_OPENID_updateSucceeded', 'プロフィールの更新が完了しました。');
+define('NP_OPENID_notloggedin', 'ログインしていません。');
+++ /dev/null
-{{message|}}
\ No newline at end of file
+++ /dev/null
-document.getElementById('nucleus_cf_name').value = '{{nick}} [OpenID]';
-document.getElementById('nucleus_cf_email').value = '{{email}}';
-document.getElementById('resp').innerHTML = 'Thanks, your profile have been updated.';
+++ /dev/null
-document.getElementById('nucleus_cf_name').value = '{{nick}} [OpenID]';
-document.getElementById('nucleus_cf_email').value = '{{email}}';
-document.getElementById('resp').innerHTML = '¥×¥í¥Õ¥£¡¼¥ë¤Î¹¹¿·¤¬´°Î»¤·¤Þ¤·¤¿¡£';
+++ /dev/null
-document.getElementById('nucleus_cf_name').value = '{{nick}} [OpenID]';
-document.getElementById('nucleus_cf_email').value = '{{email}}';
-document.getElementById('resp').innerHTML = 'プロフィールの更新が完了しました。';
this.cancel();
};
var handleSuccess = function(o) {
- var response = o.responseText;
- //debug
- //document.getElementById("resp").innerHTML = response;
- eval(response);
+ var param = eval( "(" + o.responseText + ")" );
+ if( param['result'] == 'succeeded'){
+ document.getElementById('nucleus_cf_name').value = param['nick'] + ' [OpenID]';
+ document.getElementById('nucleus_cf_email').value = param['email'];
+ document.getElementById("resp").innerHTML = param['message'];
+ } else {
+ document.getElementById("resp").innerHTML = param['message'];
+ }
};
var handleFailure = function(o) {
- document.getElementById("resp").innerHTML = "Submission failed: " + o.status;
+ document.getElementById("resp").innerHTML = "Error: " + o.status;
};
// Instantiate the Dialog
--- /dev/null
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5 |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License, |
+// | that is available at http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp> |
+// +--------------------------------------------------------------------+
+//
+//
+
+define('JSPHON_ERROR_DECODE_SYNTAX', 1);
+
+require_once(dirname(__FILE__) .'/Jsphon/Error.php');
+require_once(dirname(__FILE__) .'/Jsphon/Decoder.php');
+require_once(dirname(__FILE__) .'/Jsphon/Encoder.php');
+
+Jsphon_Error::singleton();
+
+/**
+ * Jsphon - JSON in PHP
+ *
+ * example:
+ * <code>
+ * //encode
+ * $value = array('foo', 'bar', array('hoge' => array(1,2)));
+ * $json = Jsphon::encode($value);
+ * echo $json;
+ *
+ * //decode
+ * $var = Jsphon::decode($json);
+ * echo $var[2]['hoge'];
+ *
+ * </code>
+ *
+ * @author Hawk
+ */
+class Jsphon
+{
+ /**
+ * Encodes an arbitrary variables into JSON format.
+ * See Jsphon_Encoder::encode() for details.
+ *
+ * @param String $value
+ * @param boolean $escapeNonASCII
+ * @param boolean $escapeOverUCS2
+ * @return String
+ */
+ function encode($value, $escapeNonASCII=true, $escapeOverUCS2=false)
+ {
+ $encoder = new Jsphon_Encoder($escapeNonASCII, $escapeOverUCS2);
+ return $encoder->encode($value);
+ }
+
+
+ /**
+ * Decodes JSON-formatted string into appropriate PHP variable.
+ * See Jsphon_Decoder::decode() for details.
+ *
+ * @param String $json
+ * @param String $decodeOverUCS2
+ * @return mixed
+ */
+ function decode($json, $decodeOverUCS2=false)
+ {
+ $decoder = new Jsphon_Decoder($decodeOverUCS2);
+ return $decoder->decode($json);
+ }
+
+}
+
+?>
--- /dev/null
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5 |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License, |
+// | that is available at http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp> |
+// +--------------------------------------------------------------------+
+//
+//
+
+require_once(dirname(__FILE__) .'/Decoder/Tokenizer.php');
+
+/**
+ * Converts JSON-formatted string to appropriate PHP variable
+ *
+ * example:
+ * <code>
+ * //create a new instance of Jsphon_Decoder
+ * $json =& new Jsphon_Decoder();
+ *
+ * //convert JSON-formatted string to PHP variable
+ * $value = '["foo","bar",{"hoge":[1,2]}]';
+ * $var = $json->decode($value);
+ *
+ * print_r($var);
+ * //array('foo', 'bar', array('hoge' => array(1,2)))
+ * </code>
+ *
+ * @author Hawk
+ */
+class Jsphon_Decoder
+{
+ var $_mbstring;
+
+ var $_decodeOverUCS2;
+
+ var $_internalError;
+
+ var $_transTable = array(
+ '\b' => "\x08",
+ '\t' => "\x09",
+ '\n' => "\x0A",
+ '\f' => "\x0C",
+ '\r' => "\x0D",
+ '\"' => "\x22",
+ '\/' => "\x2F",
+ '\\\\' => "\x5C"
+ );
+
+ var $_allUESreg = '/\\\u([a-fA-F0-9]{4})/';
+
+ var $_utf16surUESreg = '/\\\u(D[89AB][A-F0-9]{2})\\\u(D[C-F][A-F0-9]{2})/i';
+
+ /**
+ * construct a new Jsphon_Decoder instance.
+ *
+ * @param bool $decodeOverUCS2 If true, decodeString() converts the whole
+ * Unicode escape sequences (\uXXXX) including surrogate pairs
+ * to corresponding characters in UTF-8.
+ */
+ function Jsphon_Decoder($decodeOverUCS2=false)
+ {
+ $this->_decodeOverUCS2 = $decodeOverUCS2;
+ $this->_mbstring = extension_loaded('mbstring');
+ }
+
+ /**
+ * decodes a JSON string into appropriate variable
+ *
+ * @param String $json
+ * @return mixed
+ */
+ function decode($json)
+ {
+ $tknz = new Jsphon_Decoder_Tokenizer($json,
+ array(&$this, 'handleInternalError'));
+ $this->_internalError = false;
+
+ $result = null;
+ if($tknz->nextToken()) {
+ $result = $this->_decodeJSValue($tknz);
+ }
+
+ $this->_internalError = false;
+ return $result;
+ }
+
+ /**
+ *
+ * @param Object $tknz
+ * @return mixed
+ */
+ function _decodeJSValue(&$tknz)
+ {
+ switch($tknz->getToken()) {
+ case JSPHON_TOKEN_DATUM:
+ if(is_string($r = $tknz->getTokenValue())) {
+ $r = $this->decodeString($r);
+ }
+ return $r;
+
+ case JSPHON_TOKEN_LBRACKET:
+ return $this->_decodeArray($tknz);
+
+ case JSPHON_TOKEN_LBRACE:
+ return $this->_decodeObject($tknz);
+
+ default:
+ $this->_error("syntax error: Expecting '{', '[' or DAUM.");
+ return null;
+ }
+ }
+
+ /**
+ * Decodes a JSON array format:
+ * [element, element2,...,elementN]
+ *
+ * @param Object $tknz
+ * @return array
+ */
+ function _decodeArray(&$tknz)
+ {
+ $ret = array();
+ if(!($token = $tknz->nextToken())) {
+ return null;
+
+ } elseif($token == JSPHON_TOKEN_RBRACKET) {
+ return $ret;
+ }
+
+ //if false, break
+ while( ($value = $this->_decodeJSValue($tknz) or true)
+ and !$this->_internalError
+ and ($ret[] = $value or true)
+ and $token = $tknz->nextToken()
+ and $token == JSPHON_TOKEN_COMMA
+ and $token = $tknz->nextToken()
+ );
+
+ if($this->_internalError) {
+ return null;
+
+ } elseif($token == JSPHON_TOKEN_RBRACKET) {
+ return $ret;
+ } else {
+ $this->_error("Missing ',' or ']' in array encoding.");
+ return null;
+ }
+ }
+
+ /**
+ * Decodes an object of the form:
+ * { "attribute: value, "attribute2" : value,...}
+ *
+ * _decodeObject() always converts a JSON-object to an associative array,
+ * because you can't access empty property in PHP5.
+ * <code>
+ * // { "":"foo" }
+ * $obj->{""} = "foo"; //Fatal error: Cannot access empty property
+ * </code>
+ *
+ * @param Object $tknz
+ * @return array
+ */
+ function _decodeObject(&$tknz)
+ {
+ $ret = array();
+ if(!($token = $tknz->nextToken())) {
+ return null;
+
+ } elseif($token == JSPHON_TOKEN_RBRACE) {
+ return $ret;
+ }
+
+ //if false, break
+ while( ($key = $this->_decodeJSValue($tknz) or true)
+ and !$this->_internalError
+ and $this->_checkObjectKey($key)
+ and $token = $tknz->nextToken()
+ and $this->_checkKeyValueSep($token)
+ and $token = $tknz->nextToken()
+ and ($value = $this->_decodeJSValue($tknz) or true)
+ and !$this->_internalError
+ and ($ret[$key] = $value or true)
+ and $token = $tknz->nextToken()
+ and $token == JSPHON_TOKEN_COMMA
+ and $token = $tknz->nextToken()
+ );
+
+ if($this->_internalError) {
+ return null;
+
+ } elseif($token == JSPHON_TOKEN_RBRACE) {
+ return $ret;
+ } else {
+ $this->_error("Missing ',' or '}' in object encoding.");
+ return null;
+ }
+ }
+
+ function _checkObjectKey($key)
+ {
+ if(!is_string($key)) {
+ $this->_error("Object's key must be a string, but is ". gettype($key));
+ return false;
+ }
+ return true;
+ }
+
+ function _checkKeyValueSep($token)
+ {
+ if($token != JSPHON_TOKEN_COLON) {
+ $this->_error("Missing ':' in object encoding.");
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ *
+ *
+ * @param String $encoded
+ * @return String
+ */
+ function decodeString($encoded)
+ {
+ $ret = strtr($encoded, $this->_transTable);
+
+ if($this->_decodeOverUCS2) {
+ return $this->_decodeUESOverUCS2($ret);
+ } else {
+ //_decodeUESWithoutMbstring() fastar than _decodeUES()...
+ return $this->_decodeUESWithoutMbstring($ret);
+ }
+
+ /*
+ if(!$this->_mbstring) {
+ return $this->_decodeUESWithoutMbstring($ret);
+ } elseif($this->_decodeOverUCS2) {
+ return $this->_decodeUESOverUCS2($ret);
+ } else {
+ return $this->_decodeUES($ret);
+ }
+ */
+ }
+
+ function _decodeUES($str)
+ {
+ $transTable = array();
+
+ if(!preg_match_all($this->_allUESreg, $str, $matches)) {
+ return $str;
+ }
+
+ $codepoints = $matches[1];
+ foreach($matches[0] as $i => $escSeq) {
+ if(isset($transTable[$escSeq])) {
+ continue;
+ }
+ $codepoint = hexdec($codepoints[$i]);
+ $transTable[$escSeq] = (0xD800 <= $codepoint && $codepoint <= 0xDFFF) ? ""
+ : mb_convert_encoding(pack('n', $codepoint), 'UTF-8', 'UCS-2');
+ }
+ return strtr($str, $transTable);
+ }
+
+ function _decodeUESOverUCS2($str)
+ {
+ $transTable = array();
+
+ if(!preg_match_all($this->_allUESreg, $str, $u16)) {
+ return $str;
+ }
+
+ if(preg_match_all($this->_utf16surUESreg, $str, $u16sur)) {
+ $sur1st = $u16sur[1];
+ $sur2nd = $u16sur[2];
+
+ foreach($u16sur[0] as $i => $escSeq) {
+ if(isset($transTable[$escSeq])) {
+ continue;
+ }
+ $transTable[$escSeq] = mb_convert_encoding(
+ pack('n2', hexdec($sur1st[$i]), hexdec($sur2nd[$i])), 'UTF-8', 'UTF-16BE');
+ }
+ }
+
+ $codepoints = $u16[1];
+ foreach($u16[0] as $i => $escSeq) {
+ if(isset($transTable[$escSeq])) {
+ continue;
+ }
+ $codepoint = hexdec($codepoints[$i]);
+ $transTable[$escSeq] = (0xD800 <= $codepoint && $codepoint <= 0xDFFF) ? ""
+ : mb_convert_encoding(pack('n', $codepoint), 'UTF-8', 'UCS-2');
+ }
+ return strtr($str, $transTable);
+ }
+
+ function _decodeUESWithoutMbstring($str)
+ {
+ $transTable = array();
+
+ if(!preg_match_all($this->_allUESreg, $str, $matches)) {
+ return $str;
+ }
+
+ $codepoints = $matches[1];
+ foreach($matches[0] as $i => $escSeq) {
+ if(isset($transTable[$escSeq])) {
+ continue;
+ }
+
+ $utf8char = "";
+
+ $cp = hexdec($codepoints[$i]);
+ switch(true) {
+ case ($cp < 0x80):
+ $utf8char = chr($cp);
+ break;
+
+ case (0xD800 <= $cp && $cp <= 0xDFFF):
+ break;
+
+ case ($cp < 0x800):
+ $utf8char = chr($cp >> 6 & 0x1F | 0xC0) . chr($cp & 0x3F | 0x80);
+ break;
+
+ case ($cp < 0x10000):
+ $utf8char = chr($cp >> 12 & 0xF | 0xE0) .
+ chr($cp >> 6 & 0x3F | 0x80) . chr($cp & 0x3F | 0x80);
+ break;
+
+ default:
+ }
+ $transTable[$escSeq] = $utf8char;
+ }
+ return strtr($str, $transTable);
+ }
+
+
+ /**
+ * a simple wrapper for PEAR_ErrorStack::push.
+ *
+ * @param String $message
+ * @param array $param
+ * @param string $level
+ * @param int $code
+ * @return String
+ */
+ function _error($message,
+ $param= array(),
+ $level='error',
+ $code=JSPHON_ERROR_DECODE_SYNTAX)
+ {
+ $e = Jsphon_Error::push(
+ $code, $level, $param, $message, false, debug_backtrace());
+ $this->_internalError = true;
+ return $e;
+ }
+
+ function handleInternalError($err)
+ {
+ $this->_internalError = true;
+ }
+}
+
+?>
--- /dev/null
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5 |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License, |
+// | that is available at http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp> |
+// +--------------------------------------------------------------------+
+//
+//
+
+define('JSPHON_TOKEN_EOF', 1);
+define('JSPHON_TOKEN_DATUM', 2);
+define('JSPHON_TOKEN_LBRACE', 3);
+define('JSPHON_TOKEN_LBRACKET', 4);
+define('JSPHON_TOKEN_RBRACE', 5);
+define('JSPHON_TOKEN_RBRACKET', 6);
+define('JSPHON_TOKEN_COMMA', 7);
+define('JSPHON_TOKEN_COLON', 8);
+
+/**
+ * Jsphon_Decoder_Tokenizer
+ *
+ * @author Hawk
+ */
+class Jsphon_Decoder_Tokenizer
+{
+ var $_source;
+
+ var $_token;
+
+ var $_tokenValue;
+
+ var $_tokenTable = array(
+ '{' => JSPHON_TOKEN_LBRACE,
+ '}' => JSPHON_TOKEN_RBRACE,
+ '[' => JSPHON_TOKEN_LBRACKET,
+ ']' => JSPHON_TOKEN_RBRACKET,
+ ',' => JSPHON_TOKEN_COMMA,
+ ':' => JSPHON_TOKEN_COLON
+ );
+
+ var $_tokenValueTable = array(
+ 'true' => true,
+ 'false' => false,
+ 'null' => null
+ );
+
+ var $_errorCallback;
+
+ /**
+ * constructs a new Jsphon_Decoder_Tokenizer instance.
+ *
+ * @param String $source
+ */
+ function Jsphon_Decoder_Tokenizer($source, $internalErrorCallback=null)
+ {
+ $this->_source = $source;
+ $this->_errorCallback = $internalErrorCallback;
+ }
+
+ /**
+ * Retrieves the next token from the source stream.
+ *
+ * @return int or false
+ */
+ function nextToken()
+ {
+ $src = ltrim($this->_source);
+
+ $this->_tokenValue = null;
+ $this->_token = JSPHON_TOKEN_EOF;
+
+ switch(true)
+ {
+ case $src === '':
+ break;
+
+ case ($c = $src{0}) !== "" and isset($this->_tokenTable[$c]):
+ $this->_token = $this->_tokenTable[$c];
+ $src = substr($src, 1);
+ break;
+
+ case $c == '"' and preg_match('/^"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"/', $src, $m):
+ $this->_token = JSPHON_TOKEN_DATUM;
+ $this->_tokenValue = $m[1];
+ $src = substr($src, strlen($m[0]));
+ break;
+
+ case preg_match('/^(true|false|null)\b/', $src, $m):
+ $this->_token = JSPHON_TOKEN_DATUM;
+ $this->_tokenValue = $this->_tokenValueTable[$m[1]];
+ $src = substr($src, ($m[1]{0} == 'f' ? 5 : 4));
+ break;
+
+ case preg_match('/^-?(?:[1-9]\d+|\d)(?:\.\d+)?(?:[eE][-+]?\d+)?/', $src, $m):
+ $this->_token = JSPHON_TOKEN_DATUM;
+ $intV = (int)$m[0];
+ $floatV = (float)$m[0];
+ $this->_tokenValue = ($intV == $floatV) ? $intV : $floatV;
+ $src = substr($src, strlen($m[0]));
+ break;
+
+ default:
+ $err = Jsphon_Error::push(
+ JSPHON_ERROR_DECODE_SYNTAX,
+ 'error',
+ array(),
+ 'Illegal Token',
+ false,
+ debug_backtrace());
+
+ if(is_callable($this->_errorCallback)) {
+ call_user_func($this->_errorCallback, $err);
+ }
+ return false;
+
+ }
+
+ $this->_source = $src;
+ return $this->_token;
+ }
+
+ function getToken()
+ {
+ return $this->_token;
+ }
+
+ function getTokenValue()
+ {
+ return $this->_tokenValue;
+ }
+
+}
+
+?>
--- /dev/null
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5 |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License, |
+// | that is available at http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp> |
+// +--------------------------------------------------------------------+
+//
+//
+
+/**
+ * Converts to JSON format.
+ *
+ * example:
+ * <code>
+ * //create a new instance of Jsphon_Encoder
+ * $json =& new Jsphon_Encoder();
+ *
+ * //convert a complex value to JSON notation, and send it to the browser
+ * $value = array('foo', 'bar', array('hoge' => array(1,2)));
+ * $output = $json->encode($value);
+ *
+ * print_r($output);
+ * //prints: ["foo","bar",{"hoge":[1,2]}]
+ * </code>
+ *
+ * @author Hawk
+ */
+class Jsphon_Encoder
+{
+ var $_mbstring;
+
+ var $_escapeNonASCII;
+
+ var $_escapeOverUCS2;
+
+ var $_transTable;
+
+ var $_utf8UCS2reg;
+
+ var $_utf8overUCS2reg;
+
+ /**
+ * constructs a new Jsphon_Encoder instance.
+ *
+ * @param bool $escapeNonASCII If true, encode() converts non-ASCII characters
+ * to Unicode escape sequence (\uXXXX).
+ * @param bool $escapeOverUCS2 If true, encode() converts all the non-ASCII characters
+ * that is encodable in UTF-16 to Unicode escape sequence.
+ * This parameter affects the encoder's behavior
+ * only if $escapeNonASCII is set to true and
+ * the multibyte string extension is available.
+ *
+ */
+ function Jsphon_Encoder($escapeNonASCII=true, $escapeOverUCS2=false)
+ {
+ $this->_escapeNonASCII = $escapeNonASCII;
+ $this->_escapeOverUCS2 = $escapeOverUCS2;
+ $this->_mbstring = extension_loaded('mbstring');
+
+ $this->_transTable = array(
+ "\x08" => '\b',
+ "\x09" => '\t',
+ "\x0A" => '\n',
+ "\x0C" => '\f',
+ "\x0D" => '\r',
+ "\x22" => '\"',
+ "\x2F" => '\/',
+ "\x5C" => '\\\\'
+ );
+
+ $utf8ucs2 = '[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}';
+ $utf16sur = '[\xF0-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2}';
+ $this->_utf8UCS2reg = "/{$utf8ucs2}/";
+ $this->_utf8overUCS2reg = "/{$utf8ucs2}|{$utf16sur}/";
+ }
+
+ /**
+ * encodes an arbitrary variables into JSON format.
+ *
+ * If $_escapeNonASCII is set to true,
+ * encode() removes all non-ASCII characters to make sure that
+ * returning value dosen't contain any non-ASCII characters.
+ *
+ * @param mixed $value
+ * @return string
+ */
+ function encode($value)
+ {
+ $json = $this->_encode($value);
+ if($this->_escapeNonASCII) {
+ $json = preg_replace('/[\x80-\xFF]/', '', $json);
+ }
+ return $json;
+ }
+
+ function _encode($value)
+ {
+ if($value === null) {
+ return 'null';
+
+ } elseif(is_bool($value)) {
+ return $value ? 'true' : 'false';
+
+ } elseif(is_int($value)) {
+ return (int)$value;
+
+ } elseif(is_float($value)) {
+ return (float)$value;
+
+ } elseif(is_string($value)) {
+ return '"'. $this->_encodeString($value) .'"';
+
+ } elseif(is_array($value)) {
+ if(($len = count($value)) > 0 &&
+ array_keys($value) !== range(0, $len - 1)) {
+ return $this->_encodeObject($value);
+ } else {
+ return '['. join(',', array_map(array(&$this, '_encode'), $value)) .']';
+ }
+
+ } elseif(is_object($value)) {
+ return $this->_encodeObject($value);
+
+ }
+
+ return 'null';
+ }
+
+ function _encodeObject($arr)
+ {
+ $result = array();
+ foreach($arr as $name => $value) {
+ $result[] = $this->_encode((string)$name) .':'. $this->_encode($value);
+ }
+ return '{'. join(',', $result) ."}";
+ }
+
+ function _encodeString($str)
+ {
+ $str = strtr($str, $this->_transTable);
+
+ if(!$this->_escapeNonASCII) {
+ return $str;
+ }
+
+ if(!$this->_mbstring) {
+ return $this->_escapeNonASCIIWithoutMbstring($str);
+ }
+
+ if($this->_escapeOverUCS2) {
+ return $this->_escapeNonASCIIOverUCS2($str);
+ } else {
+ return $this->_escapeNonASCII($str);
+ }
+ }
+
+ function _escapeNonASCII($str)
+ {
+ $transTable = array();
+
+ if(!preg_match_all($this->_utf8UCS2reg, $str, $matches)) {
+ return $str;
+ }
+
+ foreach($matches[0] as $utf8char) {
+ if(isset($transTable[$utf8char])) {
+ continue;
+ }
+ $transTable[$utf8char] = $this->_formatSeq(
+ mb_convert_encoding($utf8char, 'UTF-16', 'UTF-8'));
+ }
+ return strtr($str, $transTable);
+ }
+
+ function _escapeNonASCIIOverUCS2($str)
+ {
+ $transTable = array();
+
+ if(!preg_match_all($this->_utf8overUCS2reg, $str, $matches)) {
+ return $str;
+ }
+
+ foreach($matches[0] as $utf8char) {
+ if(isset($transTable[$utf8char])) {
+ continue;
+ }
+ $utf16char = mb_convert_encoding($utf8char, 'UTF-16', 'UTF-8');
+
+ if(($l = strlen($utf16char)) == 2) {
+ $transTable[$utf8char] = $this->_formatSeq($utf16char);
+ } elseif($l == 4) {
+ $transTable[$utf8char] =
+ $this->_formatSeq(substr($utf16char, 0, 2)) . $this->_formatSeq(substr($utf16char, 2));
+ }
+
+ }
+ return strtr($str, $transTable);
+ }
+
+ function _escapeNonASCIIWithoutMbstring($str)
+ {
+ $transTable = array();
+
+ if(!preg_match_all($this->_utf8UCS2reg, $str, $matches)) {
+ return $str;
+ }
+
+ foreach($matches[0] as $utf8char) {
+ if(isset($transTable[$utf8char])) {
+ continue;
+ }
+
+ switch(strlen($utf8char)) {
+ case 2:
+ $code = (
+ ((ord($utf8char{0}) & 0x1F) << 6) |
+ (ord($utf8char{1}) & 0x3F)
+ );
+ break;
+
+ case 3:
+ $code = (
+ ((ord($utf8char{0}) & 0x0F) << 12) |
+ ((ord($utf8char{1}) & 0x3F) << 6 ) |
+ (ord($utf8char{2}) & 0x3F)
+ );
+ break;
+ default:
+ }
+ $transTable[$utf8char] = '\u'. substr('0000'. dechex($code), -4);
+ }
+ return strtr($str, $transTable);
+ }
+
+ function _formatSeq($u16)
+ {
+ return '\u'. substr('0000'. bin2hex($u16), -4);
+ }
+}
+
+?>
--- /dev/null
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5 |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License, |
+// | that is available at http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp> |
+// +--------------------------------------------------------------------+
+//
+//
+
+/**
+ * Jsphon_Error
+ *
+ * @author Hawk
+ */
+class Jsphon_Error
+{
+ var $_isPHP5;
+
+ var $_existsPEAR;
+
+ var $_throwException = true;
+
+ var $_exceptionCreator;
+
+ /**
+ * Constructor
+ *
+ * @access private
+ */
+ function Jsphon_Error()
+ {
+ $this->_isPHP5 = version_compare(phpversion(), '5', '>=');
+ $this->_existsPEAR = (@include_once "PEAR/ErrorStack.php");
+
+ if($this->_isPHP5) {
+ if($this->_existsPEAR) {
+ require_once(dirname(__FILE__) .'/Exception.php');
+ $method = '_createJsphonException';
+ } else {
+ $method = '_createException';
+ }
+ $this->_exceptionCreator = array(__CLASS__, $method);
+ }
+ }
+
+ /**
+ *
+ *
+ * @since 06/09/05 13:21
+ * @return Jsphon_Error
+ */
+ function &singleton()
+ {
+ static $instance = null;
+ if($instance === null) {
+ $instance = new Jsphon_Error();
+ }
+ return $instance;
+ }
+
+ /**
+ *
+ * @static
+ * @param int $code
+ * @param string $level
+ * @param array $params
+ * @param string $msg
+ * @param mixed $repackage
+ * @param array $backtrace
+ * @return array
+ */
+ function push($code, $level = 'error', $params = array(), $msg = false,
+ $repackage = false, $backtrace = false)
+ {
+ if (!$backtrace) {
+ $backtrace = debug_backtrace();
+ }
+
+ $self =& Jsphon_Error::singleton();
+
+ if(!$self->_isPHP5 || !$self->_throwException) {
+ return $self->_push(
+ $code, $level, $params, $msg, $repackage, $backtrace);
+ }
+
+ $pushOnly = true;
+ $err = $self->_push(
+ $code, $level, $params, $msg, $repackage, $backtrace, $pushOnly);
+
+ array_shift($backtrace);
+ throw (call_user_func($self->_exceptionCreator, $msg, $code, $backtrace));
+ return ;
+ }
+
+ /**
+ *
+ *
+ * @access private
+ * @static
+ * @param int $code
+ * @param string $level
+ * @param array $params
+ * @param string $msg
+ * @param mixed $repackage
+ * @param array $backtrace
+ * @param bool $pushOnly
+ * @return array or null unless PEAR_ErrorStack exists.
+ */
+ function _push($code, $level='error', $params=array(), $msg=false,
+ $repackage=false, $backtrace=false, $pushOnly=false)
+ {
+ if(!$this->_existsPEAR) {
+ return;
+ }
+
+ $stack =& PEAR_ErrorStack::singleton('Jsphon');
+ if($pushOnly) {
+ $stack->pushCallback(array(__CLASS__, 'pushOnly'));
+ }
+
+ $err = $stack->push($code, $level, $params, $msg, $repackage, $backtrace);
+
+ if($pushOnly) {
+ $stack->popCallback();
+ }
+ return $err;
+ }
+
+ /**
+ *
+ * @since 06/09/05 13:34
+ * @param String $bool
+ * @param String $exceptionClass
+ * @return String
+ */
+ function setThrowException($bool)
+ {
+ $this->_throwException = $bool;
+ }
+
+ /**
+ * error handler which do nothing
+ *
+ * @since 06/09/05 13:52
+ * @param array $err
+ * @return int
+ */
+ function pushOnly($err)
+ {
+ return PEAR_ERRORSTACK_PUSH;
+ }
+
+ /**
+ *
+ * @static
+ * @param String $msg
+ * @param int $code
+ * @param array $trace
+ * @return Exception
+ */
+ function _createJsphonException($msg, $code, $trace)
+ {
+ return new Jsphon_Exception($msg, $code, $trace);
+ }
+
+ /**
+ *
+ * @static
+ * @param String $msg
+ * @param int $code
+ * @param array $trace
+ * @return Exception
+ */
+ function _createException($msg, $code, $trace)
+ {
+ return new Exception($msg, $code);
+ }
+}
+
+
+?>
--- /dev/null
+<?php
+//
+// +--------------------------------------------------------------------+
+// | PHP version 4 and 5 |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 2006 Hawk |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.00 of the PHP License, |
+// | that is available at http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +--------------------------------------------------------------------+
+// | Authors: Hawk <scholar@hawklab.jp> |
+// +--------------------------------------------------------------------+
+//
+//
+
+require_once('PEAR/Exception.php');
+
+/**
+ * Jsphon_Exception
+ *
+ * @author Hawk
+ */
+class Jsphon_Exception extends PEAR_Exception
+{
+ private $_outerTrace;
+
+ /**
+ * Constructor
+ *
+ */
+ public function __construct($msg, $code, $outerTrace)
+ {
+ $this->_outerTrace = $outerTrace;
+ parent::__construct($msg, $code);
+ }
+
+ /**
+ *
+ *
+ * @override
+ * @return array
+ */
+ public function getTraceSafe()
+ {
+ if(count($this->_outerTrace) > 0) {
+ return $this->_outerTrace;
+ }
+ return parent::getTraceSafe();
+ }
+
+}
+
+?>