Search code examples
phparraysformsposthtmlspecialchars

htmlspecialchar on HTML POST to PHP script with array and single inputs


I have an HTML form that uses POST to send data to a PHP script. Until now I have not used an array in an HTML form, but this form calls for some fields to be grouped (e.g., price and qty) while other fields remain single input fields (name, email, etc).

I would like to sanitize the input when it is received by the PHP script. With single input fields, I used to loop through the fields like this:

if( !empty($_POST) ) {
    foreach( $_POST as $x => $y ) {
        $_POST[$x] = htmlspecialchars($y);
        $_POST[$x] = trim($y);
    }
}

How can I sanitize the input when some of the items are in an array?


Solution

  • Modifying all of the leaf nodes in your multidimensional array is easily done with the native function array_walk_recursive() because it visits all of the "leaf nodes" by design.

    Code: (Demo) (or as an anonymous one-liner)

    $sweet = ['a' => 'apple ', 'b' => ' "banana"      '];
    $array = ['sweet' => $sweet, 'test' => " <a href='test'>Test</a>"];
    
    function mySanitizer(&$value) {
        $value = htmlspecialchars(trim($value));
    }
    array_walk_recursive($array, 'mySanitizer');
    
    var_export($array);
    

    Output:

    array (
      'sweet' => 
      array (
        'a' => 'apple',
        'b' => '&quot;banana&quot;',
      ),
      'test' => '&lt;a href=\'test\'&gt;Test&lt;/a&gt;',
    )
    

    Notice the use of & on the value parameter. This tells the script to modify the data by reference -- otherwise no changes would persist outside of the scope of array_walk_recursive


    How to apply this technique...

    To apply this technique to all elements in the $_POST superglobal array, call:

    array_walk_recursive($_POST, 'mySanitizer');
    

    Of course, this requires you to write the custom function declaration (function mySanitizer() {...}).

    Alternatively, if you don't wish to declare the custom function mySanitizer, then this is all you need to write:

    array_walk_recursive($_POST, function(&$value){
        $value = htmlspecialchars(trim($value));
    });
    

    It is more commonplace to have a return value from most functions, however array_walk_recursive() does not offer return data. For this function to be effective for your requirements, the input array must be directly affected by the custom function that it contains. "Modifying a variable by reference" means that you don't need to overwrite the $_POST variable by assignment (like $_POST = ...). Simply by feeding the input array into the native function, writing & before the $value parameter, then overwriting each encountered $value while iterating, your $_POST variable will be sanitized.

    As for how array_walk_recursive() "iterates/loops"... there is a special behavior to enjoy. The function will traverse every level of your array. If it finds an "iterable" element, it will loop through the elements that it contains. If it encounters a non-iterable element (scalar elements might be a string, integer, float, boolean, null) it will execute a function / callback (whatever you command it to) on it.

    Another example of a php function that modifies by reference is sort(). You don't make an assignment with this function, you just pass your data through it and when you next access the variable's data, it is already modified.