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 3rd 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 class 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
<?php /** * Marker constant for XoopsJSON::decode(), used to flag stack state */ define('XOOPS_JSON_SLICE', 1); /** * Marker constant for XoopsJSON::decode(), used to flag stack state */ define('XOOPS_JSON_IN_STR', 2); /** * Marker constant for XoopsJSON::decode(), used to flag stack state */ define('XOOPS_JSON_IN_ARR', 3); /** * Marker constant for XoopsJSON::decode(), used to flag stack state */ define('XOOPS_JSON_IN_OBJ', 4); /** * Marker constant for XoopsJSON::decode(), used to flag stack state */ define('XOOPS_JSON_IN_CMT', 5); /** * Behavior switch for XoopsJSON::decode() */ define('XOOPS_JSON_LOOSE_TYPE', 16); /** * Behavior switch for XoopsJSON::decode() */ define('XOOPS_JSON_SUPPRESS_ERRORS', 32); /** * Converts to and from JSON format. * * Brief example of use: * * <code> * // create a new instance of XoopsJSON * $json = new XoopsJSON(); * * // 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 XoopsJSON /*extends XoopsObject*/ { /** * constructs a new JSON instance * * @param int $use object behavior flags; combine with boolean-OR * * possible values: * - XOOPS_JSON_LOOSE_TYPE: loose typing. * "{...}" syntax creates associative arrays * instead of objects in decode(). * - XOOPS_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 XoopsJSON($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) { 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 ((0x7F & $bytes) == $bytes): return chr(0x7F & $bytes); case (0x07FF & $bytes) == $bytes: return chr(0xC0 | (($bytes >> 6) & 0x1F)) . chr(0x80 | ($bytes & 0x3F)); case (0xFFFF & $bytes) == $bytes: return chr(0xE0 | (($bytes >> 12) & 0x0F)) . chr(0x80 | (($bytes >> 6) & 0x3F)) . chr(0x80 | ($bytes & 0x3F)); } 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) { if(function_exists('mb_convert_encoding')) { return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); } switch(strlen($utf8)) { case 1: return $utf8; case 2: return chr(0x07 & (ord($utf8{0}) >> 2)) . chr((0xC0 & (ord($utf8{0}) << 6)) | (0x3F & ord($utf8{1}))); case 3: return chr((0xF0 & (ord($utf8{0}) << 4)) | (0x0F & (ord($utf8{1}) >> 2))) . chr((0xC0 & (ord($utf8{1}) << 6)) | (0x7F & ord($utf8{2}))); } return ''; } /** * encodes an arbitrary variable into JSON format (and sends JSON Header) * * @param mixed $var any number, boolean, string, array, or object to be encoded. * see argument 1 to XoopsJSON() 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) { header('Content-type: application/json'); return $this->encodeUnsafe($var); } /** * encodes an arbitrary variable into JSON format without JSON Header - warning - may allow CSS!!!!) * * @param mixed $var any number, boolean, string, array, or object to be encoded. * see argument 1 to XoopsJSON() 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 encodeUnsafe($var) { $lc = setlocale(LC_NUMERIC, 0); setlocale(LC_NUMERIC, 'C'); $ret = $this->_encode($var); setlocale(LC_NUMERIC, $lc); return $ret; } /** * PRIVATE CODE that does the work of encodes an arbitrary variable into JSON format * * @param mixed $var any number, boolean, string, array, or object to be encoded. * see argument 1 to XoopsJSON() 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': $ascii = ''; $strlen_var = strlen($var); for ($c = 0; $c < $strlen_var; ++$c) { $ord_var_c = ord($var{$c}); switch (true) { case $ord_var_c == 0x08: $ascii .= 'b'; break; case $ord_var_c == 0x09: $ascii .= 't'; break; case $ord_var_c == 0x0A: $ascii .= 'n'; break; case $ord_var_c == 0x0C: $ascii .= 'f'; break; case $ord_var_c == 0x0D: $ascii .= 'r'; break; case $ord_var_c == 0x22: case $ord_var_c == 0x2F: case $ord_var_c == 0x5C: $ascii .= '\'.$var{$c}; break; case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): $ascii .= $var{$c}; break; case (($ord_var_c & 0xE0) == 0xC0): if ($c+1 >= $strlen_var) { $c += 1; $ascii .= '?'; break; } $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): if ($c+2 >= $strlen_var) { $c += 2; $ascii .= '?'; break; } $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): if ($c+3 >= $strlen_var) { $c += 3; $ascii .= '?'; break; } $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): if ($c+4 >= $strlen_var) { $c += 4; $ascii .= '?'; break; } $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): if ($c+5 >= $strlen_var) { $c += 5; $ascii .= '?'; break; } $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': 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(XoopsJSON::isError($property)) { return $property; } } return '{' . join(',', $properties) . '}'; } $elements = array_map(array($this, '_encode'), $var); foreach($elements as $element) { if(XoopsJSON::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(XoopsJSON::isError($property)) { return $property; } } return '{' . join(',', $properties) . '}'; default: return ($this->use & XOOPS_JSON_SUPPRESS_ERRORS) ? 'null' : new XoopsJSON_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(XoopsJSON::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( '#^s*//(.+)$#m', '#^s*/*(.+)*/#Us', '#/*(.+)*/s*$#Us' ), '', $str); 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 XoopsJSON() 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)) { return ((float)$str == (integer)$str) ? (integer)$str : (float)$str; } elseif (preg_match('/^("|').*(1)$/s', $str, $m) && $m[1] == $m[2]) { $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(0x08); ++$c; break; case $substr_chrs_c_2 == 't': $utf8 .= chr(0x09); ++$c; break; case $substr_chrs_c_2 == 'n': $utf8 .= chr(0x0A); ++$c; break; case $substr_chrs_c_2 == 'f': $utf8 .= chr(0x0C); ++$c; break; case $substr_chrs_c_2 == 'r': $utf8 .= chr(0x0D); ++$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)): $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 >= 0x20) && ($ord_chrs_c <= 0x7F): $utf8 .= $chrs{$c}; break; case ($ord_chrs_c & 0xE0) == 0xC0: $utf8 .= substr($chrs, $c, 2); ++$c; break; case ($ord_chrs_c & 0xF0) == 0xE0: $utf8 .= substr($chrs, $c, 3); $c += 2; break; case ($ord_chrs_c & 0xF8) == 0xF0: $utf8 .= substr($chrs, $c, 4); $c += 3; break; case ($ord_chrs_c & 0xFC) == 0xF8: $utf8 .= substr($chrs, $c, 5); $c += 4; break; case ($ord_chrs_c & 0xFE) == 0xFC: $utf8 .= substr($chrs, $c, 6); $c += 5; break; } } return $utf8; } elseif (preg_match('/^[.*]$/s', $str) || preg_match('/^{.*}$/s', $str)) { if ($str{0} == '[') { $stk = array(XOOPS_JSON_IN_ARR); $arr = array(); } else { if ($this->use & XOOPS_JSON_LOOSE_TYPE) { $stk = array(XOOPS_JSON_IN_OBJ); $obj = array(); } else { $stk = array(XOOPS_JSON_IN_OBJ); $obj = new stdClass(); } } array_push($stk, array('what' => XOOPS_JSON_SLICE, 'where' => 0, 'delim' => false)); $chrs = substr($str, 1, -1); $chrs = $this->reduce_string($chrs); if ($chrs == '') { if (reset($stk) == XOOPS_JSON_IN_ARR) { return $arr; } else { return $obj; } } $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'] == XOOPS_JSON_SLICE))) { $slice = substr($chrs, $top['where'], ($c - $top['where'])); array_push($stk, array('what' => XOOPS_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); if (reset($stk) == XOOPS_JSON_IN_ARR) { array_push($arr, $this->decode($slice)); } elseif (reset($stk) == XOOPS_JSON_IN_OBJ) { $parts = array(); if (preg_match('/^s*(["'].*[^\]["'])s*:s*(S.*),?$/Uis', $slice, $parts)) { $key = $this->decode($parts[1]); $val = $this->decode($parts[2]); if ($this->use & XOOPS_JSON_LOOSE_TYPE) { $obj[$key] = $val; } else { $obj->$key = $val; } } elseif (preg_match('/^s*(w+)s*:s*(S.*),?$/Uis', $slice, $parts)) { $key = $parts[1]; $val = $this->decode($parts[2]); if ($this->use & XOOPS_JSON_LOOSE_TYPE) { $obj[$key] = $val; } else { $obj->$key = $val; } } } } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != XOOPS_JSON_IN_STR)) { array_push($stk, array('what' => XOOPS_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); } elseif (($chrs{$c} == $top['delim']) && ($top['what'] == XOOPS_JSON_IN_STR) && ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\'))) % 2 != 1)) { array_pop($stk); } elseif (($chrs{$c} == '[') && in_array($top['what'], array(XOOPS_JSON_SLICE, XOOPS_JSON_IN_ARR, XOOPS_JSON_IN_OBJ))) { array_push($stk, array('what' => XOOPS_JSON_IN_ARR, 'where' => $c, 'delim' => false)); } elseif (($chrs{$c} == ']') && ($top['what'] == XOOPS_JSON_IN_ARR)) { array_pop($stk); } elseif (($chrs{$c} == '{') && in_array($top['what'], array(XOOPS_JSON_SLICE, XOOPS_JSON_IN_ARR, XOOPS_JSON_IN_OBJ))) { array_push($stk, array('what' => XOOPS_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); } elseif (($chrs{$c} == '}') && ($top['what'] == XOOPS_JSON_IN_OBJ)) { array_pop($stk); } elseif (($substr_chrs_c_2 == '/*') && in_array($top['what'], array(XOOPS_JSON_SLICE, XOOPS_JSON_IN_ARR, XOOPS_JSON_IN_OBJ))) { array_push($stk, array('what' => XOOPS_JSON_IN_CMT, 'where' => $c, 'delim' => false)); $c++; } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == XOOPS_JSON_IN_CMT)) { array_pop($stk); $c++; for ($i = $top['where']; $i <= $c; ++$i) $chrs = substr_replace($chrs, ' ', $i, 1); } } if (reset($stk) == XOOPS_JSON_IN_ARR) { return $arr; } elseif (reset($stk) == XOOPS_JSON_IN_OBJ) { return $obj; } } } } function isError($data, $code = null) { if (is_object($data) && (get_class($data) == 'services_json_error' || is_subclass_of($data, 'services_json_error'))) { return true; } return false; } } class XoopsJSON_Error { function XoopsJSON_Error($message = 'unknown error', $code = null, $mode = null, $options = null, $userinfo = null) { trigger_error($message); } } ?>
This class would normally live in /class/xoopsjson.php JSON is a fantastic feature we now have access to for forms, objects pages anything advanced with XOOPS and JQuery especially JSON for checking form inputs is great!!