Interoperability between languages has been a problem since such thing is possible. In web technologies is pretty complicated as making the things wrong may make your web app unavailable, for example if you send a string variable from PHP to JavaScript without escaping it correctly, your JavaScript may throw an exception and your app won't work.
Twig, the template engine is not the exception for this feature and if you print unsafe content into JavaScript, your app may not work neither. For example, consider the following snippet:
{% set username = "sdkcarlos" %}
{# Note the multiline string ! #}
{% set userdescription = " Hello,
This is my description
" %}
<script>
var userName = "{{- username -}}";
var description = "{{- userdescription-}}";
</script>
The previous Twig snippet will print the following HTML:
<script>
var userName = "sdkcarlos";
var description = " Hello,
This is my description
";
</script>
This code will throw on every sane Browser the following js exception: Uncaught SyntaxError: Invalid or unexpected token.
Printing safely a Twig value inside a JavaScript string
Fortunately, Twig makes the things pretty easy for everyone. By Default it doesn't escape content into JS format as it isn't needed everywhere, that's why you need to indicate this behaviour using the escape
filter in js mode. The escape filter escapes a string for safe insertion into the final output. It supports different escaping strategies depending on the template context. The e
filter is just an alias to make it shorter, so you may use the one you want as it is the same:
{% set username = "sdkcarlos" %}
{# Note the multiline string ! #}
{% set userdescription = " Hello,
This is my description
" %}
<script>
var userName = "{{- username|escape("js") -}}";
var description = "{{- userdescription|escape("js") -}}";
{# Or using e for a shorter syntax #}
var userName = "{{- username|e("js") -}}";
var description = "{{- userdescription|e("js") -}}"
</script>
Now every variable printed with this filter will be safe to print inside a JavaScript string and you won't need to be worried about if your app will fail cause of unsafe user content. The previous snippet would print:
<script>
var userName = "sdkcarlos";
var description = "\x20Hello,\x0AThis\x20is\x20my\x20description\x0A";
</script>
Which is totally valid inside a JavaScript context. As you can see the string contains in the HTML version weird characters that are safe for JavaScript and converted during the parsing of the code by the JavaScript engine to an human readable version e.g:
Printing arrays to json safely
Other developers instead of plain strings, decide to pass entire arrays with data that can be used by JavaScript. To do this, you can use the json_encode filter that automatically escapes the content of the array to be safely used by JavaScript:
{% set myData = {
"a": "Complex String Data",
"b": 12345,
"c": "Hello,
Multiline String
"
}%}
<script>
var myData = {{ myData|json_encode() }};
</script>
However you need to use the raw filter as well to print the string as a literal in Twig, otherwise html entities will be converted and printed e.g:
<script>
var myData = {"a":"Complex String Data","b":12345,"c":"Hello,\n Multiline String\n "};
</script>
So don't forget to use the raw filter after json_encode:
{% set myData = {
"a": "Complex String Data",
"b": 12345,
"c": "Hello,
Multiline String
"
}%}
<script>
var myData = {{ myData|json_encode()|raw }};
</script>
Now, we would get a safe array from Twig available in JavaScript:
<script>
var myData = {"a":"Complex String Data","b":12345,"c":"Hello,\n Multiline String\n "};
</script>
Happy coding !