21

How do I run the PHP function htmlspecialchars() on an array of array objects?

I have the following code:

$result_set = Array
(
    [0] => Array
        (
            [home_id] => 1
            [address] => 4225 Nasmyth Dr
            [city] => Plano
            [state] => TX
            [zip] => 76798
        )

    [1] => Array
        (
            [home_id] => 8
            [address] => 4229 Nasmyth Dr
            [city] => Plano
            [state] => TX
            [zip] => 75093
        )
);

// this doesn't work since $result_set is an array of arrays and htmlspecialchars is expecting a string
htmlspecialchars($result_set, ENT_QUOTES, 'UTF-8')); 

UPDATE:

Please note that even though there are quite a few answers below, none of them work for an array-of-arrays. The answers below only work for simple arrays.

I've tried the following, but it doesn't work:

array_walk_recursive($result_set, "htmlspecialchars", array(ENT_QUOTES,'UTF-8'))

I get the following error: htmlspecialchars() expects parameter 2 to be long, string given


UPDATE 2

When I try:

function cleanOutput(&$value) {
    return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
print_r($result_set);
print('-------');
print_r(array_walk_recursive($result_set, "cleanOutput"));

I get the following, undesired, output:

Array
(
    [0] => Array
        (
            [home_id] => 1
            [address] => 4225 Nasmyth Dr
            [city] => Plano
            [state] => TX
            [zip] => 76798
        )
    [1] => Array
        (
            [home_id] => 8
            [address] => 4229 Nasmyth Dr
            [city] => Plano
            [state] => TX
            [zip] => 75093
        )
)
-------1

UPDATE 3

When I try:

function cleanOutput(&$value) {
    return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
$result_set = Array
    (
        [0] => Array
            (
                [home_id] => 1
                [address] => 4225 Nasmyth Dr
                [city] => Plano
                [state] => TX
                [zip] => 76798
            )

        [1] => Array
            (
                [home_id] => 8
                [address] => 4229 Nasmyth Dr
                [city] => Plano
                [state] => TX
                [zip] => 75093
            )
    );

$cleanedOutput = array();
foreach ($result_set as $rs) {
    $cleaned[] = array_map("cleanOutput", $rs);
}
print_r($cleanedOutput);

I get the following, undesired, results:

{'homes' : []}
TeddyR
  • 383
  • 2
  • 6
  • 12

10 Answers10

27

You can use array_map() to run that method on each entry.

$cleaned = array_map("htmlspecialchars", $myArray);

If you need to pass arguments to htmlspecialchars(), you can substitute it for your own custom function:

function myFunc($a) {
  return htmlspecialchars($a, ENT_QUOES);
}

$cleaned = array_map("myFunc", $myArray);

Considering the fact that you're dealing with an array of arrays, and not an array of strings, you would need to cycle through the outer-array to get to your strings:

$cleaned = array();
foreach ($result_set as $rs) {
  foreach ($rs as $r) {
    $cleaned[] = array_map("htmlspecialchars", $r);
  }
}

Or, you could use array_walk_recursive():

array_walk_recursive($myArray, "htmlspecialchars");

Note that this method changes the $myArray object by reference, so there's no need to assign the output to a new variable.

Sampson
  • 265,109
  • 74
  • 539
  • 565
  • How do I use array_map() if I want to pass agruments to htmlspecialchars? Meaning, how do I pass the arguements of ENT_QUOTES, 'UTF-8'" to htmlspecialchars? – TeddyR Jan 04 '10 at 22:28
  • Meaning, 'array_map("htmlspecialchars", $result_set)' does not allows me to pass in the argument of ENT_QUOTES and UTF-8 – TeddyR Jan 04 '10 at 22:30
  • TeddyR, make your own function that calls htmlspecialchars with those arguments, and call your function instead. – Sampson Jan 04 '10 at 22:32
  • 1
    Why wouldn't this work --> array_map('htmlspecialchars', $result_set, array(ENT_QUOTES, 'UTF-8')) ??? – TeddyR Jan 04 '10 at 22:37
  • I receive the following error, "htmlspecialchars() expects parameter 2 to be long, string given" when using rray_map('htmlspecialchars', $result_set, array(ENT_QUOTES, 'UTF-8')) – TeddyR Jan 04 '10 at 22:43
  • @Jonathan Sampson, why do I need to create another function (myFunc)? – TeddyR Jan 04 '10 at 22:54
  • The arrays passed to array_map should be of equal length. The argument list for the callback function is comprised of one element from each array. If you wanted to do it this way, the call to array_map would look like this: array_map('htmlspecialchars', $result_set, array_fill(0, count($result_set), ENT_QUOTES), array_fill(0, count($result_set), 'UTF-8')). Take Jonathan's advice. It's much simpler and cleaner. – bish Jan 04 '10 at 22:56
  • You could also use an anonymous function (PHP 5.3 and later) that calls `htmlspecialchars` with the appropriate arguments: http://php.net/manual/en/functions.anonymous.php – Will Vousden Jan 04 '10 at 22:58
  • @bish, I receive an error when trying your way. The error is: "array_fill() [function.array-fill]: Number of elements must be positive in" – TeddyR Jan 04 '10 at 22:58
  • @TeddyR Make sure count($result_set) is actually returning the length of the $result_set array. If it's returning 0, that will cause the error you're seeing. – bish Jan 04 '10 at 23:00
  • @Jonathan, when I try your way - I receive the following error: "htmlspecialchars() expects parameter 1 to be string" – TeddyR Jan 04 '10 at 23:02
  • @TeddyR, your first-level types are arrays. $result_set[0] is an array, not a string. Within your clean-method you need to address the strings, not arrays. – Sampson Jan 04 '10 at 23:37
  • @Jonathan, so how would I do this then given that I have an array of arrays – TeddyR Jan 04 '10 at 23:42
  • @TeddyR, you could use `foreach`. – Sampson Jan 04 '10 at 23:49
  • @Jonathan, thanks for the update ... just one last question. What's the most efficient way if I also wanted to pass the ENT_QUOTES and 'UTF-8' agruments to the htmlspecialchars() function using an array-of-arrays? – TeddyR Jan 04 '10 at 23:56
  • when I try: array_walk_recursive("htmlspecialchars", $result_set, array(ENT_QUOTES,'UTF-8')) .... I get the following error: "Only variables can be passed by reference" – TeddyR Jan 04 '10 at 23:59
  • Your array is the first argument in `array_walk_recursive`, not the second. – Sampson Jan 05 '10 at 00:01
  • When I update my code to: array_walk_recursive($result_set, "htmlspecialchars", array(ENT_QUOTES,'UTF-8')) ... , I get a new error: "htmlspecialchars() expects parameter 2 to be long, string" – TeddyR Jan 05 '10 at 00:03
  • @Jonathan, any ideas? You've been of huge help so far. – TeddyR Jan 05 '10 at 00:12
  • @TeddyR, if you wish to use additional arguments, it appears you should go with my earlier suggestion, `foreach` and `array_map` according to the consensus on this page: http://stackoverflow.com/questions/1317063/php-htmlspecialchars-error – Sampson Jan 05 '10 at 00:22
  • @Jonathan, using the foreach doesn't work. See my UPDATE 3 to my original post. – TeddyR Jan 05 '10 at 00:35
  • @TeddyR, oh, I think you'll need a nested-foreach. See my updated foreach. – Sampson Jan 05 '10 at 00:52
23
function filter(&$value) {
  $value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
array_walk_recursive($result_set, "filter");
print_r($result_set);
JW.
  • 50,691
  • 36
  • 115
  • 143
  • Shouldn't this work ---> array_walk_recursive("htmlspecialchars", $result_set, array(ENT_QUOTES,'UTF-8')) ... but it doesn't. I get the error: "Only variables can be passed by reference" – TeddyR Jan 05 '10 at 00:01
  • Looks like I have the ordering wrong on my parameters. It should be: array_walk_recursive("htmlspecialchars", $result_set, array(ENT_QUOTES,'UTF-8')) ... but now I get a new error: "htmlspecialchars() expects parameter 2 to be long, string given" – TeddyR Jan 05 '10 at 00:04
  • You still have the order wrong. I updated my example to include the additional arguments that you wanted. Also, you need to define your own function, as I do above, rather than just passing "htmlspecialchars". This is because array_walk_recursive doesn't normally modify the array itself; it just calls the function on each element. So if you want the function to change the array, you need to make its first argument a reference, as in my &$value above. – JW. Jan 05 '10 at 00:09
  • @JW, I've tried the following, but it doesn't work: array_walk_recursive($result_set, "htmlspecialchars", array(ENT_QUOTES,'UTF-8')) I get the following error: htmlspecialchars() expects parameter 2 to be long, string given – TeddyR Jan 05 '10 at 00:13
  • Try the code as I wrote it first. You're misunderstanding the way the third argument to array_walk_recursive works. Check the manual page here: http://php.net/manual/en/function.array-walk-recursive.php – JW. Jan 05 '10 at 00:14
  • @JW, when I try your code above - it returns an empty array. Even when I change you code from: $value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); to return htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); ... it still doesn't work – TeddyR Jan 05 '10 at 00:21
  • It's not returning anything -- it's modifying $result_set in-place. Do print_r($result_set) after you run my code, and you'll see the results. – JW. Jan 05 '10 at 00:23
  • @JW, see UPDATE 2 for the full results in the original post. – TeddyR Jan 05 '10 at 00:29
  • @JW, as you can see in UPDATE 2 - strange why it isn't working. You can see the output in the original post. – TeddyR Jan 05 '10 at 00:36
  • 3
    In UPDATE 2, you're still printing the return value of array_walk_recursive, which is not what you want. Just print $result_set. Slow down a second and read the manual page for array_walk_recursive ... you'll see how it works. I modified my example above to print the array. – JW. Jan 05 '10 at 00:41
  • Thank You @JW. Code works perfect. Could you please briefly explain why we are using `&` symbol inside `filter(&$value)` with `$value`? – Sanchit Gupta Jun 28 '17 at 06:34
  • 1
6

A lot of the answers on this page are either insufficient, outdated, or use the wrong parameters for array_map or array_walk_recursive. Here's a function that will fix all scalar values in an array recursively.

htmlspecialchars_recursive()

<?php

function htmlspecialchars_recursive ($input, $flags = ENT_COMPAT | ENT_HTML401, $encoding = 'UTF-8', $double_encode = false) {
    static $flags, $encoding, $double_encode;
    if (is_array($input)) {
        return array_map('htmlspecialchars_recursive', $input);
    }
    else if (is_scalar($input)) {
        return htmlspecialchars($input, $flags, $encoding, $double_encode);
    }
    else {
        return $input;
    }
}

$test = array(
    0 => array(
        'test-1' => 'testing <p>html tag</p> will be fixed',
        'test-2' => '&reg; valid and will be left intact',
        'test-3' =>  '© 2080 kept intact'
    ),
    1 => array(
        'test-4' => array(
            'test-5' => 'deeper fix on <p>html tag</p> test',
            'test-6' => '&reg; will be left intact',
            'test-7' =>  '© 2080 kept intact'
        )
    )
);

print_r(htmlspecialchars_recursive($test));

?>

Output

Array
(
    [0] => Array
        (
            [test-1] => testing &lt;p&gt;html tag&lt;/p&gt; will be fixed
            [test-2] => &reg; valid and will be left intact
            [test-3] => © 2080 kept intact
        )

    [1] => Array
        (
            [test-4] => Array
                (
                    [test-5] => deeper fix on &lt;p&gt;html tag&lt;/p&gt; test
                    [test-6] => &reg; will be left intact
                    [test-7] => © 2080 kept intact
                )

        )

)
Anthony Hatzopoulos
  • 10,437
  • 2
  • 40
  • 57
4

You may wish to use array_map as Jonathon Sampson suggested, another alternative is array_walk

The difference is that array_map returns a copy of the array with the function applied to each element, while array_walk operates directly on the array you supply.

JAL
  • 21,295
  • 1
  • 48
  • 66
4

Made way to make it work for multi-dimensional arrays:

function secure($val) {
    return (is_array($val))?array_map('secure',$val):htmlspecialchars($val, ENT_QUOTES, 'UTF-8');
}

It works, that it calls its-self on array without last used array and if its not an array, it passes it to htmlspecialchars function.

Input: Array ( [0] => test< [1] => Array ( [test>] => <test?> ) [2] => Array ( [0] => test [1] => > [2] => Array ( [0] => bigtest<> ) ) )

Output: Array ( [0] => test&lt; [1] => Array ( [test>] => &lt;test?&gt; ) [2] => Array ( [0] => test [1] => &gt; [2] => Array ( [0] => bigtest&lt;&gt; ) ) )

rojikada
  • 347
  • 1
  • 3
  • 9
1

You don't need to create your own function if you are passing multiple arguments to the called back function.

According to php.net:

array array_map ( callback $callback , array $arr1 [, array $... ] )

So that means if you want to pass multiple arguments you should just pass:

$clean_array = array_map("htmlspecialchars", $myArray, array(ENT_QUOTES, 'UTF-8'));

but for some reason this doesn't work for me.

But this seems to does, don't ask me why.

$clean_array = array_map("htmlspecialchars", $myArray, array(ENT_QUOTES), array('UTF-8'));
Tyson of the Northwest
  • 2,086
  • 2
  • 21
  • 34
  • This does not work. I receive the error: array_map() [function.array-map]: Argument #3 should be an array – TeddyR Jan 04 '10 at 22:50
  • So, I'm stumped. Because neither your way nor Jonathan's way works. Both generate errors, see my comments for the exact errors. – TeddyR Jan 04 '10 at 23:04
  • I have revised it, it seems to work for me, but test it and see if it outputs properly for you. For some reason if I put both arguments in the same array it stated that "htmlspecialchars() expects parameter 2 to be long". You got me. – Tyson of the Northwest Jan 04 '10 at 23:12
  • @travover, In your second example, I receive the following error: "htmlspecialchars() expects parameter 1 to be string, array given" – TeddyR Jan 04 '10 at 23:38
  • @tvanover This would only work for the first element of the array. Look at Example #3 in the documentation and the comment immediately after it as to why. – bish Jan 04 '10 at 23:51
  • Well nuts, Looks like the custom function is the one. Or do the array_fill. – Tyson of the Northwest Jan 05 '10 at 01:02
0

If you want to use array_map and pass the function arguments, you can create your own function and use that as the callback:

 function cleanhtml($dirtyhtml) {
       return htmlspecialchars($dirtyhtml, UTF-8);
  }

  $cleaned = array_map("cleanhtml", $myArray);
Anthony
  • 36,459
  • 25
  • 97
  • 163
  • you don't really need your own function, array_map can pass multiple arguments to the target callback function. array array_map ( callback $callback , array $arr1 [, array $... ] ) The only time you would want to create your own is if you are doing more than one thing to every object in the array. – Tyson of the Northwest Jan 04 '10 at 22:42
  • I noticed that from the comment above. But the php documentation does NOT make it very clear. One simple example would really be helpful. All of their examples assume user-written functions. – Anthony Jan 04 '10 at 22:57
  • This generates the following error: "htmlspecialchars() expects parameter 1 to be string" when I use the following code: function cleanhtml($dirtyhtml) { return htmlspecialchars($dirtyhtml, ENT_QUOTES,'UTF-8'); } $cleaned = array_map("cleanhtml", $myArray); – TeddyR Jan 04 '10 at 23:05
0
function htmlspecialchars_array_modify (&$arr){
        array_walk_recursive($arr,function(&$value){
            $value=htmlspecialchars($value);
        });
        return $arr;
    }

// this will alter the source

bortunac
  • 4,642
  • 1
  • 32
  • 21
0

Validation Class function

function htmlspecialchars_recursive ($input, $flags = ENT_COMPAT | ENT_HTML401, $encoding = 'UTF-8', $double_encode = false) {
    static $flags, $encoding, $double_encode;
    if (is_array($input)) {
        return array_map(array($this, 'htmlspecialchars_recursive'), $input);
    }
    else if (is_scalar($input)) {
        return htmlspecialchars($input, $flags, $encoding, $double_encode);
    }
    else {
        return $input;
    }
}

Details:

$input = your input array() or scalar types like integer, float, string or boolean.

$flags = PHP Available flags constant description here

$encoding = encoding type default: UTF-8

$double_encode = based on your needs, you can used. TURE or FALSE

Function call

 //It will convert htmlentities
$param =  $this->htmlspecialchars_recursive($_REQUEST);
// print_r($param);

Output:

/*
        array(
            [whyiitgnq] => &lt;ul&gt;&lt;li&gt;&lt;b&gt;teste&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;tetst&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;i&gt;&lt;u&gt;tets&lt;/u&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;tets&lt;/div&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;tetst&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;tetst&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;test&lt;/b&gt;&lt;/li&gt;&lt;/ol&gt;
            [_wysihtml5_mode] => 1
            [aid] => 12695
        )
        */
venkatskpi
  • 800
  • 6
  • 8
0

Here's another generic version that uses array_walk and behaves in the way that htmlspecialchars does with respect to parameters.

function htmlspecialchars_r($string, 
    int $flags = ENT_COMPAT | ENT_HTML401, 
    string $encoding = null,
    bool $double_encode = true )
{
    if ($encoding === null)
    {
        $encoding =  ini_get("default_charset");
    }

    $filter = function(&$value, $flags, $params) {
        $value = htmlspecialchars($value, $params['flags'], $params['encoding'], $params['double_encode']);
    };

    array_walk_recursive($string, $filter,
        array(
            'flags' => $flags,
            'encoding' => $encoding,
            'double_encode' => $double_encode,
        )
    );

    return $string;
}
dougd_in_nc
  • 371
  • 5
  • 20