401

What is the easiest way to encode a PHP string for output to a JavaScript variable?

I have a PHP string which includes quotes and newlines. I need the contents of this string to be put into a JavaScript variable.

Normally, I would just construct my JavaScript in a PHP file, à la:

<script>
  var myvar = "<?php echo $myVarValue;?>";
</script>

However, this doesn't work when $myVarValue contains quotes or newlines.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
David Laing
  • 7,605
  • 10
  • 33
  • 44
  • 2
    Just wanted to point out you can use `utf8_encode()` before passing the string to `json_encode`. That's what I'm doing: `echo json_encode(utf8_encode($msg));` – carlosvini Sep 11 '13 at 18:00
  • 1
    This is *not* a duplicate of https://stackoverflow.com/questions/23740548/how-do-i-pass-variables-and-data-from-php-to-javascript. The latter speaks about AJAX etc. and networking questions, whereas here it's about encoding/escaping/quotes and newlines. Let's reopen? (Btw, here the accepted is short, works good and has many hundreds of votes) – Basj Dec 01 '21 at 12:19

14 Answers14

555

Expanding on someone else's answer:

<script>
  var myvar = <?= json_encode($myVarValue, JSON_UNESCAPED_UNICODE); ?>;
</script>

Using json_encode() requires:

  • PHP 5.2.0 or greater
  • $myVarValue encoded as UTF-8 (or US-ASCII, of course)

Since UTF-8 supports full Unicode, it should be safe to convert on the fly.

Please note that if you use this in html attributes like onclick, you need to pass the result of json_encode to htmlspecialchars(), like the following:

htmlspecialchars(json_encode($string), ENT_QUOTES);

