PageRenderTime 361ms CodeModel.GetById 37ms RepoModel.GetById 1ms app.codeStats 0ms

/var/Json.php

https://github.com/zihuxinyu/typecho
PHP | 545 lines | 479 code | 21 blank | 45 comment | 31 complexity | 4fe1eae37dc0480fe45f8b33c33a9bb8 MD5 | raw file
Possible License(s): AGPL-1.0
  1. <?php
  2. /**********************************
  3. * Created on: 2007-2-2
  4. * File Name : lib.json.php
  5. * Copyright : 2005 Michal Migursk
  6. * License : http://www.opensource.org/licenses/bsd-license.php
  7. *********************************/
  8. class Json
  9. {
  10. const SERVICES_JSON_SLICE = 1;
  11. const SERVICES_JSON_IN_STR = 2;
  12. const SERVICES_JSON_IN_ARR = 3;
  13. const SERVICES_JSON_IN_OBJ = 4;
  14. const SERVICES_JSON_IN_CMT = 5;
  15. const SERVICES_JSON_LOOSE_TYPE = 16;
  16. const SERVICES_JSON_SUPPRESS_ERRORS = 32;
  17. const E_JSONTYPE = 'json decode error';
  18. /**
  19. * 将utf16转换为utf8
  20. *
  21. * @access private
  22. * @param string $utf16 utf16字符串
  23. * @return string
  24. */
  25. private static function utf162utf8($utf16)
  26. {
  27. if (function_exists('mb_convert_encoding')) {
  28. return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
  29. }
  30. $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
  31. switch (true) {
  32. case ((0x7F & $bytes) == $bytes):
  33. return chr(0x7F & $bytes);
  34. case (0x07FF & $bytes) == $bytes:
  35. return chr(0xC0 | (($bytes >> 6) & 0x1F))
  36. . chr(0x80 | ($bytes & 0x3F));
  37. case (0xFFFF & $bytes) == $bytes:
  38. return chr(0xE0 | (($bytes >> 12) & 0x0F))
  39. . chr(0x80 | (($bytes >> 6) & 0x3F))
  40. . chr(0x80 | ($bytes & 0x3F));
  41. }
  42. return '';
  43. }
  44. /**
  45. * 将utf8转换为utf16
  46. *
  47. * @access private
  48. * @param string $utf8 utf8字符串
  49. * @return string
  50. */
  51. private static function utf82utf16($utf8)
  52. {
  53. if (function_exists('mb_convert_encoding')) {
  54. return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
  55. }
  56. switch (strlen($utf8)) {
  57. case 1:
  58. return $utf8;
  59. case 2:
  60. return chr(0x07 & (ord($utf8{0}) >> 2))
  61. . chr((0xC0 & (ord($utf8{0}) << 6))
  62. | (0x3F & ord($utf8{1})));
  63. case 3:
  64. return chr((0xF0 & (ord($utf8{0}) << 4))
  65. | (0x0F & (ord($utf8{1}) >> 2)))
  66. . chr((0xC0 & (ord($utf8{1}) << 6))
  67. | (0x7F & ord($utf8{2})));
  68. }
  69. return '';
  70. }
  71. /**
  72. * 判断错误
  73. *
  74. * @access private
  75. * @param mixed $data 错误对象
  76. * @param string $code 错误代码
  77. * @return boolean
  78. */
  79. private static function _is_error($data, $code = null)
  80. {
  81. if (is_object($data) && (get_class($data) == 'services_json_error' ||
  82. is_subclass_of($data, 'services_json_error'))) {
  83. return true;
  84. }
  85. return false;
  86. }
  87. /**
  88. * 清除特殊格式
  89. *
  90. * @access private
  91. * @param string $str 待处理字符串
  92. * @return string
  93. */
  94. private static function _reduce_string($str)
  95. {
  96. $str = preg_replace(array(
  97. '#^\s*//(.+)$#m',
  98. '#^\s*/\*(.+)\*/#Us',
  99. '#/\*(.+)\*/\s*$#Us'
  100. ), '', $str);
  101. return trim($str);
  102. }
  103. /**
  104. * 将对象转换为json串
  105. *
  106. * @access public
  107. * @param mixed $var 需要转换的对象
  108. * @return string
  109. */
  110. public static function _encode($var)
  111. {
  112. switch (gettype($var)) {
  113. case 'boolean':
  114. return $var ? 'true' : 'false';
  115. case 'NULL':
  116. return 'null';
  117. case 'integer':
  118. return (int) $var;
  119. case 'double':
  120. case 'float':
  121. return (float) $var;
  122. case 'string':
  123. $ascii = '';
  124. $strlen_var = strlen($var);
  125. for ($c = 0; $c < $strlen_var; ++$c) {
  126. $ord_var_c = ord($var{$c});
  127. switch (true) {
  128. case $ord_var_c == 0x08:
  129. $ascii .= '\b';
  130. break;
  131. case $ord_var_c == 0x09:
  132. $ascii .= '\t';
  133. break;
  134. case $ord_var_c == 0x0A:
  135. $ascii .= '\n';
  136. break;
  137. case $ord_var_c == 0x0C:
  138. $ascii .= '\f';
  139. break;
  140. case $ord_var_c == 0x0D:
  141. $ascii .= '\r';
  142. break;
  143. case $ord_var_c == 0x22:
  144. case $ord_var_c == 0x2F:
  145. case $ord_var_c == 0x5C:
  146. $ascii .= '\\'.$var{$c};
  147. break;
  148. case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
  149. $ascii .= $var{$c};
  150. break;
  151. case (($ord_var_c & 0xE0) == 0xC0):
  152. $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
  153. $c += 1;
  154. $utf16 = self::utf82utf16($char);
  155. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  156. break;
  157. case (($ord_var_c & 0xF0) == 0xE0):
  158. $char = pack('C*', $ord_var_c,
  159. ord($var{$c + 1}),
  160. ord($var{$c + 2}));
  161. $c += 2;
  162. $utf16 = self::utf82utf16($char);
  163. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  164. break;
  165. case (($ord_var_c & 0xF8) == 0xF0):
  166. $char = pack('C*', $ord_var_c,
  167. ord($var{$c + 1}),
  168. ord($var{$c + 2}),
  169. ord($var{$c + 3}));
  170. $c += 3;
  171. $utf16 = self::utf82utf16($char);
  172. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  173. break;
  174. case (($ord_var_c & 0xFC) == 0xF8):
  175. $char = pack('C*', $ord_var_c,
  176. ord($var{$c + 1}),
  177. ord($var{$c + 2}),
  178. ord($var{$c + 3}),
  179. ord($var{$c + 4}));
  180. $c += 4;
  181. $utf16 = self::utf82utf16($char);
  182. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  183. break;
  184. case (($ord_var_c & 0xFE) == 0xFC):
  185. $char = pack('C*', $ord_var_c,
  186. ord($var{$c + 1}),
  187. ord($var{$c + 2}),
  188. ord($var{$c + 3}),
  189. ord($var{$c + 4}),
  190. ord($var{$c + 5}));
  191. $c += 5;
  192. $utf16 = self::utf82utf16($char);
  193. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  194. break;
  195. }
  196. }
  197. return '"'.$ascii.'"';
  198. case 'array':
  199. if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
  200. $properties = array_map(array('Typecho_Json', '_name_value'),
  201. array_keys($var),
  202. array_values($var));
  203. foreach ($properties as $property) {
  204. if (self::_is_error($property)) {
  205. return $property;
  206. }
  207. }
  208. return '{' . join(',', $properties) . '}';
  209. }
  210. // treat it like a regular array
  211. $elements = array_map(array('Typecho_Json', '_encode'), $var);
  212. foreach ($elements as $element) {
  213. if (self::_is_error($element)) {
  214. return $element;
  215. }
  216. }
  217. return '[' . join(',', $elements) . ']';
  218. case 'object':
  219. $vars = get_object_vars($var);
  220. $properties = array_map(array('Typecho_Json', '_name_value'),
  221. array_keys($vars),
  222. array_values($vars));
  223. foreach ($properties as $property) {
  224. if (self::_is_error($property)) {
  225. return $property;
  226. }
  227. }
  228. return '{' . join(',', $properties) . '}';
  229. default:
  230. return false;
  231. }
  232. }
  233. /**
  234. * 解码json字符串
  235. *
  236. * @access public
  237. * @param string $str 解码字符串
  238. * @return mixed
  239. */
  240. public static function _decode($str)
  241. {
  242. $str = self::_reduce_string($str);
  243. switch (strtolower($str)) {
  244. case 'true':
  245. return true;
  246. case 'false':
  247. return false;
  248. case 'null':
  249. return null;
  250. default:
  251. $m = array();
  252. if (is_numeric($str)) {
  253. return ((float)$str == (integer)$str)
  254. ? (integer)$str
  255. : (float)$str;
  256. } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
  257. $delim = substr($str, 0, 1);
  258. $chrs = substr($str, 1, -1);
  259. $utf8 = '';
  260. $strlen_chrs = strlen($chrs);
  261. for ($c = 0; $c < $strlen_chrs; ++$c) {
  262. $substr_chrs_c_2 = substr($chrs, $c, 2);
  263. $ord_chrs_c = ord($chrs{$c});
  264. switch (true) {
  265. case $substr_chrs_c_2 == '\b':
  266. $utf8 .= chr(0x08);
  267. ++$c;
  268. break;
  269. case $substr_chrs_c_2 == '\t':
  270. $utf8 .= chr(0x09);
  271. ++$c;
  272. break;
  273. case $substr_chrs_c_2 == '\n':
  274. $utf8 .= chr(0x0A);
  275. ++$c;
  276. break;
  277. case $substr_chrs_c_2 == '\f':
  278. $utf8 .= chr(0x0C);
  279. ++$c;
  280. break;
  281. case $substr_chrs_c_2 == '\r':
  282. $utf8 .= chr(0x0D);
  283. ++$c;
  284. break;
  285. case $substr_chrs_c_2 == '\\"':
  286. case $substr_chrs_c_2 == '\\\'':
  287. case $substr_chrs_c_2 == '\\\\':
  288. case $substr_chrs_c_2 == '\\/':
  289. if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
  290. ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
  291. $utf8 .= $chrs{++$c};
  292. }
  293. break;
  294. case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
  295. $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
  296. . chr(hexdec(substr($chrs, ($c + 4), 2)));
  297. $utf8 .= self::utf162utf8($utf16);
  298. $c += 5;
  299. break;
  300. case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
  301. $utf8 .= $chrs{$c};
  302. break;
  303. case ($ord_chrs_c & 0xE0) == 0xC0:
  304. $utf8 .= substr($chrs, $c, 2);
  305. ++$c;
  306. break;
  307. case ($ord_chrs_c & 0xF0) == 0xE0:
  308. $utf8 .= substr($chrs, $c, 3);
  309. $c += 2;
  310. break;
  311. case ($ord_chrs_c & 0xF8) == 0xF0:
  312. $utf8 .= substr($chrs, $c, 4);
  313. $c += 3;
  314. break;
  315. case ($ord_chrs_c & 0xFC) == 0xF8:
  316. $utf8 .= substr($chrs, $c, 5);
  317. $c += 4;
  318. break;
  319. case ($ord_chrs_c & 0xFE) == 0xFC:
  320. $utf8 .= substr($chrs, $c, 6);
  321. $c += 5;
  322. break;
  323. }
  324. }
  325. return $utf8;
  326. } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
  327. if ($str {0} == '[') {
  328. $stk = array(self::SERVICES_JSON_IN_ARR);
  329. $arr = array();
  330. } else {
  331. $stk = array(self::SERVICES_JSON_IN_OBJ);
  332. $obj = new stdClass();
  333. }
  334. array_push($stk, array('what' => self::SERVICES_JSON_SLICE,
  335. 'where' => 0,
  336. 'delim' => false));
  337. $chrs = substr($str, 1, -1);
  338. $chrs = self::_reduce_string($chrs);
  339. if ($chrs == '') {
  340. if (reset($stk) == self::SERVICES_JSON_IN_ARR) {
  341. return $arr;
  342. } else {
  343. return $obj;
  344. }
  345. }
  346. $strlen_chrs = strlen($chrs);
  347. for ($c = 0; $c <= $strlen_chrs; ++$c) {
  348. $top = end($stk);
  349. $substr_chrs_c_2 = substr($chrs, $c, 2);
  350. if (($c == $strlen_chrs) || (($chrs {$c} == ',') && ($top['what'] == self::SERVICES_JSON_SLICE))) {
  351. $slice = substr($chrs, $top['where'], ($c - $top['where']));
  352. array_push($stk, array('what' => self::SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
  353. if (reset($stk) == self::SERVICES_JSON_IN_ARR) {
  354. array_push($arr, self::_decode($slice));
  355. } elseif (reset($stk) == self::SERVICES_JSON_IN_OBJ) {
  356. $parts = array();
  357. if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
  358. $key = self::_decode($parts[1]);
  359. $val = self::_decode($parts[2]);
  360. $obj->$key = $val;
  361. } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
  362. $key = $parts[1];
  363. $val = self::_decode($parts[2]);
  364. $obj->$key = $val;
  365. }
  366. }
  367. } elseif ((($chrs {$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != self::SERVICES_JSON_IN_STR)) {
  368. array_push($stk, array('what' => self::SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
  369. } elseif (($chrs {$c} == $top['delim']) &&
  370. ($top['what'] == self::SERVICES_JSON_IN_STR) &&
  371. ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
  372. array_pop($stk);
  373. } elseif (($chrs {$c} == '[') &&
  374. in_array($top['what'], array(self::SERVICES_JSON_SLICE, self::SERVICES_JSON_IN_ARR, self::SERVICES_JSON_IN_OBJ))) {
  375. array_push($stk, array('what' => self::SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
  376. } elseif (($chrs {$c} == ']') && ($top['what'] == self::SERVICES_JSON_IN_ARR)) {
  377. array_pop($stk);
  378. } elseif (($chrs {$c} == '{') &&
  379. in_array($top['what'], array(self::SERVICES_JSON_SLICE, self::SERVICES_JSON_IN_ARR, self::SERVICES_JSON_IN_OBJ))) {
  380. array_push($stk, array('what' => self::SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
  381. } elseif (($chrs {$c} == '}') && ($top['what'] == self::SERVICES_JSON_IN_OBJ)) {
  382. array_pop($stk);
  383. } elseif (($substr_chrs_c_2 == '/*') &&
  384. in_array($top['what'], array(self::SERVICES_JSON_SLICE, self::SERVICES_JSON_IN_ARR, self::SERVICES_JSON_IN_OBJ))) {
  385. array_push($stk, array('what' => self::SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
  386. $c++;
  387. } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == self::SERVICES_JSON_IN_CMT)) {
  388. array_pop($stk);
  389. $c++;
  390. for ($i = $top['where']; $i <= $c; ++$i)
  391. $chrs = substr_replace($chrs, ' ', $i, 1);
  392. }
  393. }
  394. if (reset($stk) == self::SERVICES_JSON_IN_ARR) {
  395. return $arr;
  396. } elseif (reset($stk) == self::SERVICES_JSON_IN_OBJ) {
  397. return $obj;
  398. }
  399. }
  400. }
  401. }
  402. /**
  403. * 对配对值编码
  404. *
  405. * @access public
  406. * @param string $name 名称
  407. * @param mixed $value 值
  408. * @return string
  409. */
  410. public static function _name_value($name, $value)
  411. {
  412. $encoded_value = self::_encode($value);
  413. if (self::_is_error($encoded_value)) {
  414. return $encoded_value;
  415. }
  416. return self::_encode(strval($name)) . ':' . $encoded_value;
  417. }
  418. /**
  419. * 对变量进行json编码
  420. *
  421. * @access public
  422. * @param mixed $var 需要处理的对象
  423. * @return string
  424. */
  425. public static function encode($var)
  426. {
  427. if (function_exists('json_encode')) {
  428. /** from php 5.1 */
  429. return json_encode($var);
  430. } else {
  431. return self::_encode($var);
  432. }
  433. }
  434. /**
  435. * 对字符串进行json解码
  436. *
  437. * @access public
  438. * @param string $var 需要解码的字符串
  439. * @param boolean $assoc 是否强制解释为数组
  440. * @return mixed
  441. */
  442. public static function decode($var, $assoc = false)
  443. {
  444. if (function_exists('json_decode')) {
  445. /** from php 5.1 */
  446. return json_decode($var, $assoc);
  447. } else {
  448. $result = self::_decode($var);
  449. }
  450. if ($assoc && is_object($result)) {
  451. return (array) $result;
  452. } else if (!$assoc && is_array($result)) {
  453. return (object) $result;
  454. }
  455. return $result;
  456. }
  457. }