Javascript -> PHP Serializer for Prototype
5
This is the final version of my Javascript serializer targetted at PHP.
The point:
Notes:
Javascript sample of use:
var myObject = {
name:'value',
test:['Array','of','strings'],
bool:false,
timestamp: new Date(),
float: 3.1415926539,
number: 42,
func: function () {
alert('Member functions are always omitted from serialization');
}
}
alert(Object.toPHP(myObject));
Output:
Sample of subsequent unserialization in PHP (passed via POST as 'myobject')
$myObject=unserialize(stripslashes($_POST['myobject']));
var_dump($myObject);
Output:
The point:
Objects are most easily passed over the network as serialized strings. Between serialization and unserialization, serialization is by far the easier of the two. Since object passing can sometimes be a process-hungry thing, we want to do things as quickly as possible.
My solution is to always do the hard part in compiled code, while doing the easy part in script. That is, whichever way you're passing an Object, you want to pass it in a natively decoded format for the target.
Since I work mostly in PHP, this meant writing a module that would be able to generate a string that can be decoded with PHP's unserialize() function into a PHP Associative Array (or other applicable type).
Notes:
This lib REQUIRES the Prototype lib. You can hack prototype out of it, of course (by replacing the references to Object.extend() with explicit assignments), but I can't imagine why you'd want to bother; it's used mostly with Ajax.Request anyway.
Previous versions of this code would add the .toPHP() member to the Object prototype. After trying to enumerate things, I found that this is a REALLY bad thing to do, as toPHP springs up where it's not wanted in ALL objects. As a result, I've opted to go the Prototype route and apply it as a member of the Object object.
Please note that if you pass a serialized string to PHP via GET or POST, you'll need to stripslashes() before unserialization.
Javascript sample of use:
var myObject = {
name:'value',
test:['Array','of','strings'],
bool:false,
timestamp: new Date(),
float: 3.1415926539,
number: 42,
func: function () {
alert('Member functions are always omitted from serialization');
}
}
alert(Object.toPHP(myObject));
Output:
a:7:{s:4:"name";s:5:"value";s:4:"test";a:3:{i:0;s:5:"Array";i:1;s:2:"of";i:2;s:7:"strings";}s:4:"bool";b:0;s:9:"timestamp";i:1190897619824;s:5:"float";d:3.1415926539;s:6:"number";i:42;s:4:"func";null}
Sample of subsequent unserialization in PHP (passed via POST as 'myobject')
$myObject=unserialize(stripslashes($_POST['myobject']));
var_dump($myObject);
Output:
array(7) {
["name"]=>
string(5) "value"
["test"]=>
array(3) {
[0]=>
string(5) "Array"
[1]=>
string(2) "of"
[2]=>
string(7) "strings"
}
["bool"]=>
bool(false)
["timestamp"]=>
int(1192296601)
["float"]=>
float(3.1415926539)
["number"]=>
int(42)
["func"]=>
NULL
}
Object.extend(Object,{
toPHP: function(object) {
var type = typeof object;
switch (type) {
case 'undefined':
case 'function':
case 'unknown': return 'N;';
case 'boolean': return 'b:'+(object?'1':'0')+';';
}
if (object === null) return 'N;';
if (object.toPHP) return object.toPHP();
if (Object.isElement(object)) return null;
var ret = [];
for (var property in object) {
var value = Object.toPHP(object[property]);
if (value !== undefined)
ret.push(property.toString().toPHP() + value);
}
return 'a:'+ret.length+':{'+ ret.join('')+'}';
}
});
Date.prototype.toPHP = function() {
return 'i:'+this.getTime()+';';
};
Object.extend(String.prototype,{
toPHP: function () {
var s=this.escapeUTF();
return 's:'+s.length+':"'+s+'";';
},
escapeUTF: function () {
var charCode,ret = '';
for (i=0; i<this.length; i++) {
charCode = this.charCodeAt(i);
ret+=((charCode <= 127) && (charCode >=32))?
this.charAt(i):
('&#x' + charCode.toString(16).toUpperCase() + ';');
}
return ret;
}
});
Array.prototype.toPHP = function () {
var ret=[];
this.each(function (v,i) {
ret.push(i.toPHP()+(!!v.toPHP?v.toPHP():Object.toPHP(v)));
});
return 'a:'+ret.length+':{'+ret.join('')+'}';
}
Number.prototype.toPHP = function () {
return (parseInt(this)==parseFloat(this)?'i':'d')+':'+this.toString()+';';
}






Object.extend=
(typeof Object.extend == function')?
Object.extend:
function(src,dst) {
for (var i in dst) src[i]=dst[i];
};
I've got good news, and I've got bad news:
The universe is merely a figment of my imagination.
Now are you ready for the bad news?