--- /dev/null
+<?php
+/**
+ * @package Horde_Serialize
+ */
+
+require_once 'Horde/Serialize.php';
+
+// Convert a complex value to JSON notation, and send it to the
+// browser.
+$value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
+echo Horde_Serialize::serialize($value, SERIALIZE_JSON);
+// prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
+
+// Accept incoming POST data, assumed to be in JSON notation.
+var_dump(Horde_Serialize::unserialize(file_get_contents('php://stdin'), SERIALIZE_JSON));
--- /dev/null
+<?php
+/**
+ * The Serialize:: class provides various methods of encapsulating data.
+ *
+ * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Stephane Huther <shuther1@free.fr>
+ * @package Horde_Serialize
+ * @category Horde
+ */
+
+/* TODO */
+define('SERIALIZE_UNKNOWN', -1);
+define('SERIALIZE_NONE', 0);
+define('SERIALIZE_WDDX', 1);
+define('SERIALIZE_BZIP', 2);
+define('SERIALIZE_IMAP8', 3);
+define('SERIALIZE_IMAPUTF7', 4);
+define('SERIALIZE_IMAPUTF8', 5);
+define('SERIALIZE_BASIC', 6);
+define('SERIALIZE_GZ_DEFLATE', 7);
+define('SERIALIZE_GZ_COMPRESS', 8);
+define('SERIALIZE_GZ_ENCOD', 9);
+define('SERIALIZE_BASE64', 10);
+define('SERIALIZE_SQLXML', 11);
+define('SERIALIZE_RAW', 12);
+define('SERIALIZE_URL', 13);
+define('SERIALIZE_UTF7', 14);
+define('SERIALIZE_UTF7_BASIC', 15);
+define('SERIALIZE_JSON', 16);
+define('SERIALIZE_LZF', 17);
+
+class Horde_Serialize
+{
+ /* Type constants */
+ const UNKNOWN = -1;
+ const NONE = 0;
+ const WDDX = 1;
+ const BZIP = 2;
+ const IMAP8 = 3;
+ const IMAPUTF7 = 4;
+ const IMAPUTF8 = 5;
+ const BASIC = 6;
+ const GZ_DEFLATE = 7;
+ const GZ_COMPRESS = 8;
+ const GZ_ENCODE = 9;
+ const BASE64 = 10;
+ const SQLXML = 11;
+ const RAW = 12;
+ const URL = 13;
+ const UTF7 = 14;
+ const UTF7_BASIC = 15;
+ const JSON = 16;
+ const LZF = 17;
+
+ /**
+ * Serialize a value.
+ *
+ * See the list of constants at the top of the file for the serializing
+ * techniques that can be used.
+ *
+ * @param mixed $data The data to be serialized.
+ * @param mixed $mode The mode of serialization. Can be either a single
+ * mode or array of modes. If array, will be
+ * serialized in the order provided.
+ * @param mixed $params Any additional parameters the serialization method
+ * requires.
+ *
+ * @return string The serialized data.
+ * Returns PEAR_Error on error.
+ */
+ static public function serialize($data, $mode = array(self::BASIC),
+ $params = null)
+ {
+ if (!is_array($mode)) {
+ $mode = array($mode);
+ }
+
+ /* Parse through the list of serializing modes. */
+ foreach ($mode as $val) {
+ /* Check to make sure the mode is supported. */
+ if (!self::hasCapability($val)) {
+ return PEAR::raiseError('Unsupported serialization type');
+ }
+ $data = self::_serialize($data, $val, $params);
+ if (is_a($data, 'PEAR_Error')) {
+ break;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Unserialize a value.
+ *
+ * See the list of constants at the top of the file for the serializing
+ * techniques that can be used.
+ *
+ * @param mixed $data The data to be unserialized.
+ * @param mixed $mode The mode of unserialization. Can be either a
+ * single mode or array of modes. If array, will be
+ * unserialized in the order provided.
+ * @param mixed $params Any additional parameters the unserialization
+ * method requires.
+ *
+ * @return string The unserialized data.
+ * Returns PEAR_Error on error.
+ */
+ static public function unserialize($data, $mode = self::BASIC,
+ $params = null)
+ {
+ if (!is_array($mode)) {
+ $mode = array($mode);
+ }
+
+ /* Parse through the list of unserializing modes. */
+ foreach ($mode as $val) {
+ /* Check to make sure the mode is supported. */
+ if (!self::hasCapability($val)) {
+ return PEAR::raiseError('Unsupported unserialization type');
+ }
+ $data = self::_unserialize($data, $val, $params);
+ if (is_a($data, 'PEAR_Error')) {
+ break;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Check whether or not a serialization method is supported.
+ *
+ * @param integer $mode The serialization method.
+ *
+ * @return boolean True if supported, false if not.
+ */
+ static public function hasCapability($mode)
+ {
+ switch ($mode) {
+ case self::BZIP:
+ return Util::extensionExists('bz2');
+
+ case self::WDDX:
+ return Util::extensionExists('wddx');
+
+ case self::IMAPUTF7:
+ return class_exists('Horde_Imap_Client');
+
+ case self::IMAP8:
+ case self::IMAPUTF8:
+ return class_exists('Horde_Mime');
+
+ case self::GZ_DEFLATE:
+ case self::GZ_COMPRESS:
+ case self::GZ_ENCODE:
+ return Util::extensionExists('zlib');
+
+ case self::SQLXML:
+ return @include_once 'XML/sql2xml.php';
+
+ case self::LZF:
+ return Util::extensionExists('lzf');
+
+ case self::NONE:
+ case self::BASIC:
+ case self::BASE64:
+ case self::RAW:
+ case self::URL:
+ case self::UTF7:
+ case self::UTF7_BASIC:
+ case self::JSON:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Serialize data.
+ *
+ * @param mixed $data The data to be serialized.
+ * @param mixed $mode The mode of serialization. Can be
+ * either a single mode or array of modes.
+ * If array, will be serialized in the
+ * order provided.
+ * @param mixed $params Any additional parameters the serialization method
+ * requires.
+ *
+ * @return string A serialized string or PEAR_Error on error.
+ */
+ static protected function _serialize($data, $mode, $params = null)
+ {
+ switch ($mode) {
+ case self::NONE:
+ break;
+
+ // $params['level'] = Level of compression (default: 3)
+ // $params['workfactor'] = How does compression phase behave when given
+ // worst case, highly repetitive, input data
+ // (default: 30)
+ case self::BZIP:
+ $data = bzcompress($data, isset($params['level']) ? $params['level'] : 3, isset($params['workfactor']) ? $params['workfactor'] : 30);
+ if (is_integer($data)) {
+ $data = false;
+ }
+ break;
+
+ case self::WDDX:
+ $data = wddx_serialize_value($data);
+ break;
+
+ case self::IMAP8:
+ $data = Horde_Mime::quotedPrintableEncode($data);
+ break;
+
+ case self::IMAPUTF7:
+ require_once 'Horde/String.php';
+ $data = Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap(String::convertCharset($data, 'ISO-8859-1', 'UTF-8'));
+ break;
+
+ case self::IMAPUTF8:
+ $data = Horde_Mime::decode($data, 'UTF-8');
+ break;
+
+ // $params['level'] = Level of compression (default: 3)
+ case self::GZ_DEFLATE:
+ $data = gzdeflate($data, isset($params['level']) ? $params['level'] : 3);
+ break;
+
+ case self::BASIC:
+ $data = serialize($data);
+ break;
+
+ // $params['level'] = Level of compression (default: 3)
+ case self::GZ_COMPRESS:
+ $data = gzcompress($data, isset($params['level']) ? $params['level'] : 3);
+ break;
+
+ case self::BASE64:
+ $data = base64_encode($data);
+ break;
+
+ // $params['level'] = Level of compression (default: 3)
+ case self::GZ_ENCOD:
+ $data = gzencode($data, isset($params['level']) ? $params['level'] : 3);
+ break;
+
+ case self::RAW:
+ $data = rawurlencode($data);
+ break;
+
+ case self::URL:
+ $data = urlencode($data);
+ break;
+
+ case self::SQLXML:
+ require_once 'DB.php';
+ $sql2xml = &new xml_sql2xml();
+ $data = $sql2xml->getXML($data);
+ break;
+
+ // $params = Source character set
+ case self::UTF7:
+ require_once 'Horde/String.php';
+ $data = String::convertCharset($data, $params, 'UTF-7');
+ break;
+
+ // $params = Source character set
+ case self::UTF7_BASIC:
+ $data = self::serialize($data, array(self::UTF7, self::BASIC), $params);
+ break;
+
+ // $params = Source character set
+ case self::JSON:
+ require_once 'Horde/String.php';
+ if (!empty($params)) {
+ $data = String::convertCharset($data, $params, 'UTF-8');
+ }
+ $data = json_encode($data);
+ break;
+
+ case self::LZF:
+ $data = lzf_compress($data);
+ break;
+ }
+
+ if ($data === false) {
+ return PEAR::raiseError('Serialization failed.');
+ }
+ return $data;
+ }
+
+ /**
+ * Unserialize data.
+ *
+ * @param mixed $data The data to be unserialized.
+ * @param mixed $mode The mode of unserialization. Can be either a
+ * single mode or array of modes. If array, will be
+ * unserialized in the order provided.
+ * @param mixed $params Any additional parameters the unserialization
+ * method requires.
+ *
+ * @return mixed Unserialized data on success or PEAR_Error on error.
+ */
+ static public function _unserialize(&$data, $mode, $params = null)
+ {
+ switch ($mode) {
+ case self::NONE:
+ case self::SQLXML:
+ break;
+
+ case self::RAW:
+ $data = rawurldecode($data);
+ break;
+
+ case self::URL:
+ $data = urldecode($data);
+ break;
+
+ case self::WDDX:
+ $data = wddx_deserialize($data);
+ break;
+
+ case self::BZIP:
+ // $params['small'] = Use bzip2 'small memory' mode?
+ $data = bzdecompress($data, isset($params['small']) ? $params['small'] : false);
+ break;
+
+ case self::IMAP8:
+ $data = quoted_printable_decode($data);
+ break;
+
+ case self::IMAPUTF7:
+ require_once 'Horde/String.php';
+ $data = String::convertCharset(Horde_Imap_Client_Utf7imap::Utf7ImapToUtf8($data), 'UTF-8', 'ISO-8859-1');
+ break;
+
+ case self::IMAPUTF8:
+ $data = Horde_Mime::encode($data, 'UTF-8');
+ break;
+
+ case self::BASIC:
+ $data2 = @unserialize($data);
+ // Unserialize can return false both on error and if $data is the
+ // false value.
+ if (($data2 === false) && ($data == serialize(false))) {
+ return $data2;
+ }
+ $data = $data2;
+ break;
+
+ case self::GZ_DEFLATE:
+ $data = gzinflate($data);
+ break;
+
+ case self::BASE64:
+ $data = base64_decode($data);
+ break;
+
+ case self::GZ_COMPRESS:
+ $data = gzuncompress($data);
+ break;
+
+ // $params = Output character set
+ case self::UTF7:
+ require_once 'Horde/String.php';
+ $data = String::convertCharset($data, 'utf-7', $params);
+ break;
+
+ // $params = Output character set
+ case self::UTF7_BASIC:
+ $data = self::unserialize($data, array(self::BASIC, self::UTF7), $params);
+ break;
+
+ case self::JSON:
+ $data = json_decode($data);
+ break;
+
+ case self::LZF:
+ $data = @lzf_decompress($data);
+ break;
+ }
+
+ if ($data === false) {
+ return PEAR::raiseError('Unserialization failed.');
+ }
+ return $data;
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>Serialize</name>
+ <channel>pear.horde.org</channel>
+ <summary>Data Encapulation API</summary>
+ <description>The Horde_Serialize:: class provides various methods of
+ encapsulating data.
+ </description>
+ <lead>
+ <name>Chuck Hagenbuch</name>
+ <user>chuck</user>
+ <email>chuck@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Jan Schneider</name>
+ <user>jan</user>
+ <email>jan@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <date>2009-02-12</date>
+ <version>
+ <release>0.1.0</release>
+ <api>0.1.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>* Initial Horde 4 package.</notes>
+ <contents>
+ <dir name="/">
+ <dir name="lib">
+ <dir name="Horde">
+ <file name="Serialize.php" role="php" />
+ </dir> <!-- /lib/Horde -->
+ </dir> <!-- /lib/ -->
+ <dir name="test">
+ <dir name="Horde">
+ <dir name="Serialize">
+ <file name="json_assoc_array.phpt" role="test" />
+ <file name="json_empty.phpt" role="test" />
+ <file name="json_encode_decode.phpt" role="test" />
+ <file name="json_nested_array.phpt" role="test" />
+ <file name="json_object.phpt" role="test" />
+ <file name="json_spaces_comments.phpt" role="test" />
+ <file name="json_unquoted_keys.phpt" role="test" />
+ </dir> <!-- /test/Horde/Serialize -->
+ </dir> <!-- /test/Horde -->
+ </dir> <!-- /test -->
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.5.0</min>
+ </pearinstaller>
+ <package>
+ <name>Util</name>
+ <channel>pear.horde.org</channel>
+ </package>
+ </required>
+ </dependencies>
+ <phprelease>
+ <filelist>
+ <install name="lib/Horde/Serialize.php" as="Horde/Serialize.php" />
+ </filelist>
+ </phprelease>
+ <changelog>
+ <release>
+ <date>2006-05-08</date>
+ <time>23:12:48</time>
+ <version>
+ <release>0.0.2</release>
+ <api>0.0.2</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>Converted to package.xml 2.0 for pear.horde.org</notes>
+ </release>
+ <release>
+ <version>
+ <release>0.0.1</release>
+ <api>0.0.1</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <date>2004-01-01</date>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>Initial packaging.
+ </notes>
+ </release>
+ </changelog>
+</package>
--- /dev/null
+--TEST--
+JSON associative arrays tests.
+--FILE--
+<?php
+
+error_reporting(E_ALL);
+require_once 'Horde/Serialize.php';
+
+function out($str)
+{
+ echo "$str\n";
+}
+
+$arr = array('car1'=> array('color'=> 'tan', 'model' => 'sedan'),
+ 'car2' => array('color' => 'red', 'model' => 'sports'));
+$arr_jo = '{"car1":{"color":"tan","model":"sedan"},"car2":{"color":"red","model":"sports"}}';
+
+$arn = array(0 => array(0 => 'tan\\', 'model\\' => 'sedan'), 1 => array(0 => 'red', 'model' => 'sports'));
+$arn_ja = '[{"0":"tan\\\\","model\\\\":"sedan"},{"0":"red","model":"sports"}]';
+
+$arrs = array(1 => 'one', 2 => 'two', 5 => 'five');
+$arrs_jo = '{"1":"one","2":"two","5":"five"}';
+
+/* Types test */
+
+// strict type should be array
+out(gettype(Horde_Serialize::unserialize($arn_ja, SERIALIZE_JSON)));
+
+echo"============================================================================\n";
+
+/* Encode tests */
+
+// array case - strict: associative array with nested associative arrays
+out(Horde_Serialize::serialize($arr, SERIALIZE_JSON));
+
+// array case - strict: associative array with nested associative arrays, and
+// some numeric keys thrown in
+// Should degrade to a numeric array.
+out(Horde_Serialize::serialize($arn, SERIALIZE_JSON));
+
+// sparse numeric assoc array: associative array numeric keys which are not
+// fully populated in a range of 0 to length-1
+// Test a sparsely populated numerically indexed associative array.
+out(Horde_Serialize::serialize($arrs, SERIALIZE_JSON));
+
+?>
+--EXPECT--
+array
+============================================================================
+{"car1":{"color":"tan","model":"sedan"},"car2":{"color":"red","model":"sports"}}
+[{"0":"tan\\","model\\":"sedan"},{"0":"red","model":"sports"}]
+{"1":"one","2":"two","5":"five"}
\ No newline at end of file
--- /dev/null
+--TEST--
+JSON empties tests.
+--FILE--
+<?php
+
+error_reporting(E_ALL);
+require_once 'Horde/Serialize.php';
+
+function out($str)
+{
+ echo "$str\n";
+}
+
+$obj0_j = '{}';
+$obj1_j = '{ }';
+$obj2_j = '{ /* comment inside */ }';
+
+/* Types tests */
+
+// should be object
+out(gettype(Horde_Serialize::unserialize($obj0_j, SERIALIZE_JSON)));
+// should be empty object
+out(count(get_object_vars(Horde_Serialize::unserialize($obj0_j, SERIALIZE_JSON))));
+
+// should be object, even with space
+out(gettype(Horde_Serialize::unserialize($obj1_j, SERIALIZE_JSON)));
+// should be empty object, even with space
+out(count(get_object_vars(Horde_Serialize::unserialize($obj1_j, SERIALIZE_JSON))));
+
+// should be object, despite comment
+out(gettype(Horde_Serialize::unserialize($obj2_j, SERIALIZE_JSON)));
+// should be empty object, despite comment
+out(count(get_object_vars(Horde_Serialize::unserialize($obj2_j, SERIALIZE_JSON))));
+
+?>
+--EXPECT--
+object
+0
+object
+0
+object
+0
--- /dev/null
+--TEST--
+JSON encode/decode tests.
+--FILE--
+<?php
+
+error_reporting(E_ALL);
+require_once 'Horde/Serialize.php';
+
+function out($str)
+{
+ echo "$str\n";
+}
+
+$obj = new stdClass();
+$obj->a_string = '"he":llo}:{world';
+$obj->an_array = array(1, 2, 3);
+$obj->obj = new stdClass();
+$obj->obj->a_number = 123;
+$obj_j = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}';
+
+$arr = array(null, true, array(1, 2, 3), "hello\"],[world!");
+$arr_j = '[null,true,[1,2,3],"hello\"],[world!"]';
+
+$str1 = 'hello world';
+$str1_j = '"hello world"';
+$str1_j_ = "'hello world'";
+
+$str2 = "hello\t\"world\"";
+$str2_j = '"hello\\t\\"world\\""';
+
+$str3 = "\\\r\n\t\"/";
+$str3_j = '"\\\\\\r\\n\\t\\"\\/"';
+
+$str4 = 'héllö wørłd';
+$str4_j = '"h\u00e9ll\u00f6 w\u00f8r\u0142d"';
+$str4_j_ = '"héllö wørłd"';
+
+/* Encode tests. */
+
+// type case: null
+out(Horde_Serialize::serialize(null, SERIALIZE_JSON));
+// type case: boolean true
+out(Horde_Serialize::serialize(true, SERIALIZE_JSON));
+// type case: boolean false
+out(Horde_Serialize::serialize(false, SERIALIZE_JSON));
+
+// numeric case: 1
+out(Horde_Serialize::serialize(1, SERIALIZE_JSON));
+// numeric case: -1
+out(Horde_Serialize::serialize(-1, SERIALIZE_JSON));
+// numeric case: 1.0
+out(Horde_Serialize::serialize(1.0, SERIALIZE_JSON));
+// numeric case: 1.1
+out(Horde_Serialize::serialize(1.1, SERIALIZE_JSON));
+
+// string case: hello world
+out(Horde_Serialize::serialize($str1, SERIALIZE_JSON));
+// string case: hello world, with tab, double-quotes
+out(Horde_Serialize::serialize($str2, SERIALIZE_JSON));
+// string case: backslash, return, newline, tab, double-quote
+out(Horde_Serialize::serialize($str3, SERIALIZE_JSON));
+// string case: hello world, with unicode
+out(Horde_Serialize::serialize($str4, SERIALIZE_JSON));
+
+// array case: array with elements and nested arrays
+out(Horde_Serialize::serialize($arr, SERIALIZE_JSON));
+// object case: object with properties, nested object and arrays
+out(Horde_Serialize::serialize($obj, SERIALIZE_JSON));
+
+echo"============================================================================\n";
+
+/* Decode tests */
+
+// type case: null
+var_dump(Horde_Serialize::unserialize('null', SERIALIZE_JSON));
+// type case: boolean true
+var_dump(Horde_Serialize::unserialize('true', SERIALIZE_JSON));
+// type case: boolean false
+var_dump(Horde_Serialize::unserialize('false', SERIALIZE_JSON));
+
+// numeric case: 1
+var_dump(Horde_Serialize::unserialize('1', SERIALIZE_JSON));
+// numeric case: -1
+var_dump(Horde_Serialize::unserialize('-1', SERIALIZE_JSON));
+// numeric case: 1.0
+var_dump(Horde_Serialize::unserialize('1.0', SERIALIZE_JSON));
+// numeric case: 1.1
+var_dump(Horde_Serialize::unserialize('1.1', SERIALIZE_JSON));
+
+// string case: hello world
+var_dump(Horde_Serialize::unserialize($str1_j, SERIALIZE_JSON));
+var_dump(Horde_Serialize::unserialize($str1_j_, SERIALIZE_JSON));
+// string case: hello world, with tab, double-quotes
+var_dump(Horde_Serialize::unserialize($str2_j, SERIALIZE_JSON));
+// string case: backslash, return, newline, tab, double-quote
+var_dump(Horde_Serialize::unserialize($str3_j, SERIALIZE_JSON));
+// string case: hello world, with unicode
+var_dump(Horde_Serialize::unserialize($str4_j, SERIALIZE_JSON));
+var_dump(Horde_Serialize::unserialize($str4_j_, SERIALIZE_JSON));
+
+// array case: array with elements and nested arrays
+var_dump(Horde_Serialize::unserialize($arr_j, SERIALIZE_JSON));
+// object case: object with properties, nested object and arrays
+var_dump(Horde_Serialize::unserialize($obj_j, SERIALIZE_JSON));
+
+echo"============================================================================\n";
+
+/* Encode-decode tests */
+
+// type case: null
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize(null, SERIALIZE_JSON), SERIALIZE_JSON));
+// type case: boolean true
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize(true, SERIALIZE_JSON), SERIALIZE_JSON));
+// type case: boolean false
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize(false, SERIALIZE_JSON), SERIALIZE_JSON));
+
+// numeric case: 1
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize(1, SERIALIZE_JSON), SERIALIZE_JSON));
+// numeric case: -1
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize(-1, SERIALIZE_JSON), SERIALIZE_JSON));
+// numeric case: 1.0
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize(1.0, SERIALIZE_JSON), SERIALIZE_JSON));
+// numeric case: 1.1
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize(1.1, SERIALIZE_JSON), SERIALIZE_JSON));
+
+// string case: hello world
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize($str1, SERIALIZE_JSON), SERIALIZE_JSON));
+// string case: hello world, with tab, double-quotes
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize($str2, SERIALIZE_JSON), SERIALIZE_JSON));
+// string case: backslash, return, newline, tab, double-quote
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize($str3, SERIALIZE_JSON), SERIALIZE_JSON));
+// string case: hello world, with unicode
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize($str4, SERIALIZE_JSON), SERIALIZE_JSON));
+
+// array case: array with elements and nested arrays
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize($arr, SERIALIZE_JSON), SERIALIZE_JSON));
+// object case: object with properties, nested object and arrays
+var_dump(Horde_Serialize::unserialize(Horde_Serialize::serialize($obj, SERIALIZE_JSON), SERIALIZE_JSON));
+
+echo"============================================================================\n";
+
+/* Decode-encode tests */
+
+// type case: null
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize('null', SERIALIZE_JSON), SERIALIZE_JSON));
+// type case: boolean true
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize('true', SERIALIZE_JSON), SERIALIZE_JSON));
+// type case: boolean false
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize('false', SERIALIZE_JSON), SERIALIZE_JSON));
+
+// numeric case: 1
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize('1', SERIALIZE_JSON), SERIALIZE_JSON));
+// numeric case: -1
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize('-1', SERIALIZE_JSON), SERIALIZE_JSON));
+// numeric case: 1.0
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize('1.0', SERIALIZE_JSON), SERIALIZE_JSON));
+// numeric case: 1.1
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize('1.1', SERIALIZE_JSON), SERIALIZE_JSON));
+
+// string case: hello world
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize($str1_j, SERIALIZE_JSON), SERIALIZE_JSON));
+// string case: hello world, with tab, double-quotes
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize($str2_j, SERIALIZE_JSON), SERIALIZE_JSON));
+// string case: backslash, return, newline, tab, double-quote
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize($str3_j, SERIALIZE_JSON), SERIALIZE_JSON));
+// string case: hello world, with unicode
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize($str4_j, SERIALIZE_JSON), SERIALIZE_JSON));
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize($str4_j_, SERIALIZE_JSON), SERIALIZE_JSON));
+
+// array case: array with elements and nested arrays
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize($arr_j, SERIALIZE_JSON), SERIALIZE_JSON));
+// object case: object with properties, nested object and arrays
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize($obj_j, SERIALIZE_JSON), SERIALIZE_JSON));
+
+?>
+--EXPECT--
+null
+true
+false
+1
+-1
+1
+1.1
+"hello world"
+"hello\t\"world\""
+"\\\r\n\t\"\/"
+"h\u00e9ll\u00f6 w\u00f8r\u0142d"
+[null,true,[1,2,3],"hello\"],[world!"]
+{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}
+============================================================================
+NULL
+bool(true)
+bool(false)
+int(1)
+int(-1)
+float(1)
+float(1.1)
+string(11) "hello world"
+string(11) "hello world"
+string(13) "hello "world""
+string(6) "\
+ "/"
+string(15) "héllö wørłd"
+string(15) "héllö wørłd"
+array(4) {
+ [0]=>
+ NULL
+ [1]=>
+ bool(true)
+ [2]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ [3]=>
+ string(15) "hello"],[world!"
+}
+object(stdClass)(3) {
+ ["a_string"]=>
+ string(16) ""he":llo}:{world"
+ ["an_array"]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["obj"]=>
+ object(stdClass)(1) {
+ ["a_number"]=>
+ int(123)
+ }
+}
+============================================================================
+NULL
+bool(true)
+bool(false)
+int(1)
+int(-1)
+int(1)
+float(1.1)
+string(11) "hello world"
+string(13) "hello "world""
+string(6) "\
+ "/"
+string(15) "héllö wørłd"
+array(4) {
+ [0]=>
+ NULL
+ [1]=>
+ bool(true)
+ [2]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ [3]=>
+ string(15) "hello"],[world!"
+}
+object(stdClass)(3) {
+ ["a_string"]=>
+ string(16) ""he":llo}:{world"
+ ["an_array"]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["obj"]=>
+ object(stdClass)(1) {
+ ["a_number"]=>
+ int(123)
+ }
+}
+============================================================================
+null
+true
+false
+1
+-1
+1
+1.1
+"hello world"
+"hello\t\"world\""
+"\\\r\n\t\"\/"
+"h\u00e9ll\u00f6 w\u00f8r\u0142d"
+"h\u00e9ll\u00f6 w\u00f8r\u0142d"
+[null,true,[1,2,3],"hello\"],[world!"]
+{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}
--- /dev/null
+--TEST--
+JSON nested arrays tests.
+--FILE--
+<?php
+
+error_reporting(E_ALL);
+require_once 'Horde/Serialize.php';
+
+$str1 = '[{"this":"that"}]';
+$str2 = '{"this":["that"]}';
+$str3 = '{"params":[{"foo":["1"],"bar":"1"}]}';
+$str4 = '{"0": {"foo": "bar", "baz": "winkle"}}';
+$str5 = '{"params":[{"options": {"old": [ ], "new": {"0": {"elements": {"old": [], "new": {"0": {"elementName": "aa", "isDefault": false, "elementRank": "0", "priceAdjust": "0", "partNumber": ""}}}, "optionName": "aa", "isRequired": false, "optionDesc": ""}}}}]}';
+
+/* Decode tests */
+
+// simple compactly-nested array
+var_dump(Horde_Serialize::unserialize($str1, SERIALIZE_JSON));
+// simple compactly-nested array
+var_dump(Horde_Serialize::unserialize($str2, SERIALIZE_JSON));
+// complex compactly nested array
+var_dump(Horde_Serialize::unserialize($str3, SERIALIZE_JSON));
+// complex compactly nested array
+var_dump(Horde_Serialize::unserialize($str4, SERIALIZE_JSON));
+// super complex compactly nested array
+var_dump(Horde_Serialize::unserialize($str5, SERIALIZE_JSON));
+
+?>
+--EXPECT--
+array(1) {
+ [0]=>
+ object(stdClass)(1) {
+ ["this"]=>
+ string(4) "that"
+ }
+}
+object(stdClass)(1) {
+ ["this"]=>
+ array(1) {
+ [0]=>
+ string(4) "that"
+ }
+}
+object(stdClass)(1) {
+ ["params"]=>
+ array(1) {
+ [0]=>
+ object(stdClass)(2) {
+ ["foo"]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+ ["bar"]=>
+ string(1) "1"
+ }
+ }
+}
+object(stdClass)(1) {
+ [0]=>
+ object(stdClass)(2) {
+ ["foo"]=>
+ string(3) "bar"
+ ["baz"]=>
+ string(6) "winkle"
+ }
+}
+object(stdClass)(1) {
+ ["params"]=>
+ array(1) {
+ [0]=>
+ object(stdClass)(1) {
+ ["options"]=>
+ object(stdClass)(2) {
+ ["old"]=>
+ array(0) {
+ }
+ ["new"]=>
+ object(stdClass)(1) {
+ [0]=>
+ object(stdClass)(4) {
+ ["elements"]=>
+ object(stdClass)(2) {
+ ["old"]=>
+ array(0) {
+ }
+ ["new"]=>
+ object(stdClass)(1) {
+ [0]=>
+ object(stdClass)(5) {
+ ["elementName"]=>
+ string(2) "aa"
+ ["isDefault"]=>
+ bool(false)
+ ["elementRank"]=>
+ string(1) "0"
+ ["priceAdjust"]=>
+ string(1) "0"
+ ["partNumber"]=>
+ string(0) ""
+ }
+ }
+ }
+ ["optionName"]=>
+ string(2) "aa"
+ ["isRequired"]=>
+ bool(false)
+ ["optionDesc"]=>
+ string(0) ""
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+--TEST--
+JSON objects tests.
+--FILE--
+<?php
+
+error_reporting(E_ALL);
+require_once 'Horde/Serialize.php';
+
+function out($str)
+{
+ echo "$str\n";
+}
+
+$obj_j = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}';
+
+$obj1->car1->color = 'tan';
+$obj1->car1->model = 'sedan';
+$obj1->car2->color = 'red';
+$obj1->car2->model = 'sports';
+$obj1_j = '{"car1":{"color":"tan","model":"sedan"},"car2":{"color":"red","model":"sports"}}';
+
+/* Types test */
+
+// checking whether decoded type is object
+out(gettype(Horde_Serialize::unserialize($obj_j, SERIALIZE_JSON)));
+
+/* Encode test */
+
+// object - strict: Object with nested objects
+out(Horde_Serialize::serialize($obj1, SERIALIZE_JSON));
+
+/* Decode/encode test */
+
+// object case
+out(Horde_Serialize::serialize(Horde_Serialize::unserialize($obj_j, SERIALIZE_JSON), SERIALIZE_JSON));
+
+?>
+--EXPECT--
+object
+{"car1":{"color":"tan","model":"sedan"},"car2":{"color":"red","model":"sports"}}
+{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}
--- /dev/null
+--TEST--
+JSON spaces and comments tests.
+--FILE--
+<?php
+
+error_reporting(E_ALL);
+require_once 'Horde/Serialize.php';
+
+$obj_j = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}';
+
+$obj_js = '{"a_string": "\"he\":llo}:{world",
+ "an_array":[1, 2, 3],
+ "obj": {"a_number":123}}';
+
+$obj_jc1 = '{"a_string": "\"he\":llo}:{world",
+ // here is a comment, hoorah
+ "an_array":[1, 2, 3],
+ "obj": {"a_number":123}}';
+
+$obj_jc2 = '/* this here is the sneetch */ "the sneetch"
+ // this has been the sneetch.';
+
+$obj_jc3 = '{"a_string": "\"he\":llo}:{world",
+ /* here is a comment, hoorah */
+ "an_array":[1, 2, 3 /* and here is another */],
+ "obj": {"a_number":123}}';
+
+$obj_jc4 = '{\'a_string\': "\"he\":llo}:{world",
+ /* here is a comment, hoorah */
+ \'an_array\':[1, 2, 3 /* and here is another */],
+ "obj": {"a_number":123}}';
+
+// Base result
+var_dump(Horde_Serialize::unserialize($obj_j, SERIALIZE_JSON));
+
+/* Spaces tests */
+
+// checking whether notation with spaces works
+var_dump(Horde_Serialize::unserialize($obj_js, SERIALIZE_JSON));
+
+/* Comments tests */
+
+// checking whether notation with single line comments works
+var_dump(Horde_Serialize::unserialize($obj_jc1, SERIALIZE_JSON));
+
+// checking whether notation with multiline comments works
+var_dump(Horde_Serialize::unserialize($obj_jc2, SERIALIZE_JSON));
+var_dump(Horde_Serialize::unserialize($obj_jc3, SERIALIZE_JSON));
+
+// checking whether notation with single-quotes and multiline comments works
+var_dump(Horde_Serialize::unserialize($obj_jc4, SERIALIZE_JSON));
+
+?>
+--EXPECT--
+object(stdClass)(3) {
+ ["a_string"]=>
+ string(16) ""he":llo}:{world"
+ ["an_array"]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["obj"]=>
+ object(stdClass)(1) {
+ ["a_number"]=>
+ int(123)
+ }
+}
+object(stdClass)(3) {
+ ["a_string"]=>
+ string(16) ""he":llo}:{world"
+ ["an_array"]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["obj"]=>
+ object(stdClass)(1) {
+ ["a_number"]=>
+ int(123)
+ }
+}
+object(stdClass)(3) {
+ ["a_string"]=>
+ string(16) ""he":llo}:{world"
+ ["an_array"]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["obj"]=>
+ object(stdClass)(1) {
+ ["a_number"]=>
+ int(123)
+ }
+}
+string(11) "the sneetch"
+object(stdClass)(3) {
+ ["a_string"]=>
+ string(16) ""he":llo}:{world"
+ ["an_array"]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["obj"]=>
+ object(stdClass)(1) {
+ ["a_number"]=>
+ int(123)
+ }
+}
+object(stdClass)(3) {
+ ["a_string"]=>
+ string(16) ""he":llo}:{world"
+ ["an_array"]=>
+ array(3) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+ [2]=>
+ int(3)
+ }
+ ["obj"]=>
+ object(stdClass)(1) {
+ ["a_number"]=>
+ int(123)
+ }
+}
--- /dev/null
+--TEST--
+JSON unquoted keys tests.
+--FILE--
+<?php
+
+error_reporting(E_ALL);
+require_once 'Horde/Serialize.php';
+
+$ob1->{'0'} = 'tan';
+$ob1->model = 'sedan';
+$ob2->{'0'} = 'red';
+$ob2->model = 'sports';
+$arn = array($ob1, $ob2);
+$arn_ja = '[{0:"tan","model":"sedan"},{"0":"red",model:"sports"}]';
+
+$arrs->{'1'} = 'one';
+$arrs->{'2'} = 'two';
+$arrs->{'5'} = 'fi"ve';
+$arrs_jo = '{"1":"one",2:"two","5":\'fi"ve\'}';
+
+/* Decode tests */
+
+// array case - strict: associative array with unquoted keys, nested
+// associative arrays, and some numeric keys thrown in
+// ...unless the input array has some numeric indeces, in which case the
+// behavior is to degrade to a regular array
+var_dump(Horde_Serialize::unserialize($arn_ja, SERIALIZE_JSON));
+
+// sparse numeric assoc array: associative array with unquoted keys,
+// single-quoted values, numeric keys which are not fully populated in a range
+// of 0 to length-1
+// Test a sparsely populated numerically indexed associative array
+var_dump(Horde_Serialize::unserialize($arrs_jo, SERIALIZE_JSON));
+
+?>
+--EXPECT--
+array(2) {
+ [0]=>
+ object(stdClass)(2) {
+ [0]=>
+ string(3) "tan"
+ ["model"]=>
+ string(5) "sedan"
+ }
+ [1]=>
+ object(stdClass)(2) {
+ [0]=>
+ string(3) "red"
+ ["model"]=>
+ string(6) "sports"
+ }
+}
+object(stdClass)(3) {
+ [1]=>
+ string(3) "one"
+ [2]=>
+ string(3) "two"
+ [5]=>
+ string(5) "fi"ve"
+}