PageRenderTime 193ms CodeModel.GetById 62ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 115ms

/wind/utility/WindJson.php

https://github.com/dapachong/windframework
PHP | 317 lines | 245 code | 10 blank | 62 comment | 56 complexity | cbb8ecb24bf769f6ab0cabe97aa7b54c MD5 | raw file
  1<?php
  2Wind::import('WIND:utility.WindConvert');
  3/**
  4 * json格式转换类
  5 * 
  6 * 支持json转php类型,以及php类型转json.
  7 * @author Long.shi <long.shi@adlibaba-inc.com> 2011-10-19
  8 * @copyright ©2003-2103 phpwind.com
  9 * @license http://www.windframework.com
 10 * @version $Id$
 11 * @package utility
 12 */
 13class WindJson {
 14	const JSON_SLICE = 1;
 15	const JSON_IN_STR = 2;
 16	const JSON_IN_ARR = 4;
 17	const JSON_IN_OBJ = 8;
 18	const JSON_IN_CMT = 16;
 19
 20	/**
 21	 * 将数据用json加密
 22	 * 
 23	 * @param mixed $value 要加密的值
 24	 * @param string $charset
 25	 * @return string
 26	 */
 27	public static function encode($source, $charset = 'utf8') {
 28		switch (gettype($source)) {
 29			case 'boolean':
 30				$source = $source ? 'true' : 'false';
 31				break;
 32			case 'NULL':
 33				$source = 'null';
 34				break;
 35			case 'integer':
 36				$source = (int) $source;
 37				break;
 38			case 'double':
 39			case 'float':
 40				$source = (float) $source;
 41				break;
 42			case 'string':
 43				$source = WindConvert::convert($source, 'utf8', $charset);
 44				$source = self::stringToJson($source);
 45				break;
 46			case 'array':
 47				$source = WindConvert::convert($source, 'utf8', $charset);
 48				$source = self::arrayToJson($source);
 49				break;
 50			case 'object':
 51				$source = WindConvert::convert($source, 'utf8', $charset);
 52				$source = self::objectToJson($source);
 53				break;
 54			default:
 55				break;
 56		}
 57		return $source;
 58	}
 59
 60	/**
 61	 * 将json格式数据解密
 62	 * 
 63	 * @param string $str
 64	 * @param boolean $toArray
 65	 * @param string $charset
 66	 * @return mixed
 67	 */
 68	public static function decode($str, $toArray = true, $charset = 'utf8') {
 69		$str = self::_reduceString($str);
 70		$_str = strtolower($str);
 71		if ('true' == $_str) {
 72			return true;
 73		} elseif ('false' == $_str) {
 74			return false;
 75		} elseif ('null' == $_str) {
 76			return null;
 77		} elseif (is_numeric($str)) {
 78			return (float) $str == (integer) $str ? (integer) $str : (float) $str;
 79		} elseif (preg_match('/^("|\').+(\1)$/s', $_str, $matche) && $matche[1] == $matche[2]) {
 80			$str = self::jsonToString($str);
 81		} elseif (preg_match('/^\[.*\]$/s', $_str) || preg_match('/^\{.*\}$/s', $_str)) {
 82			$str = self::complexConvert($str, $toArray);
 83		}
 84		WindConvert::convert($str, $charset, 'utf8');
 85		return $str;
 86	}
 87
 88	/**
 89	 * 将json格式转成php string类型
 90	 *
 91	 * @param string $string json字符串
 92	 * @return Ambigous <string, unknown>
 93	 */
 94	protected static function jsonToString($string) {
 95		$delim = substr($string, 0, 1);
 96		$chrs = substr($string, 1, -1);
 97		$decodeStr = '';
 98		for ($c = 0, $length = strlen($chrs); $c < $length; ++$c) {
 99			$compare = substr($chrs, $c, 2);
100			$ordCode = ord($chrs{$c});
101			if ('\b' == $compare) {
102				$decodeStr .= chr(0x08);
103				++$c;
104			} elseif ('\t' == $compare) {
105				$decodeStr .= chr(0x09);
106				++$c;
107			} elseif ('\n' == $compare) {
108				$decodeStr .= chr(0x0A);
109				++$c;
110			} elseif ('\f' == $compare) {
111				$decodeStr .= chr(0x0C);
112				++$c;
113			} elseif ('\r' == $compare) {
114				$decodeStr .= chr(0x0D);
115				++$c;
116			} elseif (in_array($compare, array('\\"', '\\\'', '\\\\', '\\/'))) {
117				if (('"' == $delim && '\\\'' != $compare) || ("'" == $delim && '\\"' != $compare)) {
118					$decodeStr .= $chrs{++$c};
119				}
120			} elseif (preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6))) {
121				$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) . chr(hexdec(substr($chrs, ($c + 4), 2)));
122				$decodeStr .= WindConvert::utf16beToUTF8($utf16); //self::utf16beToUTF8($utf16);
123				$c += 5;
124			} elseif (0x20 <= $ordCode && 0x7F >= $ordCode) {
125				$decodeStr .= $chrs{$c};
126			} elseif (0xC0 == ($ordCode & 0xE0)) {
127				$decodeStr .= substr($chrs, $c, 2);
128				++$c;
129			} elseif (0xE0 == ($ordCode & 0xF0)) {
130				$decodeStr .= substr($chrs, $c, 3);
131				$c += 2;
132			} elseif (0xF0 == ($ordCode & 0xF8)) {
133				$decodeStr .= substr($chrs, $c, 4);
134				$c += 3;
135			} elseif (0xF8 == ($ordCode & 0xFC)) {
136				$decodeStr .= substr($chrs, $c, 5);
137				$c += 4;
138			} elseif (0xFC == ($ordCode & 0xFE)) {
139				$decodeStr .= substr($chrs, $c, 6);
140				$c += 5;
141			}
142		}
143		return $decodeStr;
144	}
145
146	/**
147	 * 复杂的json格式转换,支持object array格式
148	 * 
149	 * @param string $str
150	 * @param boolean $toArray
151	 * @return Ambigous <multitype:, stdClass>|multitype:|Ambigous <mixed, boolean, NULL, number, multitype:, stdClass, Ambigous, string, unknown>|boolean
152	 */
153	protected static function complexConvert($str, $toArray = true) {
154		if ('[' == $str{0}) {
155			$stk = array(self::JSON_IN_ARR);
156			$arr = array();
157		} else {
158			$obj = $toArray ? array() : new stdClass();
159			$stk = array(self::JSON_IN_OBJ);
160		}
161		array_push($stk, array('what' => self::JSON_SLICE, 'where' => 0, 'delim' => false));
162		$chrs = substr($str, 1, -1);
163		$chrs = self::_reduceString($chrs);
164		if ('' == $chrs) {
165			return self::JSON_IN_ARR == reset($stk) ? $arr : $obj;
166		}
167		for ($c = 0, $length = strlen($chrs); $c <= $length; ++$c) {
168			$top = end($stk);
169			$substr_chrs_c_2 = substr($chrs, $c, 2);
170			if (($c == $length) || (($chrs{$c} == ',') && ($top['what'] == self::JSON_SLICE))) {
171				$slice = substr($chrs, $top['where'], ($c - $top['where']));
172				array_push($stk, array('what' => self::JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
173				if (reset($stk) == self::JSON_IN_ARR) {
174					array_push($arr, self::decode($slice, $toArray));
175				} elseif (reset($stk) == self::JSON_IN_OBJ) {
176					if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
177						$key = self::decode($parts[1], $toArray);
178						$toArray ? $obj[$key] = self::decode($parts[2], $toArray) : $obj->$key = self::decode($parts[2], 
179							$toArray);
180					} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
181						$toArray ? $obj[$parts[1]] = self::decode($parts[2], $toArray) : $obj->$parts[1] = self::decode(
182							$parts[2], $toArray);
183					}
184				}
185			
186			} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != self::JSON_IN_STR)) {
187				array_push($stk, array('what' => self::JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
188			} elseif (($chrs{$c} == $top['delim']) && ($top['what'] == self::JSON_IN_STR) && (($chrs{$c - 1} != "\\") || ($chrs{$c - 1} == "\\" && $chrs{$c - 2} == "\\"))) {
189				array_pop($stk);
190			} elseif (($chrs{$c} == '[') && in_array($top['what'], 
191				array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
192				array_push($stk, array('what' => self::JSON_IN_ARR, 'where' => $c, 'delim' => false));
193			} elseif (($chrs{$c} == ']') && ($top['what'] == self::JSON_IN_ARR)) {
194				array_pop($stk);
195			} elseif (($chrs{$c} == '{') && in_array($top['what'], 
196				array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
197				array_push($stk, array('what' => self::JSON_IN_OBJ, 'where' => $c, 'delim' => false));
198			} elseif (($chrs{$c} == '}') && ($top['what'] == self::JSON_IN_OBJ)) {
199				array_pop($stk);
200			} elseif (($substr_chrs_c_2 == '/*') && in_array($top['what'], 
201				array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) {
202				array_push($stk, array('what' => self::JSON_IN_CMT, 'where' => ++$c, 'delim' => false));
203			} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == self::JSON_IN_CMT)) {
204				array_pop($stk);
205				for ($i = $top['where']; $i <= ++$c; ++$i) {
206					$chrs = substr_replace($chrs, ' ', $i, 1);
207				}
208			}
209		
210		}
211		if (self::JSON_IN_ARR == reset($stk)) {
212			return $arr;
213		} elseif (self::JSON_IN_OBJ == reset($stk)) {
214			return $obj;
215		}
216		return false;
217	}
218
219	/**
220	 * 将字符串转化成json格式对象
221	 * 
222	 * @param string $string
223	 * @return string
224	 */
225	protected static function stringToJson($string) {
226		$ascii = '';
227		$strlen = strlen($string);
228		for ($c = 0; $c < $strlen; ++$c) {
229			$b = $string{$c};
230			$ordVar = ord($string{$c});
231			if (0x08 == $ordVar) {
232				$ascii .= '\b';
233			} elseif (0x09 == $ordVar) {
234				$ascii .= '\t';
235			} elseif (0x0A == $ordVar) {
236				$ascii .= '\n';
237			} elseif (0x0C == $ordVar) {
238				$ascii .= '\f';
239			} elseif (0x0D == $ordVar) {
240				$ascii .= '\r';
241			} elseif (in_array($ordVar, array(0x22, 0x2F, 0x5C))) {
242				$ascii .= '\\' . $string{$c};
243			} elseif (0x20 <= $ordVar && 0x7F >= $ordVar) {
244				$ascii .= $string{$c}; //ASCII
245			} elseif (0xC0 == ($ordVar & 0xE0)) {
246				$char = pack('C*', $ordVar, ord($string{++$c}));
247				$ascii .= sprintf('\u%04s', bin2hex(WindConvert::utf8ToUTF16BE($char)));
248			} elseif (0xE0 == ($ordVar & 0xF0)) {
249				$char = pack('C*', $ordVar, ord($string{++$c}), ord($string{++$c}));
250				$ascii .= sprintf('\u%04s', bin2hex(WindConvert::utf8ToUTF16BE($char)));
251			} elseif (0xF0 == ($ordVar & 0xF8)) {
252				$char = pack('C*', $ordVar, ord($string{++$c}), ord($string{++$c}), ord($string{++$c}));
253				$ascii .= sprintf('\u%04s', bin2hex(WindConvert::utf8ToUTF16BE($char)));
254			} elseif (0xF8 == ($ordVar & 0xFC)) {
255				$char = pack('C*', $ordVar, ord($string{++$c}), ord($string{++$c}), ord($string{++$c}), 
256					ord($string{++$c}));
257				$ascii .= sprintf('\u%04s', bin2hex(WindConvert::utf8ToUTF16BE($char)));
258			} elseif (0xFC == ($ordVar & 0xFE)) {
259				$char = pack('C*', $ordVar, ord($string{++$c}), ord($string{++$c}), ord($string{++$c}), 
260					ord($string{++$c}), ord($string{++$c}));
261				$ascii .= sprintf('\u%04s', bin2hex(WindConvert::utf8ToUTF16BE($char)));
262			}
263		}
264		return '"' . $ascii . '"';
265	}
266
267	/**
268	 * 将数组转化成json格式对象
269	 * 
270	 * @param array $array
271	 * @return string
272	 */
273	protected static function arrayToJson(array $array) {
274		if (is_array($array) && count($array) && (array_keys($array) !== range(0, sizeof($array) - 1))) {
275			return '{' . join(',', array_map(array('WindJson', '_nameValue'), array_keys($array), array_values($array))) . '}';
276		}
277		return '[' . join(',', array_map(array('WindJson', 'encode'), $array)) . ']';
278	}
279
280	/**
281	 * 将对象转化成json格式对象
282	 * 
283	 * @param string $object
284	 * @return string
285	 */
286	protected static function objectToJson($object) {
287		if ($object instanceof Traversable) {
288			$vars = array();
289			foreach ($object as $k => $v) {
290				$vars[$k] = $v;
291			}
292		} else {
293			$vars = get_object_vars($object);
294		}
295		return '{' . join(',', array_map(array('WindJson', '_nameValue'), array_keys($vars), array_values($vars))) . '}';
296	}
297
298	/**
299	 * @param string $str
300	 * @return string
301	 */
302	private static function _reduceString($str) {
303		return trim(preg_replace(array('#^\s*//(.+)$#m', '#^\s*/\*(.+)\*/#Us', '#/\*(.+)\*/\s*$#Us'), '', $str));
304	}
305
306	/**
307	 * callback函数,用于数组或对象加密
308	 *
309	 * @param mixed $name
310	 * @param mixed $value
311	 */
312	private static function _nameValue($name, $value) {
313		return self::encode(strval($name)) . ':' . self::encode($value);
314	}
315}
316
317?>