39 lines
1.7 KiB
TypeScript
39 lines
1.7 KiB
TypeScript
/* ---------- PHP serialize 反序列化(字节精确,覆盖 s/i/d/b/a/N) ---------- */
|
||
export function phpUnserialize(input: string): unknown {
|
||
const buf = Buffer.from(input, "utf8");
|
||
let i = 0;
|
||
function parse(): unknown {
|
||
const type = String.fromCharCode(buf[i]);
|
||
const colon = buf.indexOf(0x3a, i + 2); // 跳过 "类型:" 后定位计数值结束的冒号
|
||
if (type === "N") { i += 2; return null; } // N;
|
||
if (type === "b") { const v = buf[i + 2] === 0x31; i += 4; return v; } // b:0; / b:1;
|
||
if (type === "i") { const j = buf.indexOf(0x3b, i); const v = parseInt(buf.toString("utf8", i + 2, j)); i = j + 1; return v; } // i:123;
|
||
if (type === "d") { const j = buf.indexOf(0x3b, i); const v = parseFloat(buf.toString("utf8", i + 2, j)); i = j + 1; return v; } // d:1.5;
|
||
if (type === "s") { // s:LEN:"...";(LEN 为 UTF-8 字节数)
|
||
const len = parseInt(buf.toString("utf8", i + 2, colon));
|
||
const start = colon + 2;
|
||
const v = buf.toString("utf8", start, start + len);
|
||
i = start + len + 2;
|
||
return v;
|
||
}
|
||
if (type === "a") { // a:COUNT:{ key;value; ... }
|
||
const n = parseInt(buf.toString("utf8", i + 2, colon));
|
||
i = colon + 2; // 跳过 '{'
|
||
const arr: unknown[] = [];
|
||
const obj: Record<string, unknown> = {};
|
||
let isArr = true;
|
||
for (let k = 0; k < n; k++) {
|
||
const key = parse();
|
||
const val = parse();
|
||
if (typeof key === "number") { isArr = isArr && true; arr[key] = val; }
|
||
else { isArr = false; obj[String(key)] = val; }
|
||
}
|
||
i += 1; // 消费 '}'
|
||
return isArr ? arr : obj;
|
||
}
|
||
throw new Error(`phpUnserialize: unknown type '${type}' at byte ${i}`);
|
||
}
|
||
return parse();
|
||
}
|
||
|