or else you could get problems with, for example, &bar; in foo()&&bar; being interpreted as an HTML entity.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
bobwienholt
  • 17,420
  • 3
  • 40
  • 48
  • 10
    If you use UTF-8 that's the best solution by far. – Kornel Oct 13 '08 at 23:02
  • 4
    It is important that the implementation of json_encode escapes the forward slash. If it didn't, this wouldn't work if $myVarValue was "". But json_encode does escape forward slashes, so we're good. – Drew LeSueur Oct 01 '10 at 19:40
  • If you're not 5.2, try jsonwrapper from boutell.com http://www.boutell.com/scripts/jsonwrapper.html – Tom Auger Dec 22 '10 at 22:57
  • If you're using this in portable (e.g. library) code, there's one caveat. json_encode() has been [reported as broken](http://stackoverflow.com/a/7462419). It's fixed for me (5.4.4-7 on debian), but I don't know about earlier versions. – sourcejedi Nov 05 '12 at 12:49
  • Be aware that PHP 5.3 now has options for escaping various characters. See example #2 for various outputs: http://php.net/manual/en/function.json-encode.php – Dan Mar 13 '13 at 23:19
  • 6
    Please note that if you use this in `onclick` attributes and the like, you need to pass the result of `json_encode` to `htmlspecialchars`, like the following: `htmlspecialchars(json_encode($string),ENT_QUOTES,'utf-8')` or else you could get problems with, for example, `&bar;` in `foo()&&bar;` being interpreted as an HTML entity. – user2428118 Jun 02 '14 at 14:09
  • Worked great thanks! Also so others don't run into the same thing I did when using this: Make sure to remove the quotes around your json_encoded php variables you are inserting into javascript because json_encode already includes them. – Kt Mack Sep 09 '14 at 03:33
  • If the string contains new line, then I think it will throw an error – Abhisek Malakar Aug 06 '15 at 08:20
  • A plain json_encode() call for escaping output is insecure. Adding JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_TAG as the second parameter helps in some cases, but it still allows you to inject some JS code like "1; alert(10)" or something more harmful in an example like this. Other than proper input validation, I'm not sure what can help that case. Without the second param, injecting any code is trivial. – lucian303 Dec 30 '15 at 19:34
  • I think the best way on PHP 5.4+ to use two good special flags. And of course, the short syntax. Here is it: `var myvar = =json_encode($myVarValue, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)?>;` . The first one tells not to encode forward slash `/`, the second one prints any utf8 symbols not like `xNNNN` but just as is. – FlameStorm Mar 20 '17 at 09:45
  • @FlameStorm: Encode forward slashes, that is useful to prevent `` injections (!!) as they become `<\/script>`. Otherwise the script tag is closed prematurely which can be used as part of an attack. - see as well the earlier comment http://stackoverflow.com/questions/168214/pass-a-php-string-to-a-javascript-variable-and-escape-newlines#comment4081798_169035 – hakre May 19 '17 at 07:57
  • 4
    @hakre: But how PHP string contains `"......"` can become JS non-string `` instead of just JS string `"......"` after PHP's json_encode? It always add quotes for string. So, `var x = "......";` is just an JS string. No break. – FlameStorm Jul 27 '17 at 14:21
  • For those using Laravel, you can use the ultra-simple `@json($myVarValue)`. See "Rendering JSON" under https://laravel.com/docs/5.6/blade#displaying-data – Ryan DuVal Jun 28 '18 at 17:51
  • There are edge cases where json_encode() is not enough: https://docs.zendframework.com/zend-escaper/escaping-javascript/ – pako Oct 24 '18 at 10:55
  • hello, please does anyone know why I'm getting `SyntaxError: expected expression, got '<'` when using `var a = ;`, thank you – Scaramouche Mar 14 '19 at 13:56
27

encode it with JSON

Javier
  • 60,510
  • 8
  • 78
  • 126
  • Probably the easiest way to get this to work 100% of the time. There are too many cases to cover otherwise. – willasaywhat Oct 03 '08 at 18:42
  • Json only works with UTF-8 Charset. So it is not a solution if your website is working in a non UTF-8 Encoding – Nir Apr 27 '09 at 12:06
  • 4
    @nir: on one hand, i don't know any reason to use any other encoding, on the other hand, a full JSON encoder also manages any needed charset conversion – Javier Apr 28 '09 at 02:03
  • Encoding it with JSON is not enough, you also have to make sure that any Javascript string which contains `` (case insensitive) is dealt with properly. – Flimm Nov 13 '15 at 15:03
  • My only qualm with this is that encoding it with json will force it to an object. In practice, its easier to understand, but when you get to complex arrays of data, specifically that of reading SQL results out from a database, the programmer will need more indepth knowledge of javascript to efficiently handle the data. Essentially what I am saying is that an example of the usage scenario would be great. – Christopher 'Solidus' DeJong Jul 11 '16 at 17:41
  • 2
    Encoding a single scalar value with JSON won't force it to an object - you just get a utf-8 string. For example let's say your php code looks like this: $x=""; and your HTML looks like this: the result in the browse will be: Note the double quotes ahd the escaped slash. – Craig Jacobs Jan 07 '17 at 21:20
24
function escapeJavaScriptText($string)
{
    return str_replace("\n", '\n', str_replace('"', '\"', addcslashes(str_replace("\r", '', (string)$string), "\0..\37'\\")));
}
micahwittman
  • 12,356
  • 2
  • 32
  • 37
22

I have had a similar issue and understand that the following is the best solution:

<script>
    var myvar = decodeURIComponent("<?php echo rawurlencode($myVarValue); ?>");
</script>

However, the link that micahwittman posted suggests that there are some minor encoding differences. PHP's rawurlencode() function is supposed to comply with RFC 1738, while there appear to have been no such effort with Javascript's decodeURIComponent().

pr1001
  • 21,727
  • 17
  • 79
  • 125
12

The paranoid version: Escaping every single character.

function javascript_escape($str) {
  $new_str = '';

  $str_len = strlen($str);
  for($i = 0; $i < $str_len; $i++) {
    $new_str .= '\\x' . sprintf('%02x', ord(substr($str, $i, 1)));
  }

  return $new_str;
}

EDIT: The reason why json_encode() may not be appropriate is that sometimes, you need to prevent " to be generated, e.g.

<div onclick="alert(???)" />
giraff
  • 4,601
  • 2
  • 23
  • 35
  • Escaping every single character worked for me. json_encode doesn't handle backslashes very well. If you need to pass something like a regular expression from mysql to javascript as a parameter then this seems the best way. – Ekim May 22 '12 at 04:05
  • @kristoffer-ryhl correctly remarks that dechex doesn't work for '\t' (= '\x08'), so I edited it to use sprintf. However, this still doesn't seem to work for UTF-8 characters (this would require using '\u' instead) ... – giraff Nov 08 '15 at 12:47
  • For an HTML attribute, you could do `
    `
    – Flimm Nov 13 '15 at 14:55
  • This is not unicode save, check this out: https://docs.laminas.dev/laminas-escaper/escaping-javascript/ – vinsa May 28 '20 at 16:46
6
<script>
var myVar = <?php echo json_encode($myVarValue); ?>;
</script>

or

<script>
var myVar = <?= json_encode($myVarValue) ?>;
</script>
Salman A
  • 262,204
  • 82
  • 430
  • 521
Kld
  • 6,970
  • 3
  • 37
  • 50
4

Micah's solution below worked for me as the site I had to customise was not in UTF-8, so I could not use json; I'd vote it up but my rep isn't high enough.

function escapeJavaScriptText($string) 
{ 
    return str_replace("\n", '\n', str_replace('"', '\"', addcslashes(str_replace("\r", '', (string)$string), "\0..\37'\\"))); 
} 
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Me too! These two lines of code is the best thing that happened to php (at least IMHO). Thanks a lot!! – rizalp1 Oct 26 '12 at 03:44
3

Don't run it though addslashes(); if you're in the context of the HTML page, the HTML parser can still see the </script> tag, even mid-string, and assume it's the end of the JavaScript:

<?php
    $value = 'XXX</script><script>alert(document.cookie);</script>';
?>

<script type="text/javascript">
    var foo = <?= json_encode($value) ?>; // Use this
    var foo = '<?= addslashes($value) ?>'; // Avoid, allows XSS!
</script>
Ry-
  • 218,210
  • 55
  • 464
  • 476
Craig Francis
  • 1,855
  • 3
  • 22
  • 35
  • Maybe I'm making a dumb mistake, but when I try to execute this code, I get the following console error `SyntaxError: expected expression, got '<'` ONLY when I'm referencing an external .js file, when it's inilne, it works fine. Thoughts? – Ryan Dorn Aug 13 '15 at 14:52
  • @RADMKT Just a guess, but if it's a .js file it probably isn't using PHP. Might be worth loading the external JS file in the web browser to see the code output. – Craig Francis Aug 13 '15 at 14:55
3

You can insert it into a hidden DIV, then assign the innerHTML of the DIV to your JavaScript variable. You don't have to worry about escaping anything. Just be sure not to put broken HTML in there.

Diodeus - James MacFarlane
  • 112,730
  • 33
  • 157
  • 176
3
  1. Don’t. Use Ajax, put it in data-* attributes in your HTML, or something else meaningful. Using inline scripts makes your pages bigger, and could be insecure or still allow users to ruin layout, unless…

  2. … you make a safer function:

    function inline_json_encode($obj) {
        return str_replace('<!--', '<\!--', json_encode($obj));
    }
    
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • I'm pretty sure that ` – Flimm Nov 13 '15 at 15:00
  • @Flimm: Did you look at the codepad link? Try ``, where the two strings passed to `console.log` are user-provided (i.e. the template looks like ``, where `$s1` and `$s2` come from a bad JSON encoder). Granted, the second string contains an unescaped forward slash and the example is utterly contrived, but a malicious user could still cause a syntax error like this. – Ry- Nov 13 '15 at 20:58
  • @Flimm: How this works: ` – Ry- Nov 13 '15 at 20:59
2

You could try

<script type="text/javascript">
    myvar = unescape('<?=rawurlencode($myvar)?>');
</script>
Jacob
  • 10,452
  • 5
  • 22
  • 11
  • Doesn't completely work. Try with this string::: I'm wondering "hey jude" 'cause 1 + 1 < 5 ::: we still get < so not a 100% bidirectional transliteration – Tom Auger Dec 22 '10 at 22:55
  • `unescape` is now deprecated. Use `decodeURIComponent` instead. – Mike Doe May 19 '16 at 11:05
0

htmlspecialchars

Description

string htmlspecialchars ( string $string [, int $quote_style [, string $charset [, bool $double_encode ]]] )

Certain characters have special significance in HTML, and should be represented by HTML entities if they are to preserve their meanings. This function returns a string with some of these conversions made; the translations made are those most useful for everyday web programming. If you require all HTML character entities to be translated, use htmlentities() instead.

This function is useful in preventing user-supplied text from containing HTML markup, such as in a message board or guest book application.

The translations performed are:

* '&' (ampersand) becomes '&amp;'
* '"' (double quote) becomes '&quot;' when ENT_NOQUOTES is not set.
* ''' (single quote) becomes '&#039;' only when ENT_QUOTES is set.
* '<' (less than) becomes '&lt;'
* '>' (greater than) becomes '&gt;'

http://ca.php.net/htmlspecialchars

Chris MacDonald
  • 5,975
  • 4
  • 34
  • 35
  • 3
    This will only be the right solution if the content of the JS variable is actually supposed to be HTML, where a string token like & has meaning. Otherwise, it might be best to not convert them to entities. – Peter Bailey Oct 03 '08 at 18:48
-1

I'm not sure if this is bad practice or no, but my team and I have been using a mixed html, JS, and php solution. We start with the PHP string we want to pull into a JS variable, lets call it:

$someString

Next we use in-page hidden form elements, and have their value set as the string:

<form id="pagePhpVars" method="post">
<input type="hidden" name="phpString1" id="phpString1" value="'.$someString.'" />
</form>

Then its a simple matter of defining a JS var through document.getElementById:

<script type="text/javascript" charset="UTF-8">
    var moonUnitAlpha = document.getElementById('phpString1').value;
</script>

Now you can use the JS variable "moonUnitAlpha" anywhere you want to grab that PHP string value. This seems to work really well for us. We'll see if it holds up to heavy use.

ioTus
  • 667
  • 6
  • 9
  • 1
    I have been doing this in my previous projects. Next time, I will try to use jQuery data. – wenbert Aug 27 '10 at 06:05
  • 2
    remember to htmlencode your $someString... and while this is fine for input @value's, you have to be extra careful with href/src/onclick type attributes (try to white-list), as they can go straight into using the javascript: protocol, which is not protected against with html encoded values. – Craig Francis Oct 19 '12 at 09:55
  • To be safe, you should really do `value=""`. – Flimm Nov 13 '15 at 15:02
-3

If you use a templating engine to construct your HTML then you can fill it with what ever you want!

Check out XTemplates. It's a nice, open source, lightweight, template engine.

Your HTML/JS there would look like this:

<script>
    var myvar = {$MyVarValue};
</script>
Chandru
  • 1,306
  • 13
  • 21
Adam
  • 25,966
  • 23
  • 76
  • 87