PHP: how to perform htmlspecialchar() on an array-of-arrays?

Viewed 28334

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' : []}
10 Answers

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.

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

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.

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; ) ) )

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
                )

        )

)

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'));

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);

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
        )
        */

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;
}
Related