Skip to content

Commit fb18d8e

Browse files
committed
First draft
1 parent 4552daf commit fb18d8e

File tree

3 files changed

+265
-1
lines changed

3 files changed

+265
-1
lines changed

README.md

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,59 @@
11
js-php-unserialize
22
==================
33

4-
JavaScript tool to unserialize data taken from PHP. It can parse "serialize()" output, or even serialized sessions data.
4+
JavaScript tool to unserialize data taken from PHP. It can parse "serialize()" output, or even serialized sessions data.
5+
6+
Credits
7+
-------
8+
9+
* The PHP unserializer is taken from [kvz](https://github.com/kvz)'s [phpjs](https://github.com/kvz/phpjs) project.
10+
* The session unserializer's idea is taken from [dumpling](https://raw.github.com/st-luke/dumpling/), which is highly limited by its lack of a real unserializer, and has lot of crash cases.
11+
12+
Installation
13+
------------
14+
15+
### Node.js
16+
17+
Install from npm :
18+
19+
```sh
20+
npm install php-unserialize
21+
```
22+
23+
The use it the usual way :
24+
25+
```javascript
26+
var PHPUnserialize = require('php-unserialize');
27+
28+
console.log(PHPUnserialize.unserialize('a:0:{}')); // []
29+
```
30+
31+
### Browser
32+
33+
[Download tarball from github](https://github.com/naholyr/js-php-unserialize/downloads) and then unarchive this where you want, then you can simply include it in your page :
34+
35+
```html
36+
<script src="/path/to/php-unserialize.js"></script>
37+
<script>
38+
console.log(PHPUnserialize.unserialize('a:0:{}')); // []
39+
</script>
40+
```
41+
42+
**Compatibility issues**
43+
44+
This library has been tested server-side only. For example it uses `[].reduce`, so it may not work on some browsers. Do not hesitate to make pull requests to fix it for you favorite browsers :)
45+
46+
Usage
47+
-----
48+
49+
The module exposes two methods:
50+
51+
### `unserialize(string)`
52+
53+
Unserialize output taken from PHP's `serialize()` method.
54+
55+
It currently does not suport objects.
56+
57+
### `unserializeSession(string)`
58+
59+
Unserialize PHP serialized session. PHP uses a weird custom format to serialize session data, something like "`$key1$serializedData1|$key2$serializedData2|…`", this methods will parse this and unserialize chunks so you can have a simple anonymous objects.

package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"author": "Nicolas Chambrier <naholyr@gmail.com> (http://naholyr.fr)",
3+
"name": "php-unserialize",
4+
"description": "tool to unserialize data taken from PHP. It can parse \"serialize()\" output, or even serialized sessions data.",
5+
"version": "0.0.1",
6+
"repository": {
7+
"type": "git",
8+
"url": "git://github.com/naholyr/js-php-unserialize.git"
9+
},
10+
"main": "php-unserialize.js",
11+
"dependencies": {},
12+
"devDependencies": {},
13+
"optionalDependencies": {},
14+
"engines": {
15+
"node": "*"
16+
}
17+
}

