json.class.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. <?php
  2. if(!defined('IN_MOBILE_API') && !defined('IN_DISCUZ')) {
  3. exit('Access Denied');
  4. }
  5. class CJSON {
  6. const JSON_SLICE = 1;
  7. const JSON_IN_STR = 2;
  8. const JSON_IN_ARR = 4;
  9. const JSON_IN_OBJ = 8;
  10. const JSON_IN_CMT = 16;
  11. static function encode($var) {
  12. global $_G;
  13. switch (gettype($var)) {
  14. case 'boolean':
  15. return $var ? 'true' : 'false';
  16. case 'NULL':
  17. return 'null';
  18. case 'integer':
  19. return (int) $var;
  20. case 'double':
  21. case 'float':
  22. return rtrim(sprintf('%.16F',$var),'0');
  23. case 'string':
  24. if(function_exists('diconv') && strtolower($_G['charset']) != 'utf-8') {
  25. $var = diconv($var, $_G['charset'], 'utf-8');
  26. }
  27. if(function_exists('json_encode')) {
  28. return json_encode($var);
  29. }
  30. $ascii = '';
  31. $strlen_var = strlen($var);
  32. for ($c = 0; $c < $strlen_var; ++$c) {
  33. $ord_var_c = ord($var{$c});
  34. switch (true) {
  35. case $ord_var_c == 0x08:
  36. $ascii .= '\b';
  37. break;
  38. case $ord_var_c == 0x09:
  39. $ascii .= '\t';
  40. break;
  41. case $ord_var_c == 0x0A:
  42. $ascii .= '\n';
  43. break;
  44. case $ord_var_c == 0x0C:
  45. $ascii .= '\f';
  46. break;
  47. case $ord_var_c == 0x0D:
  48. $ascii .= '\r';
  49. break;
  50. case $ord_var_c == 0x22:
  51. case $ord_var_c == 0x2F:
  52. case $ord_var_c == 0x5C:
  53. $ascii .= '\\'.$var{$c};
  54. break;
  55. case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
  56. $ascii .= $var{$c};
  57. break;
  58. case (($ord_var_c & 0xE0) == 0xC0):
  59. $char = pack('C*', $ord_var_c, ord($var{$c+1}));
  60. $c+=1;
  61. $utf16 = self::utf8ToUTF16BE($char);
  62. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  63. break;
  64. case (($ord_var_c & 0xF0) == 0xE0):
  65. $char = pack('C*', $ord_var_c,
  66. ord($var{$c+1}),
  67. ord($var{$c+2}));
  68. $c+=2;
  69. $utf16 = self::utf8ToUTF16BE($char);
  70. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  71. break;
  72. case (($ord_var_c & 0xF8) == 0xF0):
  73. $char = pack('C*', $ord_var_c,
  74. ord($var{$c+1}),
  75. ord($var{$c+2}),
  76. ord($var{$c+3}));
  77. $c+=3;
  78. $utf16 = self::utf8ToUTF16BE($char);
  79. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  80. break;
  81. case (($ord_var_c & 0xFC) == 0xF8):
  82. $char = pack('C*', $ord_var_c,
  83. ord($var{$c+1}),
  84. ord($var{$c+2}),
  85. ord($var{$c+3}),
  86. ord($var{$c+4}));
  87. $c+=4;
  88. $utf16 = self::utf8ToUTF16BE($char);
  89. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  90. break;
  91. case (($ord_var_c & 0xFE) == 0xFC):
  92. $char = pack('C*', $ord_var_c,
  93. ord($var{$c+1}),
  94. ord($var{$c+2}),
  95. ord($var{$c+3}),
  96. ord($var{$c+4}),
  97. ord($var{$c+5}));
  98. $c+=5;
  99. $utf16 = self::utf8ToUTF16BE($char);
  100. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  101. break;
  102. }
  103. }
  104. return '"'.$ascii.'"';
  105. case 'array':
  106. if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
  107. return '{' .
  108. join(',', array_map(array('CJSON', 'nameValue'),
  109. array_keys($var),
  110. array_values($var)))
  111. . '}';
  112. }
  113. return '[' . join(',', array_map(array('CJSON', 'encode'), $var)) . ']';
  114. case 'object':
  115. if ($var instanceof Traversable)
  116. {
  117. $vars = array();
  118. foreach ($var as $k=>$v)
  119. $vars[$k] = $v;
  120. }
  121. else
  122. $vars = get_object_vars($var);
  123. return '{' .
  124. join(',', array_map(array('CJSON', 'nameValue'),
  125. array_keys($vars),
  126. array_values($vars)))
  127. . '}';
  128. default:
  129. return '';
  130. }
  131. }
  132. static function nameValue($name, $value) {
  133. return self::encode(strval($name)) . ':' . self::encode($value);
  134. }
  135. static function reduceString($str) {
  136. $str = preg_replace(array(
  137. '#^\s*//(.+)$#m',
  138. '#^\s*/\*(.+)\*/#Us',
  139. '#/\*(.+)\*/\s*$#Us'
  140. ), '', $str);
  141. return trim($str);
  142. }
  143. static function decode($str, $useArray=true) {
  144. if(function_exists('json_decode')) {
  145. return json_decode($str, $useArray);
  146. }
  147. $str = self::reduceString($str);
  148. switch (strtolower($str)) {
  149. case 'true':
  150. return true;
  151. case 'false':
  152. return false;
  153. case 'null':
  154. return null;
  155. default:
  156. if (is_numeric($str)) {
  157. return ((float)$str == (integer)$str)
  158. ? (integer)$str
  159. : (float)$str;
  160. } elseif (preg_match('/^("|\').+(\1)$/s', $str, $m) && $m[1] == $m[2]) {
  161. $delim = substr($str, 0, 1);
  162. $chrs = substr($str, 1, -1);
  163. $utf8 = '';
  164. $strlen_chrs = strlen($chrs);
  165. for ($c = 0; $c < $strlen_chrs; ++$c) {
  166. $substr_chrs_c_2 = substr($chrs, $c, 2);
  167. $ord_chrs_c = ord($chrs{$c});
  168. switch (true) {
  169. case $substr_chrs_c_2 == '\b':
  170. $utf8 .= chr(0x08);
  171. ++$c;
  172. break;
  173. case $substr_chrs_c_2 == '\t':
  174. $utf8 .= chr(0x09);
  175. ++$c;
  176. break;
  177. case $substr_chrs_c_2 == '\n':
  178. $utf8 .= chr(0x0A);
  179. ++$c;
  180. break;
  181. case $substr_chrs_c_2 == '\f':
  182. $utf8 .= chr(0x0C);
  183. ++$c;
  184. break;
  185. case $substr_chrs_c_2 == '\r':
  186. $utf8 .= chr(0x0D);
  187. ++$c;
  188. break;
  189. case $substr_chrs_c_2 == '\\"':
  190. case $substr_chrs_c_2 == '\\\'':
  191. case $substr_chrs_c_2 == '\\\\':
  192. case $substr_chrs_c_2 == '\\/':
  193. if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
  194. ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
  195. $utf8 .= $chrs{++$c};
  196. }
  197. break;
  198. case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
  199. $utf16 = chr(hexdec(substr($chrs, ($c+2), 2)))
  200. . chr(hexdec(substr($chrs, ($c+4), 2)));
  201. $utf8 .= self::utf16beToUTF8($utf16);
  202. $c+=5;
  203. break;
  204. case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
  205. $utf8 .= $chrs{$c};
  206. break;
  207. case ($ord_chrs_c & 0xE0) == 0xC0:
  208. $utf8 .= substr($chrs, $c, 2);
  209. ++$c;
  210. break;
  211. case ($ord_chrs_c & 0xF0) == 0xE0:
  212. $utf8 .= substr($chrs, $c, 3);
  213. $c += 2;
  214. break;
  215. case ($ord_chrs_c & 0xF8) == 0xF0:
  216. $utf8 .= substr($chrs, $c, 4);
  217. $c += 3;
  218. break;
  219. case ($ord_chrs_c & 0xFC) == 0xF8:
  220. $utf8 .= substr($chrs, $c, 5);
  221. $c += 4;
  222. break;
  223. case ($ord_chrs_c & 0xFE) == 0xFC:
  224. $utf8 .= substr($chrs, $c, 6);
  225. $c += 5;
  226. break;
  227. }
  228. }
  229. return $utf8;
  230. } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
  231. if ($str{0} == '[') {
  232. $stk = array(self::JSON_IN_ARR);
  233. $arr = array();
  234. } else {
  235. if ($useArray) {
  236. $stk = array(self::JSON_IN_OBJ);
  237. $obj = array();
  238. } else {
  239. $stk = array(self::JSON_IN_OBJ);
  240. $obj = new stdClass();
  241. }
  242. }
  243. array_push($stk, array('what' => self::JSON_SLICE,
  244. 'where' => 0,
  245. 'delim' => false));
  246. $chrs = substr($str, 1, -1);
  247. $chrs = self::reduceString($chrs);
  248. if ($chrs == '') {
  249. if (reset($stk) == self::JSON_IN_ARR) {
  250. return $arr;
  251. } else {
  252. return $obj;
  253. }
  254. }
  255. $strlen_chrs = strlen($chrs);
  256. for ($c = 0; $c <= $strlen_chrs; ++$c) {
  257. $top = end($stk);
  258. $substr_chrs_c_2 = substr($chrs, $c, 2);
  259. if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == self::JSON_SLICE))) {
  260. $slice = substr($chrs, $top['where'], ($c - $top['where']));
  261. array_push($stk, array('what' => self::JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
  262. if (reset($stk) == self::JSON_IN_ARR) {
  263. array_push($arr, self::decode($slice,$useArray));
  264. } elseif (reset($stk) == self::JSON_IN_OBJ) {
  265. if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
  266. $key = self::decode($parts[1],$useArray);
  267. $val = self::decode($parts[2],$useArray);
  268. if ($useArray) {
  269. $obj[$key] = $val;
  270. } else {
  271. $obj->$key = $val;
  272. }
  273. } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
  274. $key = $parts[1];
  275. $val = self::decode($parts[2],$useArray);
  276. if ($useArray) {
  277. $obj[$key] = $val;
  278. } else {
  279. $obj->$key = $val;
  280. }
  281. }
  282. }
  283. } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != self::JSON_IN_STR)) {
  284. array_push($stk, array('what' => self::JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
  285. } elseif (($chrs{$c} == $top['delim']) &&
  286. ($top['what'] == self::JSON_IN_STR) &&
  287. (($chrs{$c - 1} != "\\") ||
  288. ($chrs{$c - 1} == "\\" && $chrs{$c - 2} == "\\"))) {
  289. array_pop($stk);
  290. } elseif (($chrs{$c} == '[') &&
  291. in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
  292. array_push($stk, array('what' => self::JSON_IN_ARR, 'where' => $c, 'delim' => false));
  293. } elseif (($chrs{$c} == ']') && ($top['what'] == self::JSON_IN_ARR)) {
  294. array_pop($stk);
  295. } elseif (($chrs{$c} == '{') &&
  296. in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
  297. array_push($stk, array('what' => self::JSON_IN_OBJ, 'where' => $c, 'delim' => false));
  298. } elseif (($chrs{$c} == '}') && ($top['what'] == self::JSON_IN_OBJ)) {
  299. array_pop($stk);
  300. } elseif (($substr_chrs_c_2 == '/**') &&
  301. in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
  302. array_push($stk, array('what' => self::JSON_IN_CMT, 'where' => $c, 'delim' => false));
  303. $c++;
  304. } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == self::JSON_IN_CMT)) {
  305. array_pop($stk);
  306. $c++;
  307. for ($i = $top['where']; $i <= $c; ++$i) {
  308. $chrs = substr_replace($chrs, ' ', $i, 1);
  309. }
  310. }
  311. }
  312. if (reset($stk) == self::JSON_IN_ARR) {
  313. return $arr;
  314. } elseif (reset($stk) == self::JSON_IN_OBJ) {
  315. return $obj;
  316. }
  317. }
  318. }
  319. }
  320. static function utf8ToUnicode( &$str ) {
  321. $unicode = array();
  322. $values = array();
  323. $lookingFor = 1;
  324. for ($i = 0; $i < strlen( $str ); $i++ ) {
  325. $thisValue = ord( $str[ $i ] );
  326. if ( $thisValue < 128 ) {
  327. $unicode[] = $thisValue;
  328. } else {
  329. if ( count( $values ) == 0 ) {
  330. $lookingFor = ( $thisValue < 224 ) ? 2 : 3;
  331. }
  332. $values[] = $thisValue;
  333. if ( count( $values ) == $lookingFor ) {
  334. $number = ( $lookingFor == 3 ) ?
  335. ( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ):
  336. ( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 );
  337. $unicode[] = $number;
  338. $values = array();
  339. $lookingFor = 1;
  340. }
  341. }
  342. }
  343. return $unicode;
  344. }
  345. static function unicodeToUTF8( &$str )
  346. {
  347. $utf8 = '';
  348. foreach( $str as $unicode )
  349. {
  350. if ( $unicode < 128 )
  351. {
  352. $utf8.= chr( $unicode );
  353. }
  354. elseif ( $unicode < 2048 )
  355. {
  356. $utf8.= chr( 192 + ( ( $unicode - ( $unicode % 64 ) ) / 64 ) );
  357. $utf8.= chr( 128 + ( $unicode % 64 ) );
  358. }
  359. else
  360. {
  361. $utf8.= chr( 224 + ( ( $unicode - ( $unicode % 4096 ) ) / 4096 ) );
  362. $utf8.= chr( 128 + ( ( ( $unicode % 4096 ) - ( $unicode % 64 ) ) / 64 ) );
  363. $utf8.= chr( 128 + ( $unicode % 64 ) );
  364. }
  365. }
  366. return $utf8;
  367. }
  368. static function utf8ToUTF16BE(&$str, $bom = false) {
  369. $out = $bom ? "\xFE\xFF" : '';
  370. if(function_exists('mb_convert_encoding'))
  371. return $out.mb_convert_encoding($str,'UTF-16BE','UTF-8');
  372. $uni = self::utf8ToUnicode($str);
  373. foreach($uni as $cp)
  374. $out .= pack('n',$cp);
  375. return $out;
  376. }
  377. static function utf16beToUTF8(&$str) {
  378. $uni = unpack('n*',$str);
  379. return self::unicodeToUTF8($uni);
  380. }
  381. }