CodeIgniter Forums

Full Version: Using JSON in data attributes with JS
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I don't know if it's considered bad practice, or if it's the way everyone does it, but I find myself inserting JSON data into HTML element attributes all the time. So, for instance:

PHP Code:
foreach( $query->result_array() as $row )
    
$arr[] = (object) array_map'html_escape'$row );

$json json_encode$arr );

$json_string str_replace([
    
'"',
    
''',
    
'& #039;' // space here for codeigniter forum
], [
    
'\u0022',
    
'\u0027',
    
'\u0027'
], $json ); 

Now I know that json_encode has options like JSON_HEX_APOS and JSON_HEX_QUOT, but I also want to use html_escape() which is why I'm using str_replace the way I am. This allows me to do this:


PHP Code:
echo '<div data-json=\'' $json_string '\'>'

Then later in my json I can use JSON.parse() on the contents of that data-json attribute.

What are your thoughts here? Is there a better way?
For views I use the Twig parser and here is a test on how I would do this:

Code:
<div id="test_element" data-json="{{ '{ "value_1": "A test string value.", "value_2": 2 }'|e('html_attr') }}"></div>

<script>

    $(function() {

        var data_json = $('#test_element').attr('data-json');
        alert(data_json);

        var data = JSON.parse(data_json);
        alert(data.value_1);
        alert(data.value_2);
    });

</script>

This works, and the produced HTML code looks like this:

Code:
<div id="test_element" data-json="&#x7B;&#x20;&quot;value_1&quot;&#x3A;&#x20;&quot;A&#x20;test&#x20;string&#x20;value.&quot;,&#x20;&quot;value_2&quot;&#x3A;&#x20;2&#x20;&#x7D;"></div>

<script>

    $(function() {

        var data_json = $('#test_element').attr('data-json');
        alert(data_json);

        var data = JSON.parse(data_json);
        alert(data.value_1);
        alert(data.value_2);
    });

</script>

For PHP views this example would be:

Code:
<div id="test_element" data-json="<?php echo html_attr_escape('{ "value_1": "A test string value.", "value_2": 2 }'); ?>"></div>

<script>

    $(function() {

        var data_json = $('#test_element').attr('data-json');
        alert(data_json);

        var data = JSON.parse(data_json);
        alert(data.value_1);
        alert(data.value_2);
    });

</script>

The helper function html_attr_escape() is introduced by me, it calls the Twig's escaper to do the job.
https://github.com/ivantcholakov/starter...n.php#L283

If you don't need Twig to be installed in your project, you can implement html_attr_escape() by using the escaper form Zend. https://github.com/zendframework/zend-es...r.php#L155 The escapers of Twig seem to be ported from Zend. I can see that CodeIgniter 4 would use the Zend Escaper, you can back-port this function: https://github.com/bcit-ci/CodeIgniter4/...n.php#L219 :

Code:
<div id="test_element" data-json="<?php echo esc('{ "value_1": "A test string value.", "value_2": 2 }', 'attr'); ?>"></div>

In conclusion, you should find a way to escape the data html attribute as html attribute, it does not matter whether it would contain json data or something else. I think, the trivial way would be the best here, everyone would understand it without getting bored or tired.
ivantcholakov, that Escaper class is very thorough. My only concern is that when testing, it took a 41 character string of json and turned it into 127 characters.

So this:


PHP Code:
$escaper = new Escaper('utf-8');
$str $escaper->escapeHtmlAttr(json_encode([
 
   'yodels' => 'Brian\'s',
 
   'lemons' => '"Lovely"'
]));
echo 
$str

Became this:


Code:
&#x7B;&quot;yodels&quot;&#x3A;&quot;Brian&#x27;s&quot;,&quot;lemons&quot;&#x3A;&quot;&#x5C;&quot;Lovely&#x5C;&quot;&quot;&#x7D;

If I've got a lot of json, I guess I might need to put it somewhere besides an attribute.

Thanks for the links. That Escaper class is pretty cool. Definitely useful and easier to use than rolling my own.
Another possible way that I used in the past is using base_64 encoded strings, they could be put as attributes directly. But this is a complication that I don't like, the JavaScript should decode from base_64 first and then to decode the JSON string.
(11-14-2017, 10:48 PM)ivantcholakov Wrote: [ -> ]Another possible way that I used in the past is using base_64 encoded strings, they could be put as attributes directly. But this is a complication that I don't like, the JavaScript should decode from base_64 first and then to decode the JSON string.

I haven't used that technique, but I saw that it can be done, decoding in JS with atob(). For me I just want something that is easy and foolproof.
About base_64 I used this JavaScript: http://www.webtoolkit.info/javascript-ba...gxPf3RSxhG , it worked for me. Probably there are other similar ones.

I did not try atob(), I am not sure about it: https://developer.mozilla.org/en-US/docs...de_Problem
(11-15-2017, 07:33 AM)ivantcholakov Wrote: [ -> ]About base_64 I used this JavaScript: http://www.webtoolkit.info/javascript-ba...gxPf3RSxhG , it worked for me. Probably there are other similar ones.

I did not try atob(), I am not sure about it: https://developer.mozilla.org/en-US/docs...de_Problem

 Re the second link, gotta laugh at "Solution #1 – escaping the string before encoding it". That would just make the string even longer.