json.php 13 KB

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