public function encode($var, $options = null)
{
if ($this->isJsonEncodeEnabled()) {
return @json_encode($var, $options);
}
switch (gettype($var)) {
case 'boolean':
return $var ? 'true' : 'false';
case 'NULL':
return 'null';
case 'integer':
return (int) $var;
case 'double':
case 'float':
return (double) $var;
case 'string':
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
$ascii = '';
$strlen_var = strlen($var);
/*
* Iterate over every character in the string,
* escaping with a slash or encoding to UTF-8 where necessary
*/
for ($c = 0; $c < $strlen_var; ++$c) {
$ord_var_c = ord($var[$c]);
switch (true) {
case $ord_var_c == 0x8:
$ascii .= '\\b';
break;
case $ord_var_c == 0x9:
$ascii .= '\\t';
break;
case $ord_var_c == 0xa:
$ascii .= '\\n';
break;
case $ord_var_c == 0xc:
$ascii .= '\\f';
break;
case $ord_var_c == 0xd:
$ascii .= '\\r';
break;
case $ord_var_c == 0x22:
case $ord_var_c == 0x2f:
case $ord_var_c == 0x5c:
// double quote, slash, slosh
if ($options == JSON_UNESCAPED_SLASHES && $ord_var_c == 0x2f) {
$ascii .= $var[$c];
} else {
$ascii .= '\\' . $var[$c];
}
break;
case $ord_var_c >= 0x20 && $ord_var_c <= 0x7f:
// characters U-00000000 - U-0000007F (same as ASCII)
$ascii .= $var[$c];
break;
case ($ord_var_c & 0xe0) == 0xc0:
// characters U-00000080 - U-000007FF, mask 1 1 0 X X X X X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var[$c + 1]));
$c += 1;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\\u%04s', bin2hex($utf16));
break;
case ($ord_var_c & 0xf0) == 0xe0:
// characters U-00000800 - U-0000FFFF, mask 1 1 1 0 X X X X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var[$c + 1]), ord($var[$c + 2]));
$c += 2;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\\u%04s', bin2hex($utf16));
break;
case ($ord_var_c & 0xf8) == 0xf0:
// characters U-00010000 - U-001FFFFF, mask 1 1 1 1 0 X X X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var[$c + 1]), ord($var[$c + 2]), ord($var[$c + 3]));
$c += 3;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\\u%04s', bin2hex($utf16));
break;
case ($ord_var_c & 0xfc) == 0xf8:
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var[$c + 1]), ord($var[$c + 2]), ord($var[$c + 3]), ord($var[$c + 4]));
$c += 4;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\\u%04s', bin2hex($utf16));
break;
case ($ord_var_c & 0xfe) == 0xfc:
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$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]));
$c += 5;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\\u%04s', bin2hex($utf16));
break;
}
}
return '"' . $ascii . '"';
case 'array':
/*
* As per JSON spec if any array key is not an integer
* we must treat the the whole array as an object. We
* also try to catch a sparsely populated associative
* array with numeric keys here because some JS engines
* will create an array with empty indexes up to
* max_index which can cause memory issues and because
* the keys, which may be relevant, will be remapped
* otherwise.
*
* As per the ECMA and JSON specification an object may
* have any string as a property. Unfortunately due to
* a hole in the ECMA specification if the key is a
* ECMA reserved word or starts with a digit the
* parameter is only accessible using ECMAScript's
* bracket notation.
*/
// treat as a JSON object
if (is_array($var) && count($var) && array_keys($var) !== range(0, sizeof($var) - 1)) {
$optionsArray = array();
for ($i = 0; $i < count($var); $i++) {
$optionsArray[] = $options;
}
$properties = array_map(array($this, 'name_value'), array_keys($var), array_values($var), $optionsArray);
foreach ($properties as $property) {
if (Gpf_Rpc_Json::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
}
$optionsArray = array();
for ($i = 0; $i < count($var); $i++) {
$optionsArray[] = $options;
}
// treat it like a regular array
$elements = array_map(array($this, 'encode'), $var, $optionsArray);
foreach ($elements as $element) {
if (Gpf_Rpc_Json::isError($element)) {
return $element;
}
}
return '[' . join(',', $elements) . ']';
case 'object':
$vars = get_object_vars($var);
$optionsArray = array();
for ($i = 0; $i < count($vars); $i++) {
$optionsArray[] = $options;
}
$properties = array_map(array($this, 'name_value'), array_keys($vars), array_values($vars), $optionsArray);
foreach ($properties as $property) {
if (Gpf_Rpc_Json::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
default:
if ($this->use & self::SERVICES_JSON_SUPPRESS_ERRORS) {
return 'null';
}
return new Gpf_Rpc_Json_Error(gettype($var) . " can not be encoded as JSON string");
}
}