In the end, I used my own solution based on @VolkerK's answer. I should clarify what I want. I am updating my question with this information.
I'm still looking for an easier solution.
First, I made several arrays of results:
// errors to display $errors = array(); // fields to ignore in the validation step $ignore_fields = array(); // return values after validation $returnvalues = array();
First, I filtered out the required fields:
function required($string){ return trim($string) == "" ? false : $string; } $required_errors = array( "firstname" => "Je moet je voornaam invullen.", "lastname" => "Je moet je achternaam invullen.", "email" => "Je moet je e-mailadres invullen." ); $required_filter = array(); foreach($required_errors as $requiredfieldname => $error){ $required_filter[$requiredfieldname] = array( 'filter' => FILTER_CALLBACK, 'options' => "required", 'flags' => FILTER_NULL_ON_FAILURE ); } $required_filtered = filter_input_array(INPUT_GET | INPUT_POST, $required_filter); foreach($required_errors as $required => $error){ if(!isset($required_filtered[$required])){ $errors[$required] = $required_errors[$required]; $returnvalues[$required] = ""; $ignore_fields[$required] = "ignored";
Then check the empty fields and load them with the default value
// ignore the other fields if they are empty; // the actual form has about 10 values here $maybeempty = array("from", "to", "phonenumber"); $optional_defaultvalue = array( "from" => 0, "to" => 0, "phonenumber" => "", ); $optional_filter = array(); foreach($maybeempty as $field){ $required_filter[$requiredfieldname] = array( 'filter' => FILTER_CALLBACK, 'options' => "required", 'flags' => FILTER_NULL_ON_FAILURE ); } $optional_filtered = filter_input_array(INPUT_GET | INPUT_POST, $required_filter); foreach($maybeempty as $field){ if(!isset($optional_filtered[$field])){ $ignore_fields[$field] = "ignored"; // value doesn't matter $returnvalue[$field] = $optional_defaultvalue[$field]; } }
In the last step, I will create an array of checks, custom error messages, and ignore ignore fields to skip empty fields or fields that already had an error:
$validity_filter = array( 'email' => array( 'filter' => FILTER_VALIDATE_EMAIL, 'flags' => FILTER_REQUIRE_SCALAR ), 'from' => array( 'filter' => FILTER_VALIDATE_INT, 'flags' => FILTER_REQUIRE_SCALAR, 'options' => array('min_range' => 1964, 'max_range' => 2009)), 'to' => array( 'filter' => FILTER_VALIDATE_INT, 'flags' => FILTER_REQUIRE_SCALAR, 'options' => array('min_range' => 1964, 'max_range' => 2009)) ); // filter all ignored fields $validity_filter = array_diff_key($validity_filter, $ignore_fields); $validity_filtered = filter_input_array(INPUT_GET | INPUT_POST, $required_filter); foreach($validity_filter as $field => $value){ if($value === false){ // NULL values are checked in a previous step $errors[$field] = $validity_errors[$field]; // show error $returnvalues[$field] = $_REQUEST[$field]; // return original value } else { $returnvalues[$field] = $value; // return filtered value } } // process possible errors and response values