smarty-php / smarty-php/smarty
Default behavior of `json_encode` is inappropriate for HTML/XML documents
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 2.3k
- Forks
- 709
- PR merge metrics
- No merged PRs in 30d
Description
Background
There is a good write-up about using PHP to generate JSON that is embedded within an HTML document:
https://sirre.al/2025/08/06/safe-json-in-script-tags-how-not-to-break-a-site/
TLDR: json_encode() has lots of crazy-looking flags. These flags would be silly if you were focused on pure JSON. But PHP applications (and Smarty applications) are often used for HTML/XML documents with embedded bits of JSON. This context requires a slightly different flavor of JSON. ("Flavor of JSON" => it's valid/well-formed JSON with quirky choices.)
(This issue is inspired by @colemanw's filing on https://lab.civicrm.org/dev/core/-/issues/6080.)
Discussion
I think the important thing is this:
- It is typical to use Smarty to generate HTML/XML.
- If you generate an HTML document with user-supplied content processed by Smarty's
json_encodemodifier, then (by default) you will probably a problem. - I think the blog makes a persuasive case that the JSON flags are not a matter of local taste. It's a matter of output's document-format:
- If you are outputting an HTML document (as in a typical web-app), then you want one set of JSON flags (e.g.
JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS). - If you are outputting a pure JSON document (as when
composer.phargeneratescomposer.json), then you want another set of JSON flags (e.g.JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT).
- If you are outputting an HTML document (as in a typical web-app), then you want one set of JSON flags (e.g.
- There's an asymmetry:
- If you incorrectly have a pure JSON document generated with the flags for HTML-JSON, then the output is quirky but valid.
- If you incorrectly have an HTML document generated with the flags for pure-JSON, then the output is unsafe.
This is similar to #1011, in that both issues seek a default behavior for json_encode(). It differs in that #1011 talks about default character-set (Smarty::$_CHARSET), and this talks about neutralizing risky strings for HTML ("<!--" vs "\u003C!--").
This can also be related to #1048 -- e.g. if one can override json_encode, then it's possible to change the default JSON rules, and solve the issue for one app. However, outputting HTML is a normal thing for Smarty -- you shouldn't have to do anything complicated to produce well-formed markup.
I don't know the best way to indicate the appropriate codec, but you could imagine things like....
Smarty::$_JSON_FLAGS = JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS
// and then `json_encode` consults this property
// or...
$smarty->setJsonDefaults(JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS);
// and then `json_encode` consults this setting
// or...
$smarty->setOutputFormat('text/html');
// and then `json_encode` consults this setting
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing Smarty's json_encode modifier documentation and the discussion of #1011 and #1048. Compare the proposed JSON flag sets for HTML/XML and pure JSON output, then define and test a concrete default or configuration behavior for safely embedding user-supplied JSON in HTML.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- security, web-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100