用Javascript反序列化PHP数组
Unserialize PHP Array in Javascript
我有一个表,其中包含一系列序列化数组,我计划请求并将其传递给JavaScript
。
问题是-是可能的unserialize
与JavaScript而不是PHP ?
否则,我将不得不加载所有行,循环它们并将它们反序列化,并将它们分配给一个临时PHP数组,然后json_encode它返回到JavaScript,这似乎是非常低效的,如果我可以发送数据仍然序列化,以便JavaScript可以在需要时反序列化数据。
是否有一个内置的Javascript函数,这样做,或者我必须在PHP中循环行之前,我编码它?
注意我没有使用jQuery。
编辑:PHP中序列化数据的例子:
a:8:{i:0;a:2:{i:0;i:10;i:1;i:11;}i:1;a:2:{i:0;i:9;i:1;i:11;}i:2;a:2:
{i:0;i:8;i:1;i:11;}i:3;a:2:{i:0;i:8;i:1;i:10;}i:4;a:2:{i:0;i:8;i:1;i:9;}i:5;a:2:
{i:0;i:8;i:1;i:8;}i:6;a:2:{i:0;i:8;i:1;i:7;}i:7;a:2:{i:0;i:8;i:1;i:6;}}
Php.js有unserialize和serialize的javascript实现:
http://phpjs.org/functions/unserialize/http://phpjs.org/functions/serialize/也就是说,在服务器端转换为JSON可能更有效。JSON。parse会比PHP.js的unserialize快很多
我想我应该试着写一个JS函数来反序列化php序列化的数据。
但在使用此解决方案之前,请注意:
- 由PHP的
serialize
函数产生的格式是PHP特定的,所以最好的选择是使用PHP的unserialize
有100%的保证,它正在做正确的工作。 PHP可以在这些字符串中存储类信息,甚至可以在一些自定义序列化方法的输出中存储类信息。所以要反序列化这样的字符串,你需要知道那些类和方法。PHP数据结构与JavaScript数据结构并不一一对应:PHP关联数组可以将字符串作为键,因此它们看起来更像JavaScript对象,而不是JS数组,但在PHP中键保持插入顺序,键可以具有真正的数字数据类型,这在JS对象中是不可能的。有人可能会说,我们应该看看JS中的
Map
对象,但这些对象允许将13和"13"作为单独的键存储,这是PHP不允许的。而我们在这里只触及了冰山一角……PHP序列化对象的受保护和私有属性,这不仅很奇怪(私有是怎么回事?),而且是JS中不存在的概念,或者至少不是以同样的方式存在的。如果有人想在JS中实现(硬)私有属性,那么一些反序列化如何能够设置这样的私有属性呢?JSON是一种不特定于PHP的替代方案,也不关心自定义类。如果您可以访问序列化发生的PHP源代码,那么将其更改为生成JSON。PHP提供json_encode
, JavaScript有JSON.parse
来解码它。如果可以的话,这当然是你要走的路。如果你仍然认为需要JS的反序列化函数,那么继续往下读。
这是一个JS实现,提供了一个PHP
对象,其方法与内置的JSON
对象相似:parse
和stringify
。
当parse
方法的输入引用一个类时,它将首先检查您是否在(可选的)第二个参数中传递了对该类的引用。如果没有,将为该类创建一个mock(以避免不希望出现的副作用)。在任何一种情况下,都将创建该类的实例。如果输入字符串指定了自定义序列化,则将调用该对象实例上的unserialize
方法。你必须在那个方法中提供逻辑,因为字符串本身并没有给出应该如何做的信息。只有在PHP代码中知道生成这个字符串。
这个实现也支持循环引用。当关联数组被证明是顺序数组时,将返回一个JS数组。
const PHP = {
stdClass: function() {},
stringify(val) {
const hash = new Map([[Infinity, "d:INF;"], [-Infinity, "d:-INF;"], [NaN, "d:NAN;"], [null, "N;"], [undefined, "N;"]]);
const utf8length = str => str ? encodeURI(str).match(/(%.)?./g).length : 0;
const serializeString = (s,delim='"') => `${utf8length(s)}:${delim[0]}${s}${delim[delim.length-1]}`;
let ref = 0;
function serialize(val, canReference = true) {
if (hash.has(val)) return hash.get(val);
ref += canReference;
if (typeof val === "string") return `s:${serializeString(val)};`;
if (typeof val === "number") return `${Math.round(val) === val ? "i" : "d"}:${(""+val).toUpperCase().replace(/(-?'d)E/, "$1.0E")};`;
if (typeof val === "boolean") return `b:${+val};`;
const a = Array.isArray(val) || val.constructor === Object;
hash.set(val, `${"rR"[+a]}:${ref};`);
if (typeof val.serialize === "function") {
return `C:${serializeString(val.constructor.name)}:${serializeString(val.serialize(), "{}")}`;
}
const vals = Object.entries(val).filter(([k, v]) => typeof v !== "function");
return (a ? "a" : `O:${serializeString(val.constructor.name)}`)
+ `:${vals.length}:{${vals.map(([k, v]) => serialize(a && /^'d{1,16}$/.test(k) ? +k : k, false) + serialize(v)).join("")}}`;
}
return serialize(val);
},
// Provide in second argument the classes that may be instantiated
// e.g. { MyClass1, MyClass2 }
parse(str, allowedClasses = {}) {
allowedClasses.stdClass = PHP.stdClass; // Always allowed.
let offset = 0;
const values = [null];
const specialNums = { "INF": Infinity, "-INF": -Infinity, "NAN": NaN };
const kick = (msg, i = offset) => { throw new Error(`Error at ${i}: ${msg}'n${str}'n${" ".repeat(i)}^`) }
const read = (expected, ret) => expected === str.slice(offset, offset+=expected.length) ? ret
: kick(`Expected '${expected}'`, offset-expected.length);
function readMatch(regex, msg, terminator=";") {
read(":");
const match = regex.exec(str.slice(offset));
if (!match) kick(`Exected ${msg}, but got '${str.slice(offset).match(/^[:;{}]|[^:;{}]*/)[0]}'`);
offset += match[0].length;
return read(terminator, match[0]);
}
function readUtf8chars(numUtf8Bytes, terminator="") {
const i = offset;
while (numUtf8Bytes > 0) {
const code = str.charCodeAt(offset++);
numUtf8Bytes -= code < 0x80 ? 1 : code < 0x800 || code>>11 === 0x1B ? 2 : 3;
}
return numUtf8Bytes ? kick("Invalid string length", i-2) : read(terminator, str.slice(i, offset));
}
const create = className => !className ? {}
: allowedClasses[className] ? Object.create(allowedClasses[className].prototype)
: new {[className]: function() {} }[className]; // Create a mock class for this name
const readBoolean = () => readMatch(/^[01]/, "a '0' or '1'", ";");
const readInt = () => +readMatch(/^-?'d+/, "an integer", ";");
const readUInt = terminator => +readMatch(/^'d+/, "an unsigned integer", terminator);
const readString = (terminator="") => readUtf8chars(readUInt(':"'), '"'+terminator);
function readDecimal() {
const num = readMatch(/^-?('d+('.'d+)?(E[+-]'d+)?|INF)|NAN/, "a decimal number", ";");
return num in specialNums ? specialNums[num] : +num;
}
function readKey() {
const typ = str[offset++];
return typ === "s" ? readString(";")
: typ === "i" ? readUInt(";")
: kick("Expected 's' or 'i' as type for a key, but got ${str[offset-1]}", offset-1);
}
function readObject(obj) {
for (let i = 0, length = readUInt(":{"); i < length; i++) obj[readKey()] = readValue();
return read("}", obj);
}
function readArray() {
const obj = readObject({});
return Object.keys(obj).some((key, i) => key != i) ? obj : Object.values(obj);
}
function readCustomObject(obj) {
if (typeof obj.unserialize !== "function") kick(`Instance of ${obj.constructor.name} does not have an "unserialize" method`);
obj.unserialize(readUtf8chars(readUInt(":{")));
return read("}", obj);
}
function readValue() {
const typ = str[offset++].toLowerCase();
const ref = values.push(null)-1;
const val = typ === "n" ? read(";", null)
: typ === "s" ? readString(";")
: typ === "b" ? readBoolean()
: typ === "i" ? readInt()
: typ === "d" ? readDecimal()
: typ === "a" ? readArray() // Associative array
: typ === "o" ? readObject(create(readString())) // Object
: typ === "c" ? readCustomObject(create(readString())) // Custom serialized object
: typ === "r" ? values[readInt()] // Backreference
: kick(`Unexpected type ${typ}`, offset-1);
if (typ !== "r") values[ref] = val;
return val;
}
const val = readValue();
if (offset !== str.length) kick("Unexpected trailing character");
return val;
}
}
/**************** EXAMPLE USES ************************/
// Unserialize a sequential array
console.log(PHP.parse('a:4:{i:0;s:4:"This";i:1;s:2:"is";i:2;s:2:"an";i:3;s:5:"array";}'));
// Unserialize an associative array into an object
console.log(PHP.parse('a:2:{s:8:"language";s:3:"PHP";s:7:"version";d:7.1;}'));
// Example with class that has custom serialize function:
var MyClass = (function () {
const priv = new WeakMap(); // This is a way to implement private properties in ES6
return class MyClass {
constructor() {
priv.set(this, "");
this.wordCount = 0;
}
unserialize(serialised) {
const words = PHP.parse(serialised);
priv.set(this, words);
this.wordCount = words.split(" ").length;
}
serialize() {
return PHP.stringify(priv.get(this));
}
}
})();
// Unserialise a PHP string that needs the above class to work, and will call its unserialize method
// The class needs to be passed as object key/value as second argument, so to allow this side effect to happen:
console.log(PHP.parse('C:7:"MyClass":23:{s:15:"My private data";}', { MyClass } ));
将json_encode
包裹在unserialize
上
echo json_encode( unserialize( $array));
http://php.net/manual/en/book.json.php
刚刚注意到你的评论,所以我们开始:
在PHP中json_encode(unserialize(SerializedVal));
在JavaScript: JSON.parse(JsonString);
- 将数组从PHP传递到Javascript
- MongoDB (php) - 以数组而不是多个属性的形式返回文档属性
- 如何使用Javascript将空数组发送到PHP服务器
- 调用php数组中的JS函数
- PHP中的数组输出
- 将带有多维数组的表单从Javascript提交到PHP
- 将数组从javascript格式化为php的更好方法,反之亦然
- 将PHP变量分配给PHP数组
- php数组转换为javascript
- 如何用javascript打印php数组
- 将PHP数组传递给js变量
- 如何在php中读取没有任何键的JSON数组
- 从javascript访问属性多端数组PHP
- 替换辅助数组 PHP 中的值
- JavaScript发送变量,但插入数组PHP不能正常工作
- 在数组php中中断数组
- 如何通过javascript数组php laravel4
- 多维json编码关联数组php到JS
- (删除重复)重新索引多维数组PHP jquery
- 我可以't在jQuery中获取数组PHP编码