// {{{ HTML_AJAX_Serialize_PHP /** * PHP serializer * * This class can be used to serialize and unserialize data in a * format compatible with PHP's native serialization functions. * * @version 0.0.3 * @copyright 2005 Arpad Ray * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * * See Main.js for Author/license details */ function HTML_AJAX_Serialize_PHP() {} HTML_AJAX_Serialize_PHP.prototype = { error: false, message: "", cont: "", defaultEncoding: 'UTF-8', contentType: 'application/php-serialized; charset: UTF-8', // {{{ serialize /** * Serializes a variable * * @param mixed inp the variable to serialize * @return string a string representation of the input, * which can be reconstructed by unserialize() * @author Arpad Ray * @author David Coallier */ serialize: function(inp) { var type = HTML_AJAX_Util.getType(inp); var val; switch (type) { case "undefined": val = "N"; break; case "boolean": val = "b:" + (inp ? "1" : "0"); break; case "number": val = (Math.round(inp) == inp ? "i" : "d") + ":" + inp; break; case "string": val = "s:" + inp.length + ":\"" + inp + "\""; break; case "array": val = "a"; case "object": if (type == "object") { var objname = inp.constructor.toString().match(/(\w+)\(\)/); if (objname == undefined) { return; } objname[1] = this.serialize(objname[1]); val = "O" + objname[1].substring(1, objname[1].length - 1); } var count = 0; var vals = ""; var okey; for (key in inp) { okey = (key.match(/^[0-9]+$/) ? parseInt(key) : key); vals += this.serialize(okey) + this.serialize(inp[key]); count++; } val += ":" + count + ":{" + vals + "}"; break; } if (type != "object" && type != "array") val += ";"; return val; }, // }}} // {{{ unserialize /** * Reconstructs a serialized variable * * @param string inp the string to reconstruct * @return mixed the variable represented by the input string, or void on failure */ unserialize: function(inp) { this.error = 0; if (inp == "" || inp.length < 2) { this.raiseError("input is too short"); return; } var val, kret, vret, cval; var type = inp.charAt(0); var cont = inp.substring(2); var size = 0, divpos = 0, endcont = 0, rest = "", next = ""; switch (type) { case "N": // null if (inp.charAt(1) != ";") { this.raiseError("missing ; for null", cont); } // leave val undefined rest = cont; break; case "b": // boolean if (!/[01];/.test(cont.substring(0,2))) { this.raiseError("value not 0 or 1, or missing ; for boolean", cont); } val = (cont.charAt(0) == "1"); rest = cont.substring(1); break; case "s": // string val = ""; divpos = cont.indexOf(":"); if (divpos == -1) { this.raiseError("missing : for string", cont); break; } size = parseInt(cont.substring(0, divpos)); if (size == 0) { if (cont.length - divpos < 4) { this.raiseError("string is too short", cont); break; } rest = cont.substring(divpos + 4); break; } if ((cont.length - divpos - size) < 4) { this.raiseError("string is too short", cont); break; } if (cont.substring(divpos + 2 + size, divpos + 4 + size) != "\";") { this.raiseError("string is too long, or missing \";", cont); } val = cont.substring(divpos + 2, divpos + 2 + size); rest = cont.substring(divpos + 4 + size); break; case "i": // integer case "d": // float var dotfound = 0; for (var i = 0; i < cont.length; i++) { cval = cont.charAt(i); if (isNaN(parseInt(cval)) && !(type == "d" && cval == "." && !dotfound++)) { endcont = i; break; } } if (!endcont || cont.charAt(endcont) != ";") { this.raiseError("missing or invalid value, or missing ; for int/float", cont); } val = cont.substring(0, endcont); val = (type == "i" ? parseInt(val) : parseFloat(val)); rest = cont.substring(endcont + 1); break; case "a": // array if (cont.length < 4) { this.raiseError("array is too short", cont); return; } divpos = cont.indexOf(":", 1); if (divpos == -1) { this.raiseError("missing : for array", cont); return; } size = parseInt(cont.substring(0, divpos)); cont = cont.substring(divpos + 2); val = new Array(); if (cont.length < 1) { this.raiseError("array is too short", cont); return; } for (var i = 0; i < size; i++) { kret = this.unserialize(cont, 1); if (this.error || kret[0] == undefined || kret[1] == "") { this.raiseError("missing or invalid key, or missing value for array", cont); return; } vret = this.unserialize(kret[1], 1); if (this.error) { this.raiseError("invalid value for array", cont); return; } val[kret[0]] = vret[0]; cont = vret[1]; } if (cont.charAt(0) != "}") { this.raiseError("missing ending }, or too many values for array", cont); return; } rest = cont.substring(1); break; case "O": // object divpos = cont.indexOf(":"); if (divpos == -1) { this.raiseError("missing : for object", cont); return; } size = parseInt(cont.substring(0, divpos)); var objname = cont.substring(divpos + 2, divpos + 2 + size); if (cont.substring(divpos + 2 + size, divpos + 4 + size) != "\":") { this.raiseError("object name is too long, or missing \":", cont); return; } var objprops = this.unserialize("a:" + cont.substring(divpos + 4 + size), 1); if (this.error) { this.raiseError("invalid object properties", cont); return; } rest = objprops[1]; var objout = "function " + objname + "(){"; for (key in objprops[0]) { objout += "this." + key + "=objprops[0]['" + key + "'];"; } objout += "}val=new " + objname + "();"; eval(objout); break; default: this.raiseError("invalid input type", cont); } return (arguments.length == 1 ? val : [val, rest]); }, // }}} // {{{ getError /** * Gets the last error message * * @return string the last error message from unserialize() */ getError: function() { return this.message + "\n" + this.cont; }, // }}} // {{{ raiseError /** * Raises an eror (called by unserialize().) * * @param string message the error message * @param string cont the remaining unserialized content */ raiseError: function(message, cont) { this.error = 1; this.message = message; this.cont = cont; } // }}} } // }}}