Escape JSON in PHP — json_encode Options Explained
- json_encode escapes forward slashes by default — use JSON_UNESCAPED_SLASHES to stop it.
- It also escapes non-ASCII characters — use JSON_UNESCAPED_UNICODE to keep UTF-8 raw.
- Combined flags give you clean, compact JSON that matches what JavaScript and Python produce.
Table of Contents
PHP's json_encode has the most surprising default behavior of any major JSON library. It escapes forward slashes (which JSON doesn't require) and non-ASCII characters (which JSON allows raw). The output is still valid JSON, but it's noisier than what JavaScript, Python, or Java produce for the same input. A one-flag fix makes PHP's output match everything else.
What PHP Does By Default
Compare the same data serialized by PHP vs Node:
// PHP
echo json_encode(["url" => "https://example.com/path", "name" => "café"]);
// {"url":"https:\/\/example.com\/path","name":"caf\u00e9"}
// Node
JSON.stringify({url: "https://example.com/path", name: "café"})
// {"url":"https://example.com/path","name":"café"}
Two differences: PHP escapes forward slashes as \/, and escapes non-ASCII as \u sequences. Both are valid JSON. Both parse back to the same data. But for log readability, byte-for-byte cross-language comparison, or just not confusing your future self — you usually want the unescaped form.
Fixing the Defaults With Flags
The two flags you almost always want:
json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
Now PHP produces the same output as Node:
{"url":"https://example.com/path","name":"café"}
Other useful flags:
JSON_PRETTY_PRINT— indented output for human readingJSON_THROW_ON_ERROR— throws an exception instead of returning false on failure (PHP 7.3+)JSON_PRESERVE_ZERO_FRACTION— keeps 1.0 as 1.0 instead of 1JSON_UNESCAPED_LINE_TERMINATORS— leaves U+2028 and U+2029 raw
A sensible default encode call for most modern PHP:
json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);Sell Custom Apparel — We Handle Printing & Free Shipping
Why Does PHP Escape Forward Slashes By Default?
The historical reason: HTML embedding safety. If JSON containing </script> is embedded inside an HTML script tag without slash escaping, the browser sees the literal </script> and closes the script tag, breaking the page.
Escaping the slash as \/ prevents this — the browser sees a regular text character, and your JSON stays intact inside the script tag.
In modern web apps this is handled at the rendering layer (Blade, Twig, React, Vue all escape output automatically). You no longer need PHP's slash escaping for safety, which is why the flag to turn it off is the norm.
For APIs where PHP serializes JSON to a Content-Type: application/json response, there's no HTML context and no safety benefit. Turn it off.
json_decode Handles Unescaping Correctly
The reverse direction is json_decode:
$json = '{"url":"https:\/\/example.com"}';
$data = json_decode($json, true);
echo $data['url'];
// https://example.com
The true second argument returns associative arrays instead of objects — usually what you want in modern PHP. Without it, you get stdClass objects.
Error handling: json_decode returns null on failure. Check with json_last_error(), or better, use JSON_THROW_ON_ERROR on PHP 7.3+:
try {
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
// Handle parse error
}
Escaping a Single String For Inclusion in JSON
For cases where you're building JSON by hand (usually a bad idea — let json_encode do the work) and need to escape a single string value:
$escaped = json_encode($inputString); // Returns: "value with \"quotes\" escaped"
This returns the quoted, escaped string literal. Use it directly inside a larger JSON string if you're building one:
$json = '{"msg":' . json_encode($userMessage) . '}';
Better: build the structure as an array and json_encode the whole thing:
$json = json_encode(['msg' => $userMessage]);
The second approach is safer, shorter, and correct by construction. String concatenation of JSON is a category of bugs; let the library handle the boundaries.
Escape JSON Outside PHP
For log debugging and cross-language JSON. Browser-based, no PHP runtime.
Open Free JSON Escape / Unescape ToolFrequently Asked Questions
Why does PHP escape my URLs as https:\/\/?
Historical HTML-embedding safety default. Pass JSON_UNESCAPED_SLASHES to json_encode to stop it.
How do I keep UTF-8 characters raw in PHP JSON output?
Pass JSON_UNESCAPED_UNICODE. Combine with JSON_UNESCAPED_SLASHES for Node-compatible output.
Should I use json_encode or manual string building?
Always json_encode. Manual building is a source of bugs and security issues. Build an array; serialize the array.
Why does json_decode return null sometimes?
Invalid JSON. Check json_last_error() for the specific reason, or use JSON_THROW_ON_ERROR for exceptions.

