<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Converts to and from JSON format .
*
* JSON ( JavaScript Object Notation ) is a lightweight data - interchange
* format . It is easy for humans to read and write . It is easy for machines
* to parse and generate . It is based on a subset of the JavaScript
* Programming Language , Standard ECMA - 262 3 rd Edition - December 1999 .
* This feature can also be found in Python . JSON is a text format that is
* completely language independent but uses conventions that are familiar
* to programmers of the C - family of languages , including C , C + + , C # , Java ,
* JavaScript , Perl , TCL , and many others . These properties make JSON an
* ideal data - interchange language .
*
* This package provides a simple encoder and decoder for JSON notation . It
* is intended for use with client - side Javascript applications that make
* use of HTTPRequest to perform server communication functions - data can
* be encoded into JSON notation for use in a client - side javascript , or
* decoded from incoming Javascript requests . JSON format is native to
* Javascript , and can be directly eval ( ) ' ed with no further parsing
* overhead
*
* All strings should be in ASCII or UTF - 8 format !
*
* LICENSE : Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met : Redistributions of source code must retain the
* above copyright notice , this list of conditions and the following
* disclaimer . Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following disclaimer
* in the documentation and / or other materials provided with the
* distribution .
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS
* OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR
* TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE .
*
* @ category
* @ package Services_JSON
* @ author Michal Migurski < mike - json @ teczno . com >
* @ author Matt Knapp < mdknapp [ at ] gmail [ dot ] com >
* @ author Brett Stimmerman < brettstimmerman [ at ] gmail [ dot ] com >
* @ copyright 2005 Michal Migurski
* @ version CVS : $ Id $
* @ license http : / / www . opensource . org / licenses / bsd - license . php
* @ link http : / / pear . php . net / pepr / pepr - proposal - show . php ? id = 198
*/
/**
* Marker constant for Services_JSON : : decode ( ) , used to flag stack state
*/
define(
'SERVICES_JSON_SLICE' ,
1 );
/**
* Marker constant for Services_JSON : : decode ( ) , used to flag stack state
*/
define(
'SERVICES_JSON_IN_STR' ,
2 );
/**
* Marker constant for Services_JSON : : decode ( ) , used to flag stack state
*/
define(
'SERVICES_JSON_IN_ARR' ,
3 );
/**
* Marker constant for Services_JSON : : decode ( ) , used to flag stack state
*/
define(
'SERVICES_JSON_IN_OBJ' ,
4 );
/**
* Marker constant for Services_JSON : : decode ( ) , used to flag stack state
*/
define(
'SERVICES_JSON_IN_CMT' ,
5 );
/**
* Behavior switch for Services_JSON : : decode ( )
*/
define(
'SERVICES_JSON_LOOSE_TYPE' ,
16 );
/**
* Behavior switch for Services_JSON : : decode ( )
*/
define(
'SERVICES_JSON_SUPPRESS_ERRORS' ,
32 );
/**
* Converts to and from JSON format .
*
* Brief example of use :
*
* < code >
* / / create a new instance of Services_JSON
* $ json = new Services_JSON ( ) ;
*
* / / convert a complexe value to JSON notation , and send it to the browser
* $ value = array ( ' foo ' , ' bar ' , array ( 1 , 2 , ' baz ' ) , array ( 3 , array ( 4 ) ) ) ;
* $ output = $ json - > encode ( $ value ) ;
*
* print ( $ output ) ;
* / / prints : [ " foo " , " bar " , [ 1 , 2 , " baz " ] , [ 3 , [ 4 ] ] ]
*
* / / accept incoming POST data , assumed to be in JSON notation
* $ input = file_get_contents ( ' php : / / input ' , 1000000 ) ;
* $ value = $ json - > decode ( $ input ) ;
* < / code >
*/
class Services_JSON
{
/**
* constructs a new JSON instance
*
* @ param int $ use object behavior flags ; combine with boolean - OR
*
* possible values :
* - SERVICES_JSON_LOOSE_TYPE : loose typing .
* " { . . . } " syntax creates associative arrays
* instead of objects in decode ( ) .
* - SERVICES_JSON_SUPPRESS_ERRORS : error suppression .
* Values which can ' t be encoded ( e . g . resources )
* appear as NULL instead of throwing errors .
* By default , a deeply - nested resource will
* bubble up with an error , so all return values
* from encode ( ) should be checked with isError ( )
*/
function Services_JSON($
use =
0 )
{
$this->
use = $
use ;
}
/**
* convert a string from one UTF - 16 char to one UTF - 8 char
*
* Normally should be handled by mb_convert_encoding , but
* provides a slower PHP - only method for installations
* that lack the multibye string extension .
*
* @ param string $ utf16 UTF - 16 character
* @ return string UTF - 8 character
* @ access private
*/
function utf162utf8($utf16)
{
// oh please oh please oh please oh please oh please
if (function_exists(
'mb_convert_encoding' )) {
return mb_convert_encoding($utf16,
'UTF-8' ,
'UTF-16' );
}
$bytes = (ord($utf16{
0 }) <<
8 ) | ord($utf16{
1 });
switch (true) {
case ((
0 x7F & $bytes) == $bytes):
// this
case should never be reached, because we are in ASCII range
// see:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
return chr(
0 x7F & $bytes);
case (
0 x07FF & $bytes) == $bytes:
//
return a
2 -byte UTF-
8 character
// see:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
return chr(
0 xC0 | (($bytes >>
6 ) &
0 x1F))
. chr(
0 x80 | ($bytes &
0 x3F));
case (
0 xFFFF & $bytes) == $bytes:
//
return a
3 -byte UTF-
8 character
// see:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
return chr(
0 xE0 | (($bytes >>
12 ) &
0 x0F))
. chr(
0 x80 | (($bytes >>
6 ) &
0 x3F))
. chr(
0 x80 | ($bytes &
0 x3F));
}
// ignoring UTF-
32 for now, sorry
return '' ;
}
/**
* convert a string from one UTF - 8 char to one UTF - 16 char
*
* Normally should be handled by mb_convert_encoding , but
* provides a slower PHP - only method for installations
* that lack the multibye string extension .
*
* @ param string $ utf8 UTF - 8 character
* @ return string UTF - 16 character
* @ access private
*/
function utf82utf16($utf8)
{
// oh please oh please oh please oh please oh please
if (function_exists(
'mb_convert_encoding' )) {
return mb_convert_encoding($utf8,
'UTF-16' ,
'UTF-8' );
}
switch (strlen($utf8)) {
case 1 :
// this
case should never be reached, because we are in ASCII range
// see:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
return $utf8;
case 2 :
//
return a UTF-
16 character from a
2 -byte UTF-
8 char
// see:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
return chr(
0 x07 & (ord($utf8{
0 }) >>
2 ))
. chr((
0 xC0 & (ord($utf8{
0 }) <<
6 ))
| (
0 x3F & ord($utf8{
1 })));
case 3 :
//
return a UTF-
16 character from a
3 -byte UTF-
8 char
// see:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
return chr((
0 xF0 & (ord($utf8{
0 }) <<
4 ))
| (
0 x0F & (ord($utf8{
1 }) >>
2 )))
. chr((
0 xC0 & (ord($utf8{
1 }) <<
6 ))
| (
0 x7F & ord($utf8{
2 })));
}
// ignoring UTF-
32 for now, sorry
return '' ;
}
/**
* encodes an arbitrary variable into JSON format
*
* @ param mixed $ var any number , boolean , string , array , or object to be encoded .
* see argument 1 to Services_JSON ( ) above for array - parsing behavior .
* if var is a strng , note that encode ( ) always expects it
* to be in ASCII or UTF - 8 format !
*
* @ return mixed JSON string representation of input var or an error if a problem occurs
* @ access public
*/
function encode($
var )
{
switch (gettype($
var )) {
case 'boolean' :
return $
var ?
'true' :
'false' ;
case 'NULL' :
return 'null' ;
case 'integer' :
return (int) $
var ;
case 'double' :
case 'float' :
return (float) $
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 ==
0 x08:
$ascii .=
'\b' ;
break ;
case $ord_var_c ==
0 x09:
$ascii .=
'\t' ;
break ;
case $ord_var_c ==
0 x0A:
$ascii .=
'\n' ;
break ;
case $ord_var_c ==
0 x0C:
$ascii .=
'\f' ;
break ;
case $ord_var_c ==
0 x0D:
$ascii .=
'\r' ;
break ;
case $ord_var_c ==
0 x22:
case $ord_var_c ==
0 x2F:
case $ord_var_c ==
0 x5C:
// double quote, slash, slosh
$ascii .=
'\\' .$
var {$c};
break ;
case (($ord_var_c >=
0 x20) && ($ord_var_c <=
0 x7F)):
// characters U-
00000000 - U-
0000007 F (same
as ASCII)
$ascii .= $
var {$c};
break ;
case (($ord_var_c &
0 xE0) ==
0 xC0):
// characters U-
00000080 - U-
000007 FF, mask
110 XXXXX
// 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 &
0 xF0) ==
0 xE0):
// characters U-
00000800 - U-
0000 FFFF, mask
1110 XXXX
// 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 &
0 xF8) ==
0 xF0):
// characters U-
00010000 - U-
001 FFFFF, mask
11110 XXX
// 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 &
0 xFC) ==
0 xF8):
// characters U-
00200000 - U-
03 FFFFFF, mask
111110 XX
// 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 &
0 xFE) ==
0 xFC):
// characters U-
04000000 - U-
7 FFFFFFF, mask
1111110 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 }),
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 ))) {
$properties = array_map(
array ($this,
'name_value' ),
array_keys($
var ),
array_values($
var ));
foreach ($properties
as $property) {
if (Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(
',' , $properties) .
'}' ;
}
// treat it like a regular
array
$elements = array_map(
array ($this,
'encode' ), $
var );
foreach ($elements
as $element) {
if (Services_JSON::isError($element)) {
return $element;
}
}
return '[' . join(
',' , $elements) .
']' ;
case 'object' :
$vars = get_object_vars($
var );
$properties = array_map(
array ($this,
'name_value' ),
array_keys($vars),
array_values($vars));
foreach ($properties
as $property) {
if (Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(
',' , $properties) .
'}' ;
default :
return ($this->
use & SERVICES_JSON_SUPPRESS_ERRORS)
?
'null'
:
new Services_JSON_Error(gettype($
var ).
" can not be encoded as JSON string" );
}
}
/**
* array - walking function for use in generating JSON - formatted name - value pairs
*
* @ param string $ name name of key to use
* @ param mixed $ value reference to an array element to be encoded
*
* @ return string JSON - formatted name - value pair , like ' " name " : value '
* @ access private
*/
function name_value($name, $value)
{
$encoded_value = $this->encode($value);
if (Services_JSON::isError($encoded_value)) {
return $encoded_value;
}
return $this->encode(strval($name)) .
':' . $encoded_value;
}
/**
* reduce a string by removing leading and trailing comments and whitespace
*
* @ param $ str string string value to strip of comments and whitespace
*
* @ return string string value stripped of comments and whitespace
* @ access private
*/
function reduce_string($str)
{
$str = preg_replace(
array (
// eliminate single line comments in
'// ...' form
'#^\s*//(.+)$#m' ,
// eliminate multi-line comments in
'/* ... */' form, at start of string
'#^\s*/\*(.+)\*/#Us' ,
// eliminate multi-line comments in
'/* ... */' form, at end of string
'#/\*(.+)\*/\s*$#Us'
),
'' , $str);
// eliminate extraneous space
return trim($str);
}
/**
* decodes a JSON string into appropriate variable
*
* @ param string $ str JSON - formatted string
*
* @ return mixed number , boolean , string , array , or object
* corresponding to given JSON input string .
* See argument 1 to Services_JSON ( ) above for object - output behavior .
* Note that decode ( ) always returns strings
* in ASCII or UTF - 8 format !
* @ access public
*/
function decode($str)
{
$str = $this->reduce_string($str);
switch (strtolower($str)) {
case 'true' :
return true;
case 'false' :
return false;
case 'null' :
return null;
default :
$m =
array ();
if (is_numeric($str)) {
// Lookie-loo, it
's a number
// This would work on its own, but I
'm trying to be
// good about returning integers where appropriate:
//
return (float)$str;
//
Return float
or int,
as appropriate
return ((float)$str == (integer)$str)
? (integer)$str
: (float)$str;
}
elseif (preg_match(
'/^("|\' ).*(\
1 )$/s
', $str, $m) && $m[1] == $m[2]) {
// STRINGS RETURNED IN UTF-
8 FORMAT
$delim = substr($str,
0 ,
1 );
$chrs = substr($str,
1 , -
1 );
$utf8 =
'' ;
$strlen_chrs = strlen($chrs);
for ($c =
0 ; $c < $strlen_chrs; ++$c) {
$substr_chrs_c_2 = substr($chrs, $c,
2 );
$ord_chrs_c = ord($chrs{$c});
switch (true) {
case $substr_chrs_c_2 ==
'\b' :
$utf8 .= chr(
0 x08);
++$c;
break ;
case $substr_chrs_c_2 ==
'\t' :
$utf8 .= chr(
0 x09);
++$c;
break ;
case $substr_chrs_c_2 ==
'\n' :
$utf8 .= chr(
0 x0A);
++$c;
break ;
case $substr_chrs_c_2 ==
'\f' :
$utf8 .= chr(
0 x0C);
++$c;
break ;
case $substr_chrs_c_2 ==
'\r' :
$utf8 .= chr(
0 x0D);
++$c;
break ;
case $substr_chrs_c_2 ==
'\\"' :
case $substr_chrs_c_2 ==
'\\\' ':
case $substr_chrs_c_2 ==
'\\\\' :
case $substr_chrs_c_2 ==
'\\/' :
if (($delim ==
'"' && $substr_chrs_c_2 !=
'\\\' ') ||
($delim ==
"'" && $substr_chrs_c_2 !=
'\\"' )) {
$utf8 .= $chrs{++$c};
}
break ;
case preg_match(
'/\\\u[0-9A-F]{4}/i' , substr($chrs, $c,
6 )):
// single, escaped unicode character
$utf16 = chr(hexdec(substr($chrs, ($c +
2 ),
2 )))
. chr(hexdec(substr($chrs, ($c +
4 ),
2 )));
$utf8 .= $this->utf162utf8($utf16);
$c +=
5 ;
break ;
case ($ord_chrs_c >=
0 x20) && ($ord_chrs_c <=
0 x7F):
$utf8 .= $chrs{$c};
break ;
case ($ord_chrs_c &
0 xE0) ==
0 xC0:
// characters U-
00000080 - U-
000007 FF, mask
110 XXXXX
//see
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
$utf8 .= substr($chrs, $c,
2 );
++$c;
break ;
case ($ord_chrs_c &
0 xF0) ==
0 xE0:
// characters U-
00000800 - U-
0000 FFFF, mask
1110 XXXX
// see
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
$utf8 .= substr($chrs, $c,
3 );
$c +=
2 ;
break ;
case ($ord_chrs_c &
0 xF8) ==
0 xF0:
// characters U-
00010000 - U-
001 FFFFF, mask
11110 XXX
// see
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
$utf8 .= substr($chrs, $c,
4 );
$c +=
3 ;
break ;
case ($ord_chrs_c &
0 xFC) ==
0 xF8:
// characters U-
00200000 - U-
03 FFFFFF, mask
111110 XX
// see
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
$utf8 .= substr($chrs, $c,
5 );
$c +=
4 ;
break ;
case ($ord_chrs_c &
0 xFE) ==
0 xFC:
// characters U-
04000000 - U-
7 FFFFFFF, mask
1111110 X
// see
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf- 8
$utf8 .= substr($chrs, $c,
6 );
$c +=
5 ;
break ;
}
}
return $utf8;
}
elseif (preg_match(
'/^\[.*\]$/s' , $str) || preg_match(
'/^\{.*\}$/s' , $str)) {
//
array ,
or object notation
if ($str{
0 } ==
'[' ) {
$stk =
array (SERVICES_JSON_IN_ARR);
$arr =
array ();
}
else {
if ($this->
use & SERVICES_JSON_LOOSE_TYPE) {
$stk =
array (SERVICES_JSON_IN_OBJ);
$obj =
array ();
}
else {
$stk =
array (SERVICES_JSON_IN_OBJ);
$obj =
new stdClass();
}
}
array_push($stk,
array (
'what' => SERVICES_JSON_SLICE,
'where' =>
0 ,
'delim' => false));
$chrs = substr($str,
1 , -
1 );
$chrs = $this->reduce_string($chrs);
if ($chrs ==
'' ) {
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
}
else {
return $obj;
}
}
//
print (
"\nparsing {$chrs}\n" );
$strlen_chrs = strlen($chrs);
for ($c =
0 ; $c <= $strlen_chrs; ++$c) {
$top = end($stk);
$substr_chrs_c_2 = substr($chrs, $c,
2 );
if (($c == $strlen_chrs) || (($chrs{$c} ==
',' ) && ($top[
'what' ] == SERVICES_JSON_SLICE))) {
// found a comma that is not inside a string,
array , etc.,
//
OR we
've reached the end of the character list
$slice = substr($chrs, $top[
'where' ], ($c - $top[
'where' ]));
array_push($stk,
array (
'what' => SERVICES_JSON_SLICE,
'where' => ($c +
1 ),
'delim' => false));
//
print (
"Found split at {$c}: " .substr($chrs, $top[
'where' ], (
1 + $c - $top[
'where' ])).
"\n" );
if (reset($stk) == SERVICES_JSON_IN_ARR) {
// we are in an
array , so just push an element onto the stack
array_push($arr, $this->decode($slice));
}
elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
// we are in an object, so figure
// out the property name
and set an
// element in an associative
array ,
//
for now
$parts =
array ();
if (preg_match(
'/^\s*(["\' ].*[^\\\][
"\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
//
"name" :value pair
$key = $this->decode($parts[
1 ]);
$val = $this->decode($parts[
2 ]);
if ($this->
use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
}
else {
$obj->$key = $val;
}
}
elseif (preg_match(
'/^\s*(\w+)\s*:\s*(\S.*),?$/Uis' , $slice, $parts)) {
// name:value pair, where name is unquoted
$key = $parts[
1 ];
$val = $this->decode($parts[
2 ]);
if ($this->
use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
}
else {
$obj->$key = $val;
}
}
}
}
elseif ((($chrs{$c} ==
'"' ) || ($chrs{$c} ==
"'" )) && ($top[
'what' ] != SERVICES_JSON_IN_STR)
) {
// found a quote, and we are not inside a string
array_push($stk, array ('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
//print ("Found start of string at {$c}\n" );
} elseif (($chrs{$c} == $top['delim' ]) &&
($top['what' ] == SERVICES_JSON_IN_STR) &&
((strlen(substr($chrs, 0 , $c)) - strlen(rtrim(substr($chrs, 0 , $c), '\\' ))) % 2 != 1)) {
// found a quote, we're in a string, and it' s not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print ("Found end of string at {$c}: " .substr($chrs, $top['where' ], (1 + 1 + $c - $top['where' ]))."\n" );
} elseif (($chrs{$c} == '[' ) &&
in_array($top['what' ], array (SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-bracket, and we are in an array , object, or slice
array_push($stk, array ('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
//print ("Found start of array at {$c}\n" );
} elseif (($chrs{$c} == ']' ) && ($top['what' ] == SERVICES_JSON_IN_ARR)) {
// found a right-bracket, and we're in an array
array_pop($stk);
//print ("Found end of array at {$c}: " .substr($chrs, $top['where' ], (1 + $c - $top['where' ]))."\n" );
} elseif (($chrs{$c} == '{' ) &&
in_array($top['what' ], array (SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-brace, and we are in an array , object, or slice
array_push($stk, array ('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
//print ("Found start of object at {$c}\n" );
} elseif (($chrs{$c} == '}' ) && ($top['what' ] == SERVICES_JSON_IN_OBJ)) {
// found a right-brace, and we're in an object
array_pop($stk);
//print ("Found end of object at {$c}: " .substr($chrs, $top['where' ], (1 + $c - $top['where' ]))."\n" );
} elseif (($substr_chrs_c_2 == '/*') &&
in_array($top['what' ], array (SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a comment start, and we are in an array , object, or slice
array_push($stk, array ('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
$c++;
//print ("Found start of comment at {$c}\n" );
} elseif (($substr_chrs_c_2 == '*/' ) && ($top['what' ] == SERVICES_JSON_IN_CMT)) {
// found a comment end, and we're in one now
array_pop($stk);
$c++;
for ($i = $top['where' ]; $i <= $c; ++$i)
$chrs = substr_replace($chrs, ' ' , $i, 1 );
//print ("Found end of comment at {$c}: " .substr($chrs, $top['where' ], (1 + $c - $top['where' ]))."\n" );
}
}
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
return $obj;
}
}
}
}
/**
* @ todo Ultimately , this should just call PEAR : : isError ( )
*/
function isError($data, $code = null)
{
if (class_exists('pear' )) {
return PEAR::isError($data, $code);
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
is_subclass_of($data, 'services_json_error' ))) {
return true;
}
return false;
}
}
if (class_exists('PEAR_Error' )) {
class Services_JSON_Error extends PEAR_Error
{
function Services_JSON_Error($message = 'unknown error' , $code = null,
$mode = null, $options = null, $userinfo = null)
{
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
}
}
} else {
/**
* @ todo Ultimately , this class shall be descended from PEAR_Error
*/
class Services_JSON_Error
{
function Services_JSON_Error($message = 'unknown error' , $code = null,
$mode = null, $options = null, $userinfo = null)
{
}
}
}
?>
Messung V0.5 in Prozent C=89 H=86 G=87
¤ Dauer der Verarbeitung: 0.17 Sekunden
¤
*© Formatika GbR, Deutschland