00001 <?php
00030 class Zend_Json_Encoder
00031 {
00037 protected $_cycleCheck;
00038
00044 protected $_options = array();
00045
00051 protected $_visited = array();
00052
00060 protected function __construct($cycleCheck = false, $options = array())
00061 {
00062 $this->_cycleCheck = $cycleCheck;
00063 $this->_options = $options;
00064 }
00065
00074 public static function encode($value, $cycleCheck = false, $options = array())
00075 {
00076 $encoder = new self(($cycleCheck) ? true : false, $options);
00077
00078 return $encoder->_encodeValue($value);
00079 }
00080
00091 protected function _encodeValue(&$value)
00092 {
00093 if (is_object($value)) {
00094 return $this->_encodeObject($value);
00095 } else if (is_array($value)) {
00096 return $this->_encodeArray($value);
00097 }
00098
00099 return $this->_encodeDatum($value);
00100 }
00101
00102
00103
00115 protected function _encodeObject(&$value)
00116 {
00117 if ($this->_cycleCheck) {
00118 if ($this->_wasVisited($value)) {
00119
00120 if (isset($this->_options['silenceCyclicalExceptions'])
00121 && $this->_options['silenceCyclicalExceptions']===true) {
00122
00123 return '"* RECURSION (' . get_class($value) . ') *"';
00124
00125 } else {
00126 require_once 'Zend/Json/Exception.php';
00127 throw new Zend_Json_Exception(
00128 'Cycles not supported in JSON encoding, cycle introduced by '
00129 . 'class "' . get_class($value) . '"'
00130 );
00131 }
00132 }
00133
00134 $this->_visited[] = $value;
00135 }
00136
00137 $props = '';
00138
00139 if ($value instanceof Iterator) {
00140 $propCollection = $value;
00141 } else {
00142 $propCollection = get_object_vars($value);
00143 }
00144
00145 foreach ($propCollection as $name => $propValue) {
00146 if (isset($propValue)) {
00147 $props .= ','
00148 . $this->_encodeValue($name)
00149 . ':'
00150 . $this->_encodeValue($propValue);
00151 }
00152 }
00153
00154 return '{"__className":"' . get_class($value) . '"'
00155 . $props . '}';
00156 }
00157
00158
00165 protected function _wasVisited(&$value)
00166 {
00167 if (in_array($value, $this->_visited, true)) {
00168 return true;
00169 }
00170
00171 return false;
00172 }
00173
00174
00188 protected function _encodeArray(&$array)
00189 {
00190 $tmpArray = array();
00191
00192
00193 if (!empty($array) && (array_keys($array) !== range(0, count($array) - 1))) {
00194
00195 $result = '{';
00196 foreach ($array as $key => $value) {
00197 $key = (string) $key;
00198 $tmpArray[] = $this->_encodeString($key)
00199 . ':'
00200 . $this->_encodeValue($value);
00201 }
00202 $result .= implode(',', $tmpArray);
00203 $result .= '}';
00204 } else {
00205
00206 $result = '[';
00207 $length = count($array);
00208 for ($i = 0; $i < $length; $i++) {
00209 $tmpArray[] = $this->_encodeValue($array[$i]);
00210 }
00211 $result .= implode(',', $tmpArray);
00212 $result .= ']';
00213 }
00214
00215 return $result;
00216 }
00217
00218
00228 protected function _encodeDatum(&$value)
00229 {
00230 $result = 'null';
00231
00232 if (is_int($value) || is_float($value)) {
00233 $result = (string) $value;
00234 $result = str_replace(",", ".", $result);
00235 } elseif (is_string($value)) {
00236 $result = $this->_encodeString($value);
00237 } elseif (is_bool($value)) {
00238 $result = $value ? 'true' : 'false';
00239 }
00240
00241 return $result;
00242 }
00243
00244
00251 protected function _encodeString(&$string)
00252 {
00253
00254
00255 $search = array('\\', "\n", "\t", "\r", "\b", "\f", '"');
00256 $replace = array('\\\\', '\\n', '\\t', '\\r', '\\b', '\\f', '\"');
00257 $string = str_replace($search, $replace, $string);
00258
00259
00260
00261
00262 $string = str_replace(array(chr(0x08), chr(0x0C)), array('\b', '\f'), $string);
00263 $string = self::encodeUnicodeString($string);
00264
00265 return '"' . $string . '"';
00266 }
00267
00268
00276 private static function _encodeConstants(ReflectionClass $cls)
00277 {
00278 $result = "constants : {";
00279 $constants = $cls->getConstants();
00280
00281 $tmpArray = array();
00282 if (!empty($constants)) {
00283 foreach ($constants as $key => $value) {
00284 $tmpArray[] = "$key: " . self::encode($value);
00285 }
00286
00287 $result .= implode(', ', $tmpArray);
00288 }
00289
00290 return $result . "}";
00291 }
00292
00293
00302 private static function _encodeMethods(ReflectionClass $cls)
00303 {
00304 $methods = $cls->getMethods();
00305 $result = 'methods:{';
00306
00307 $started = false;
00308 foreach ($methods as $method) {
00309 if (! $method->isPublic() || !$method->isUserDefined()) {
00310 continue;
00311 }
00312
00313 if ($started) {
00314 $result .= ',';
00315 }
00316 $started = true;
00317
00318 $result .= '' . $method->getName(). ':function(';
00319
00320 if ('__construct' != $method->getName()) {
00321 $parameters = $method->getParameters();
00322 $paramCount = count($parameters);
00323 $argsStarted = false;
00324
00325 $argNames = "var argNames=[";
00326 foreach ($parameters as $param) {
00327 if ($argsStarted) {
00328 $result .= ',';
00329 }
00330
00331 $result .= $param->getName();
00332
00333 if ($argsStarted) {
00334 $argNames .= ',';
00335 }
00336
00337 $argNames .= '"' . $param->getName() . '"';
00338
00339 $argsStarted = true;
00340 }
00341 $argNames .= "];";
00342
00343 $result .= "){"
00344 . $argNames
00345 . 'var result = ZAjaxEngine.invokeRemoteMethod('
00346 . "this, '" . $method->getName()
00347 . "',argNames,arguments);"
00348 . 'return(result);}';
00349 } else {
00350 $result .= "){}";
00351 }
00352 }
00353
00354 return $result . "}";
00355 }
00356
00357
00366 private static function _encodeVariables(ReflectionClass $cls)
00367 {
00368 $properties = $cls->getProperties();
00369 $propValues = get_class_vars($cls->getName());
00370 $result = "variables:{";
00371 $cnt = 0;
00372
00373 $tmpArray = array();
00374 foreach ($properties as $prop) {
00375 if (! $prop->isPublic()) {
00376 continue;
00377 }
00378
00379 $tmpArray[] = $prop->getName()
00380 . ':'
00381 . self::encode($propValues[$prop->getName()]);
00382 }
00383 $result .= implode(',', $tmpArray);
00384
00385 return $result . "}";
00386 }
00387
00401 public static function encodeClass($className, $package = '')
00402 {
00403 $cls = new ReflectionClass($className);
00404 if (! $cls->isInstantiable()) {
00405 require_once 'Zend/Json/Exception.php';
00406 throw new Zend_Json_Exception("$className must be instantiable");
00407 }
00408
00409 return "Class.create('$package$className',{"
00410 . self::_encodeConstants($cls) .","
00411 . self::_encodeMethods($cls) .","
00412 . self::_encodeVariables($cls) .'});';
00413 }
00414
00415
00425 public static function encodeClasses(array $classNames, $package = '')
00426 {
00427 $result = '';
00428 foreach ($classNames as $className) {
00429 $result .= self::encodeClass($className, $package);
00430 }
00431
00432 return $result;
00433 }
00434
00446 public static function encodeUnicodeString($value)
00447 {
00448 $strlen_var = strlen($value);
00449 $ascii = "";
00450
00455 for($i = 0; $i < $strlen_var; $i++) {
00456 $ord_var_c = ord($value[$i]);
00457
00458 switch (true) {
00459 case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
00460
00461 $ascii .= $value[$i];
00462 break;
00463
00464 case (($ord_var_c & 0xE0) == 0xC0):
00465
00466
00467 $char = pack('C*', $ord_var_c, ord($value[$i + 1]));
00468 $i += 1;
00469 $utf16 = self::_utf82utf16($char);
00470 $ascii .= sprintf('\u%04s', bin2hex($utf16));
00471 break;
00472
00473 case (($ord_var_c & 0xF0) == 0xE0):
00474
00475
00476 $char = pack('C*', $ord_var_c,
00477 ord($value[$i + 1]),
00478 ord($value[$i + 2]));
00479 $i += 2;
00480 $utf16 = self::_utf82utf16($char);
00481 $ascii .= sprintf('\u%04s', bin2hex($utf16));
00482 break;
00483
00484 case (($ord_var_c & 0xF8) == 0xF0):
00485
00486
00487 $char = pack('C*', $ord_var_c,
00488 ord($value[$i + 1]),
00489 ord($value[$i + 2]),
00490 ord($value[$i + 3]));
00491 $i += 3;
00492 $utf16 = self::_utf82utf16($char);
00493 $ascii .= sprintf('\u%04s', bin2hex($utf16));
00494 break;
00495
00496 case (($ord_var_c & 0xFC) == 0xF8):
00497
00498
00499 $char = pack('C*', $ord_var_c,
00500 ord($value[$i + 1]),
00501 ord($value[$i + 2]),
00502 ord($value[$i + 3]),
00503 ord($value[$i + 4]));
00504 $i += 4;
00505 $utf16 = self::_utf82utf16($char);
00506 $ascii .= sprintf('\u%04s', bin2hex($utf16));
00507 break;
00508
00509 case (($ord_var_c & 0xFE) == 0xFC):
00510
00511
00512 $char = pack('C*', $ord_var_c,
00513 ord($value[$i + 1]),
00514 ord($value[$i + 2]),
00515 ord($value[$i + 3]),
00516 ord($value[$i + 4]),
00517 ord($value[$i + 5]));
00518 $i += 5;
00519 $utf16 = self::_utf82utf16($char);
00520 $ascii .= sprintf('\u%04s', bin2hex($utf16));
00521 break;
00522 }
00523 }
00524
00525 return $ascii;
00526 }
00527
00541 protected static function _utf82utf16($utf8)
00542 {
00543
00544 if( function_exists('mb_convert_encoding') ) {
00545 return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
00546 }
00547
00548 switch (strlen($utf8)) {
00549 case 1:
00550
00551
00552 return $utf8;
00553
00554 case 2:
00555
00556
00557 return chr(0x07 & (ord($utf8{0}) >> 2))
00558 . chr((0xC0 & (ord($utf8{0}) << 6))
00559 | (0x3F & ord($utf8{1})));
00560
00561 case 3:
00562
00563
00564 return chr((0xF0 & (ord($utf8{0}) << 4))
00565 | (0x0F & (ord($utf8{1}) >> 2)))
00566 . chr((0xC0 & (ord($utf8{1}) << 6))
00567 | (0x7F & ord($utf8{2})));
00568 }
00569
00570
00571 return '';
00572 }
00573 }
00574