J'ai une table avec un chargement de rangées de tableaux sérialisés que je prévois de demander et de le transmettre à JavaScript
.
Le problème est - est-il possible de unserialize
avec JavaScript plutôt que PHP?
Sinon, je devrai charger toutes les lignes, les boucler, les désérialiser et les attribuer à un tableau temporaire PHP, puis le retourner au code JavaScript qui semble très inefficace si je peux envoyer les données encore sérialisées JavaScript peut désérialiser les données en cas de besoin.
Existe-t-il une fonction Javascript intégrée qui le fait ou devrai-je boucler les lignes dans PHP avant de l'encoder?
Notez que je n'utilise pas jQuery.
EDIT: Exemple de mes données sérialisées dans PHP de ma table:
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;}}
envelopper json_encode
autour de unserialize
echo json_encode( unserialize( $array));
Php.js a des implémentations javascript desserialize et serialize:
http://phpjs.org/functions/unserialize/
http://phpjs.org/functions/serialize/
Cela dit, il est probablement plus efficace de convertir en JSON côté serveur. JSON.parse va être beaucoup plus rapide que la désérialisation de PHP.js.
http://php.net/manual/en/book.json.php
Je viens juste de remarquer ton commentaire, alors on y va:
en PHP
json_encode(unserialize(SerializedVal));
en JavaScript:
JSON.parse(JsonString);
Je pensais pouvoir écrire une fonction JS capable de désérialiser les données sérialisées PHP.
Mais avant de choisir cette solution, veuillez noter que:
serialize
de PHP est spécifique à PHP. La meilleure option consiste donc à utiliser la variable unserialize
de PHP afin de garantir à 100% qu'elle fonctionne correctement.Map
dans JS, mais ceux-ci permettent de stocker les clés 13 et "13" séparément, ce que PHP ne permet pas. Et nous ne touchons que la pointe de l'iceberg ici ...json_encode
pour cela, et JavaScript a JSON.parse
pour le décoder. C'est certainement la voie à suivre si vous le pouvez.Si, avec ces remarques, vous voyez toujours la nécessité d’une fonction d’annulation de la numérotation JS, lisez la suite.
Voici une implémentation JS qui fournit un objet PHP
avec des méthodes similaires à celles de l'objet JSON
intégré: parse
et stringify
.
Lorsqu'une entrée de la méthode parse
fait référence à une classe, elle vérifie d'abord si vous avez passé une référence à cette classe dans le deuxième argument (facultatif). Sinon, une maquette sera créée pour cette classe (afin d'éviter des effets secondaires indésirables). Dans les deux cas, une instance de cette classe sera créée. Si la chaîne d'entrée spécifie qu'un custom serialization s'est produit, la méthode unserialize
sur l'instance de cet objet sera appelée. Vous devez fournir la logique dans cette méthode car la chaîne elle-même ne donne pas d'informations sur la procédure à suivre. Il est seulement connu dans le code PHP que généré cette chaîne.
Cette implémentation prend également en charge les références cycliques. Lorsqu'un tableau associatif s'avère être un tableau séquentiel, un tableau JS est renvoyé.
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 } ));