PHP Serialized Data Decoder
Decode PHP serialized data into a local typed tree with byte offsets, reference checks, and binary-safe display without object instantiation.{{ summaryTitle }}
{{ summaryLine }}
{{ summaryAnnouncement }}
{{ computation.values.artifact_text }}
The chart renderer is unavailable. The canonical signals remain available in the inspection ledger.
| Signal | Value | Interpretation | Copy |
|---|---|---|---|
| {{ row.label }} | {{ row.display }} | {{ row.detail }} |
PHP serialization turns a value into a byte stream that keeps type and structure. It appears in legacy caches, session records, stored options, queue payloads, and diagnostic exports. Reading that stream can reveal the original arrays, objects, scalar values, and references, but a damaged length or delimiter can make everything after it appear invalid.
This format is not ordinary text. A string record declares a byte count, so one visible character may occupy several bytes and a binary string may contain null bytes that a text editor hides. Object records can also carry class names and property names whose embedded null bytes distinguish public, protected, and private visibility.
- A type marker selects the record shape for a null, Boolean, integer, float, string, array, object, enum, or reference.
- A declared length or count controls how many bytes, entries, or properties belong to the record. String lengths count bytes, not displayed characters.
- A reference identifier links back to an earlier value or object in the same stream and has no meaning outside that serialized value.
- Object metadata names a class and its properties, but viewing the record is not the same as safely restoring the object in PHP.
Inspection and restoration are different jobs. PHP warns against passing untrusted data to unserialize() because restoring objects can load classes and invoke object hooks. An inert structural decode is useful for investigation, but it does not authenticate the source, prove that an application will accept it, or make an altered payload safe to run.
Treat the decoded structure as evidence. Keep the original bytes, note where they came from, and avoid editing length-prefixed records by sight unless every changed byte count is recalculated.
How to Use This Tool:
Choose the input representation that matches the bytes you actually have, then use the tree and byte offsets to inspect the record without restoring PHP objects.
- Paste one complete value into Serialized value, browse for a local text or binary file, or load the sample. The source must contain exactly one serialized value.
- Set Input format to UTF-8 text for ordinary pasted text. Choose Hex byte escapes when binary bytes are written as sequences such as
\x00or\xFF. - Choose how Binary strings should appear. The automatic setting keeps printable UTF-8 as text and uses base64 for other byte sequences; the other settings force byte escapes or base64 throughout.
- Set Object property names to reveal public, protected, and private visibility, or keep raw mangled names when the exact stored bytes matter.
- Review the Decoded PHP tree first. If parsing stops, use the reported byte offset to inspect the marker, delimiter, declared byte length, or container count at that position.
Interpreting Results:
The root type and node count describe the parsed structure, while maximum depth, reference count, and object count help reveal unexpectedly complex payloads. Byte offsets use the interpreted byte stream, so offsets can differ from visible character positions when UTF-8 characters occupy more than one byte.
Successful parsing means the supported grammar, declared lengths, counts, references, and final boundary were internally consistent. It does not prove that the bytes are trusted, that a particular PHP class exists, or that application-level validation will pass.
Legacy custom-object records preserve their payload bytes but leave them uninterpreted. A warning on that record is a boundary, not a partial restoration result.
Technical Details:
PHP's serialized representation is a prefix grammar. A marker selects a record shape, delimiters separate its fields, and length or count fields determine how many bytes or child records belong to it. Parsing must therefore move in byte order rather than split the source on punctuation.
Transformation Core:
| Stage | Transformation | Important Boundary |
|---|---|---|
| Interpret input | UTF-8 text becomes bytes, or valid \xHH sequences become their byte values while other text is encoded as UTF-8. |
The chosen representation must match the source or declared lengths will not line up. |
| Read records | Each marker is parsed with its required delimiters, byte lengths, item counts, and child records. | String payloads are consumed by declared byte length, even when they contain quotes or null bytes. |
| Resolve structure | Arrays become ordered key-value entries, object properties gain visibility metadata, and references must point backward to eligible earlier values. | No class is loaded and no object hook or custom payload code is executed. |
| Format output | Binary strings follow the chosen display policy and every node receives start and end byte offsets. | The display form may be UTF-8, byte escapes, or base64 while the declared source length remains a byte count. |
Rule Core:
| Marker | Meaning | Rule Applied |
|---|---|---|
N | Null | Must be followed by a semicolon. |
b, i, d | Boolean, integer, float | Boolean accepts only 0 or 1; numeric token text must match its grammar. |
s | String | The decimal length is the exact number of payload bytes before the closing quote. |
a | Array | Each declared item contains one integer or string key followed by one value. |
O | Object | The class name and property count are checked; properties are inspected without instantiation. |
C | Legacy custom object | The declared payload bytes are preserved but deliberately not interpreted. |
E | Enum case | The identifier must contain a non-empty Class:Case pair. |
R, r | Value or object reference | The positive reference identifier must point to an eligible earlier record. |
The uppercase S escaped-string marker is rejected because its use is deprecated in PHP 8.4. After the root record closes, any remaining bytes are reported rather than silently ignored.
| Limit | Maximum | Purpose |
|---|---|---|
| Visible source | 262,144 characters | Bounds pasted text before byte interpretation. |
| Interpreted source | 262,144 bytes | Bounds the actual stream being parsed. |
| Nesting | 64 levels | Stops excessively deep arrays and objects. |
| Declared container items | 10,000 | Bounds the combined array entries and object properties. |
| Parsed nodes | 20,000 | Bounds total structural work. |
| Decoded tree text | 1,000,000 characters | Prevents an oversized rendered artifact. |
For example, a:2:{s:4:"name";s:3:"Ada";s:6:"active";b:1;} becomes one array with two string keys, one string value, and one Boolean value. The declared lengths 4, 3, and 6 are checked against the exact payload bytes before the closing quotes.
Safety and Privacy Notes:
The source is processed in the current browser tab and is not added to the page URL. Decoding does not call PHP, restore objects, autoload classes, invoke object hooks, execute custom payloads, or make network requests with the source.
- Do not treat a structurally valid decode as permission to run the same bytes through
unserialize(). - Keep secrets out of screenshots, copied trees, and downloaded reports; serialized values often contain session data, tokens, or private properties.
- Preserve the original byte stream when the result may be used for debugging, incident response, or evidence.
References:
- serialize, PHP Manual.
- unserialize, PHP Manual.