php-unserialize.js

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
2+
module.exports = {
3+
unserialize: unserialize,
4+
unserializeSession: unserializeSession
5+
};
6+
7+
8+
// Taken from https://github.com/kvz/phpjs/blob/master/functions/var/unserialize.js
9+
// Fixed window reference to make it nodejs-compatible
10+
function unserialize (data) {
11+
// http://kevin.vanzonneveld.net
12+
// + original by: Arpad Ray (mailto:arpad@php.net)
13+
// + improved by: Pedro Tainha (http://www.pedrotainha.com)
14+
// + bugfixed by: dptr1988
15+
// + revised by: d3x
16+
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
17+
// + input by: Brett Zamir (http://brett-zamir.me)
18+
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
19+
// + improved by: Chris
20+
// + improved by: James
21+
// + input by: Martin (http://www.erlenwiese.de/)
22+
// + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
23+
// + improved by: Le Torbi
24+
// + input by: kilops
25+
// + bugfixed by: Brett Zamir (http://brett-zamir.me)
26+
// + input by: Jaroslaw Czarniak
27+
// % note: We feel the main purpose of this function should be to ease the transport of data between php & js
28+
// % note: Aiming for PHP-compatibility, we have to translate objects to arrays
29+
// * example 1: unserialize('a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}');
30+
// * returns 1: ['Kevin', 'van', 'Zonneveld']
31+
// * example 2: unserialize('a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}');
32+
// * returns 2: {firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'}
33+
if (!this.window) this.window = this;
34+
var that = this,
35+
utf8Overhead = function (chr) {
36+
// http://phpjs.org/functions/unserialize:571#comment_95906
37+
var code = chr.charCodeAt(0);
38+
if (code < 0x0080) {
39+
return 0;
40+
}
41+
if (code < 0x0800) {
42+
return 1;
43+
}
44+
return 2;
45+
},
46+
error = function (type, msg, filename, line) {
47+
throw new that.window[type](msg, filename, line);
48+
},
49+
read_until = function (data, offset, stopchr) {
50+
var i = 2, buf = [], chr = data.slice(offset, offset + 1);
51+
52+
while (chr != stopchr) {
53+
if ((i + offset) > data.length) {
54+
error('Error', 'Invalid');
55+
}
56+
buf.push(chr);
57+
chr = data.slice(offset + (i - 1), offset + i);
58+
i += 1;
59+
}
60+
return [buf.length, buf.join('')];
61+
},
62+
read_chrs = function (data, offset, length) {
63+
var i, chr, buf;
64+
65+
buf = [];
66+
for (i = 0; i < length; i++) {
67+
chr = data.slice(offset + (i - 1), offset + i);
68+
buf.push(chr);
69+
length -= utf8Overhead(chr);
70+
}
71+
return [buf.length, buf.join('')];
72+
},
73+
_unserialize = function (data, offset) {
74+
var dtype, dataoffset, keyandchrs, keys,
75+
readdata, readData, ccount, stringlength,
76+
i, key, kprops, kchrs, vprops, vchrs, value,
77+
chrs = 0,
78+
typeconvert = function (x) {
79+
return x;
80+
};
81+
82+
if (!offset) {
83+
offset = 0;
84+
}
85+
dtype = (data.slice(offset, offset + 1)).toLowerCase();
86+
87+
dataoffset = offset + 2;
88+
89+
switch (dtype) {
90+
case 'i':
91+
typeconvert = function (x) {
92+
return parseInt(x, 10);
93+
};
94+
readData = read_until(data, dataoffset, ';');
95+
chrs = readData[0];
96+
readdata = readData[1];
97+
dataoffset += chrs + 1;
98+
break;
99+
case 'b':
100+
typeconvert = function (x) {
101+
return parseInt(x, 10) !== 0;
102+
};
103+
readData = read_until(data, dataoffset, ';');
104+
chrs = readData[0];
105+
readdata = readData[1];
106+
dataoffset += chrs + 1;
107+
break;
108+
case 'd':
109+
typeconvert = function (x) {
110+
return parseFloat(x);
111+
};
112+
readData = read_until(data, dataoffset, ';');
113+
chrs = readData[0];
114+
readdata = readData[1];
115+
dataoffset += chrs + 1;
116+
break;
117+
case 'n':
118+
readdata = null;
119+
break;
120+
case 's':
121+
ccount = read_until(data, dataoffset, ':');
122+
chrs = ccount[0];
123+
stringlength = ccount[1];
124+
dataoffset += chrs + 2;
125+
126+
readData = read_chrs(data, dataoffset + 1, parseInt(stringlength, 10));
127+
chrs = readData[0];
128+
readdata = readData[1];
129+
dataoffset += chrs + 2;
130+
if (chrs != parseInt(stringlength, 10) && chrs != readdata.length) {
131+
error('SyntaxError', 'String length mismatch');
132+
}
133+
break;
134+
case 'a':
135+
readdata = {};
136+
137+
keyandchrs = read_until(data, dataoffset, ':');
138+
chrs = keyandchrs[0];
139+
keys = keyandchrs[1];
140+
dataoffset += chrs + 2;
141+
142+
for (i = 0; i < parseInt(keys, 10); i++) {
143+
kprops = _unserialize(data, dataoffset);
144+
kchrs = kprops[1];
145+
key = kprops[2];
146+
dataoffset += kchrs;
147+
148+
vprops = _unserialize(data, dataoffset);
149+
vchrs = vprops[1];
150+
value = vprops[2];
151+
dataoffset += vchrs;
152+
153+
readdata[key] = value;
154+
}
155+
156+
dataoffset += 1;
157+
break;
158+
default:
159+
error('SyntaxError', 'Unknown / Unhandled data type(s): ' + dtype);
160+
break;
161+
}
162+
return [dtype, dataoffset - offset, typeconvert(readdata)];
163+
}
164+
;
165+
166+
return _unserialize((data + ''), 0)[2];
167+
}
168+
169+
function unserializeSession (input) {
170+
return input.split(/\|/).reduce(function (output, part, index, parts) {
171+
// First part = $key
172+
if (index === 0) {
173+
output._currKey = part;
174+
}
175+
// Last part = $someSerializedStuff
176+
else if (index === parts.length - 1) {
177+
output[output._currKey] = unserialize(part);
178+
delete output._currKey;
179+
}
180+
// Other output = $someSerializedStuff$key
181+
else {
182+
var match = part.match(/^((?:.*?[;\}])+)([^;\}]+?)$/);
183+
if (match) {
184+
output[output._currKey] = unserialize(match[1]);
185+
output._currKey = match[2];
186+
} else {
187+
throw new Error('Parse error on part "' + part + '"');
188+
}
189+
}
190+
return output;
191+
}, {});
192+
}

0 commit comments

Comments
 (0)