The first time serialized PHP data cost me an afternoon, it was a WP Adminify support ticket. A user's dashboard widget settings had gone haywire, and the "settings" they were describing lived in the wp_options table as a single serialized string that looked like line noise: a:4:{s:8:"_builtin";b:1;.... I could not read it, I could not tell at a glance what was wrong, and I did not want to spin up a full PHP environment just to print_r one row. That afternoon is why I care about having a decoder that is one browser tab away.
If you work in WordPress, WooCommerce, Laravel, or any legacy PHP codebase, you have met serialized data whether you wanted to or not. It shows up in options tables, session files, cache stores, and post meta. And when something breaks, being able to read it fast is the difference between a five-minute fix and an afternoon.
This guide covers what the serialized format actually is, how to decode it with the Unserialize tool on toolz.dev, and — importantly — the one real limitation you need to know about before you trust the output on non-English data.
TL;DR: PHP
serialize()packs values into a typed string likea:2:{s:4:"name";s:5:"Alice";...}where each piece carries its type and length. The Unserialize tool parses that in your browser and shows it as a tree,print_r,var_dump, or JSON — no PHP server, no data upload. Big caveat I verified myself: it counts string length in UTF-16 code units, not bytes, so serialized data containing accents, emoji, or CJK characters can mis-parse or fail. For ASCII data it is reliable. It reads data; it does not resolve object references or let you edit in place.
What is PHP serialization, really?
Serialization turns a PHP value — an array, object, string, integer, whatever — into a flat string you can store in a database column or a file and later rebuild with unserialize(). Two functions do the work: serialize() converts a value to the string, and unserialize() converts it back.
What makes the format readable once you know the code is that every value announces its type and size. Here is the whole vocabulary:
s:5:"hello" // string: s:length:"value"
i:42 // integer: i:value
d:3.14 // double: d:value
b:1 // boolean true (b:0 is false)
N; // null
a:2:{...} // array: a:count:{key;value;...}
O:8:"ClassName":1:{...} // object: O:namelen:"Class":propcount:{...}
So a serialized associative array looks like this:
a:3:{s:4:"name";s:10:"John Smith";s:5:"email";s:16:"[email protected]";s:4:"role";s:5:"admin";}
Which is just this PHP array, packed tight:
array(
'name' => 'John Smith',
'email' => '[email protected]',
'role' => 'admin'
)
Compact for the machine, close to unreadable for a human at 2pm on a support call. That is the whole problem the tool solves.
How does the toolz.dev Unserialize tool decode it?
You paste the string, and it parses the format directly in JavaScript in your browser and renders the result. I tested each of these against the tool's own parser while writing this, so the behavior below is what it actually does, not what a manual assumes.
Sequential integer-keyed arrays come back as a real list. a:2:{i:0;s:5:"apple";i:1;s:6:"banana";} decodes to ["apple", "banana"]. Associative arrays come back as keyed objects. Nested structures nest correctly, arrays inside arrays inside objects, all the way down.
Objects keep their class name. O:4:"User":2:{s:4:"name";s:3:"Bob";...} decodes with a __class__ marker of "User" plus its properties, so you can see both the type and the data. It even handles the awkward case of private and protected properties, which PHP serializes with null-byte prefixes around the class name — the tool strips those and shows you the clean property name.
You get eight output formats to switch between: Tree View, print_r, var_dump, var_export, Krumo, FirePHP, dBug, and plain JSON. I live in Tree View for exploring and JSON for copying into something else, but if your muscle memory expects var_dump output, it is right there.
The one limitation you need to know: multibyte strings
This is the part I would want someone to tell me before I trusted a decoder on production data, so here it is up front.
PHP's serialized format measures string length in bytes. The tool measures it in JavaScript string length, which counts UTF-16 code units. For plain ASCII those are the same number, so English data decodes perfectly. The moment a string contains a multibyte UTF-8 character, they diverge.
Take the word "café." In UTF-8 the "é" is two bytes, so PHP serializes it as s:5:"café" — length five, counting bytes. The tool reads that 5 and grabs five code units from the string, which is café" — it swallows the closing quote and loses its place. I ran exactly this: a standalone s:5:"café"; decodes to the wrong value, and inside an array like a:2:{s:1:"a";s:5:"café";s:1:"b";i:1;} it fails outright with Unknown type ':' at position 25.
The practical takeaway: if you are debugging WordPress options that are pure ASCII — most plugin settings, slugs, boolean flags — you are fine. If the serialized data contains accented names, emoji, or CJK text, the decode may corrupt or error, and that is a real bug in the tool, not your data. (For the record, the fix on our end is to parse by UTF-8 byte length rather than .length; it is on my list.) When you hit it, WP-CLI's serialization-aware commands on the server are the reliable fallback.
There is a related, gentler caveat: the var_dump output reports string lengths using that same code-unit count, so var_dump("café") shows string(4) where real PHP would say string(5), and an emoji shows a length that will not match PHP's byte count either. Read those numbers as "JavaScript length," not "PHP byte length."
Why would you need to unserialize data outside PHP?
Plenty of reasons, and almost none of them are "for fun."
Debugging is the big one. A bug report says the user's settings are wrong; the settings are a serialized blob in the database; you cannot see the problem until you decode it. The workflow I use is: SELECT option_value FROM wp_options WHERE option_name = 'widget_text';, copy the result, paste it into the Unserialize tool, and read the tree. Ten seconds versus writing a throwaway PHP script.
Migrations are the sneaky one. Serialized strings embed their own lengths, so a naive find-and-replace on a database dump — say, swapping an old domain for a new one — changes the string content without updating the length prefix, and every affected value becomes un-unserializable. Decoding first shows you exactly which values carry the domain so you know what a plain search-and-replace will break. (The correct tool for the replace itself is WP-CLI's search-replace, which understands serialization.)
Then there is cache and session inspection — Redis, Memcached, and file caches in PHP apps often hold serialized values — and security review, where you need to see what is actually stored before you can judge whether it is safe.
Is decoding serialized data in the browser safe?
Safer than doing it in PHP, and worth understanding why.
PHP's native unserialize() has a long security history. Fed a crafted string, it can instantiate arbitrary objects and trigger their magic methods (__wakeup, __destruct), which under the right conditions becomes an object-injection attack and, at worst, remote code execution. That is why the standing advice is to never call unserialize() on untrusted input, and to pass ['allowed_classes' => false] when you must.
The browser tool sidesteps all of that because it never runs PHP. It reads the string format and displays the structure — no PHP objects are created, no magic methods fire, and there is no interpreter to exploit. The data also stays on your device; it is parsed locally and never sent to a server, which matters when the serialized blob is a session or something else you would rather not upload. So for inspecting untrusted serialized data, the browser is genuinely the safer place.
Native PHP unserialize() |
toolz.dev browser tool | |
|---|---|---|
| Instantiates objects | Yes (injection risk) | No — reads structure only |
| Runs on a server | Yes | No — local in browser |
| Safe on untrusted input | Only with allowed_classes |
Yes, it never executes |
| Handles multibyte lengths | Correctly (bytes) | Not reliably (code units) |
| Resolves object references | Yes | No — shows [Reference] |
| Purpose | Reconstruct live values | Inspect and read |
That table is also an honest summary of the tradeoff: the browser tool is the safe reader, not a drop-in replacement for the language function.
What are the common real-world sources?
If you are here, it is probably one of these. WordPress leans on serialization heavily in wp_options — widget_text, sidebars_widgets, theme_mods_*, the active plugins list, cron schedules. WooCommerce stores product variations, attributes, and custom fields as serialized post meta, which is why a product with wrong pricing so often traces back to a serialized value. Laravel uses serialization for file cache and session storage. Magento's configuration system is full of it. Same format everywhere; same decoding approach.
A couple of things the tool does not do
Two honest boundaries. It does not resolve references — PHP can serialize a pointer to an earlier value (r: or R:), and the tool shows those as a literal [Reference] marker rather than following them. And it is a reader, not an editor: there is no "change this value and re-serialize" mode. To modify serialized data, decode it, make your change in PHP or in JSON, and re-serialize on the PHP side. If you must hand-edit the raw string, remember you have to fix the length prefixes too, and — per the section above — count bytes, not characters.
Frequently Asked Questions
What is PHP serialization used for?
It converts complex values like arrays and objects into a single string that can live in a database column, a file, or a cache, and be rebuilt later. WordPress, WooCommerce, Laravel, and Magento all use it heavily for settings, session data, and cached values.
Can I unserialize PHP data without a PHP server?
Yes. The Unserialize tool parses serialized PHP in JavaScript in your browser. No PHP install, no server, no account.
Is it safe to decode serialized data in the browser?
Yes, and it is safer than PHP's own unserialize() on untrusted input, because the tool only reads the string structure. It never instantiates PHP objects, so the magic-method attacks that make native unserialize() dangerous simply cannot happen.
Why does my serialized string fail to decode?
The usual causes are a truncated copy (you missed the trailing braces or the first character), a broken length prefix after a find-and-replace, or data that is not actually PHP serialized. One more that catches people: if the string contains accented characters, emoji, or CJK text, the tool's code-unit length counting can mis-parse it, because PHP counts string length in bytes and the tool counts UTF-16 units.
Can I decode WordPress wp_options values with it?
Yes — that is one of the most common uses. Query the option_value, paste it in, and read the structure. Just be aware that if the option holds multibyte text, you may need WP-CLI on the server instead.
Can I edit serialized data with this tool?
No, it is a reader. To change a value, decode it, edit in PHP or JSON, and re-serialize on the PHP side. Hand-editing the raw string means fixing the byte-length prefixes yourself, which is error-prone.
What is the difference between PHP serialization and JSON?
Serialization preserves PHP-specific types, including object class names and private properties. JSON is language-agnostic and only knows strings, numbers, booleans, null, arrays, and objects. New code generally prefers JSON because json_decode() does not instantiate objects, so it avoids the injection risk, and JSON is readable everywhere. You can move a decoded structure into the JSON Formatter to work with it that way.
Does the tool handle serialized objects, not just arrays?
Yes. Objects decode with their class name preserved alongside the properties, and private or protected properties (which PHP serializes with null-byte prefixes) are cleaned up to readable names in the output.
Conclusion
Serialized PHP data is unavoidable if you touch WordPress, WooCommerce, or Laravel, and being able to read it on demand turns a category of frustrating bugs into quick ones. The Unserialize tool does that in a browser tab, safely, without a PHP server — as long as you know its one real edge: multibyte strings can trip the length counting, and ASCII data is where it shines. Paste, read, fix. And when the data is full of accents or emoji, reach for WP-CLI instead.
Related Tools:

