24

From time to time I have to pass some variables from PHP to JS script. For now I did it like this:

var js-variable = "<?php echo $php-variable; ?>";

But this is very ugly and I can't hide my JS script in .js file because it has to be parsed by PHP. What is the best solution to handle this?

Léo Léopold Hertz 준영
  • 134,464
  • 179
  • 445
  • 697
user606521
  • 14,486
  • 30
  • 113
  • 204

8 Answers8

35

If you don't want to use PHP to generate your javascript (and don't mind the extra call to your webserver), use AJAX to fetch the data.

If you do want to use PHP, always encode with json_encode before outputting.

<script>
    var myvar = <?php echo json_encode($myVarValue); ?>;
</script>
ilanco
  • 9,581
  • 4
  • 32
  • 37
  • +1 json is the best way to use data from a PHP script, whether it's via ajax or the the same time as the page is compiled. – Joseph Jun 05 '12 at 09:43
  • 7
    WARNING: This can kill your website. Example: `'; ?>`. See [this question](http://stackoverflow.com/q/20942452/1402846) for details. Solution: Use [`JSON_HEX_TAG`](http://www.php.net/manual/en/json.constants.php#constant.json-hex-tag) to escape `<` and `>` (requires PHP 5.3.0). – Pang Jan 12 '14 at 07:30
  • Another downside of this is that impacts the inital page load time. – biplav Jun 18 '14 at 10:18
  • @Pang and biplav, could you be more specific please. http://stackoverflow.com/q/24855186/1951635 – Yatko Jul 20 '14 at 21:45
  • @biplav - how does this affect the performance? I what circumstances? Thanks! – Yatko Jul 20 '14 at 21:47
  • @Yatko : The out put of this would be calculated before the page is served from apache to your browser. Suppose, if $myVarValue is calculated by executing a query which takes 500ms. This would add a 500ms delay to initial page load. Another disadvantage is that, to test this query would be tougher compared to an api/rest driven approach. From the point of view of testability and UX rest driven approach is better. Once can easily load the entire page and show the loading symbol for the part of page which uses this variable and then make an ajax call to load that part and build the page. – biplav Jul 21 '14 at 07:53
8
<?php
// filename: output-json.php
header('content-type:application/json;charset=utf-8');
printf('var foo = %s;', json_encode($foo, JSON_PRETTY_PRINT));

json_encode is a robust function that ensures the output is encoded and formatted as valid javascript / json. The content-type header tells the browser how to interpret the response.

If your response is truly JSON, such as:

{"foo": 5}

Then declare it as content-type:application/json;charset=utf-8. JSON is faster to parse, and has much less chance of being xss exploited when compared to javascript. But, if you need to use real javascript in the response, such as:

var obj = {foo: 5};

Then declare it as content-type:text/javascript;charset=utf-8

You can link to it like a file:

<script src="output-json.php"></script>

Alternatively, it can be convenient to embed the value directly in your html instead of making a separate http request. Do it like so:

<script>
    <?php printf('var foo = %s;', json_encode($foo, JSON_HEX_TAG | JSON_PRETTY_PRINT)) ?>
</script>

Make sure to use JSON_HEX_TAG if embedding into your html via the <script> tag, otherwise you risk xss injection attacks. There's also other flags you may need to make use of for more security depending on the context you use it in: JSON_HEX_AMP, JSON_HEX_QUOT, JSON_HEX_APOS. Those flags make the response less human readable, but are generally good for security and compatibility, so you should probably just use them.

I really want to emphasize the importance of declaring the content type and possibly using the JSON_HEX_TAG flag, as they can both help mitigate xss injection.

Do not do this unless you wish to tempt an xss attack:

<script>
    var myvar = <?php echo json_encode($myVarValue); ?>;
</script>
goat
  • 31,486
  • 7
  • 73
  • 96
8

Please use a rest/rpc api and pass json to your js. This can be done in the following way if you are using jquery:

rest.php

<?php echo "{name:biplav}" ?>

Then From your js make a get call like this:

var js_var;
$.get("rest.php", function(data) {
         js_var=data;
});

Thats the simplest example I can think of.

biplav
  • 781
  • 6
  • 13
3

In my opinion, if you need to pass a variable directly in your JS, probably your web application is not good designed.

So, I have two tips: * Use JSON files for general configurations, like /js/conf/userprefs.json

{
    "avatar": "/img/users/123/avatar.jpg",
    "preferred_color": "blue"
    // ...
}
  • or (better way) you can retrieve your json confs with an AJAX call.

With PHP frameworks like Symfony2, you can decide a format in your routing configuration leaving the output of a variable to the template engine (like Twig).

I do an example for Symfony2 users but this can be used by any programmer:

routing.yml

userprefs:
    pattern: /js/confs/userprefs.{_format}
    defaults: { _controller: CoreBundle:JsonPrefs:User, _format: json }
    requirements:
        _format: json
        _method: GET

Inside the controller you can do all the queries that you need to retrieve your variables putting these in the view:

Resources/Views/JsonPrefs/User.json

{
    "avatar": "{{ user.avatar }}",
    "preferred_color": "{{ user.preferred_color }}"
    // ...
}

Inside your JS now you'll be able to retrieve the JSON with a simple AJAX call. For performance purposes you can cache the JSONs (for example) with Varnish. In this way your server doesn't need to do a query every time you read the user preferences.

Francesco Casula
  • 26,184
  • 15
  • 132
  • 131
2

If you modify your .htaccess file to include

 AddType application/x-httpd-php .js

you can use a .js file and it will be handled by PHP, which is half of what you require.

In terms of how ugly that solution is, I would say that this is the least ugly mechanism. You could try to pass your whole JS script through a PHP script as a string and do a search and replace for the variables you need to insert, but I think that you will agree that this is uglier than the solution you are currently using.

Eliot Ball
  • 698
  • 5
  • 11
2

Put all your .js files in a folder and configure your HTTP server to redirect all the request to those files to a PHP file that loads the files and outputs them.

Let's suppose you have Apache and your .js files are in /js:

RewriteRule /js   /getjs.php

getjs.php:

<?php
header('Content-Type: text/javascript');
include_once($_SERVER['SCRIPT_NAME']);
?>
MaxArt
  • 22,200
  • 10
  • 82
  • 81
1

As far as avoiding running .js files through the PHP parser, there is little you can do, except maybe fetching the value of js-variable via an AJAX call.

Also you may consider outputing the value like this:

var js_variable = <?php echo json_encode ($php_variable); ?>

to escape all the things that would break your javascript.

wroniasty
  • 7,884
  • 2
  • 32
  • 24
0

At the very least, you can use a PHP shortcode to make your "ugly" solution a bit cleaner:

var js-variable = "<?= $php-variable ?>";
Kevin
  • 661
  • 6
  • 14
  • 1
    I am not the downvoter, but shortcode has portability issues and hence should be avoided friend. – Stephane Gosselin Mar 02 '14 at 22:15
  • This is not ugly when you think of PHP as the template engine that it also is. However, if he could solve it with Ajax, it would be better, I agree. – David Jul 05 '15 at 18:54