Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using PHP Filter function to validate, but ignore empty non-required fields

I want to use the PHP Filter functions to quickly filter a form and show feedback to the user. Some of the fields in my form are required, some are not.

I am going to use filter_input_array() to filter all my fields. I will pass the data through in multiple runs. In this way, I will be able to display multiple error messages.

I have one problem: how can I ignore empty fields that are not required? I didn't see a filter for it.

Update: Clarification of the requirements for the filters and error messages:

I want to use filters to check:

  1. If all required fields are filled in
  2. If optional fields are filled in; if not, ignore for the rest of the process
  3. If fields like e-mail, phonenumber, etc. are filled in.

I want to display error messages for every type of error, with a maximum of 1 error message per field.

like image 521
Scharrels Avatar asked Aug 08 '09 21:08

Scharrels


People also ask

What is Filter_var function in PHP?

The filter_var() function filters a variable with the specified filter. This function is used to both validate and sanitize the data. Syntax :- filter_var(var, filtername, options)

What is Filter_validate_email?

Definition and Usage The FILTER_VALIDATE_EMAIL filter validates an e-mail address.


3 Answers

The filter_xyz_array() functions will return NULL for an element that does not exist in the input array, e.g.

<?php

$args = array(
    'foo'    => array(
        'filter'    => FILTER_VALIDATE_INT,
        'flags'     => FILTER_REQUIRE_ARRAY,
        'options'   => array('min_range' => 1, 'max_range' => 4)
    ),
    'bar'   => array(
        'filter' => FILTER_VALIDATE_INT,
        'flags'  => FILTER_REQUIRE_SCALAR
    )
);

$input = array(
    'foo'=>array(1,2,3,4)
);

$filtered = filter_var_array($input, $args);
var_dump($filtered);

prints

array(2) {
  ["foo"]=>
  array(4) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
    [3]=>
    int(4)
  }
  ["bar"]=>
  NULL
}

isset() returns false for a variable/array element that contains NULL. You can use that to ignore the elements that are set to NULL by the filter functions.
Depending on what you're filtering and the structure of the array returned by the filter function you can even use array_filter() the "clean up" the array.

like image 98
VolkerK Avatar answered Nov 14 '22 23:11

VolkerK


PHP filters: Handling optional values / optional form inputs with filter_input_array() filter function.

I'll demonstrate a simple way of how to handle optional fields or form inputs when working with PHP filters. The rule of thumb is:

  1. Filter ALL form inputs, required & optional. Don't leave out optional fields in your filter.
  2. Use the === comparison operator to differentiate between FALSE, NULL, "" and 0 values

Sample code for a simple contact form with 4 required and 4 optional inputs is shown below

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST"){
/*set validation control variable*/
$input_error_flag = true;

/*set form input validation filters*/
$form_filter = array(
    'first_name'        =>  FILTER_SANITIZE_STRING,
    'middle_name'       =>  FILTER_SANITIZE_STRING,
    'last_name'         =>  FILTER_SANITIZE_STRING,
    'email_address'     =>  FILTER_SANITIZE_EMAIL,
    'postal_address'    =>  FILTER_SANITIZE_NUMBER_INT,
    'street_address'    =>  FILTER_SANITIZE_STRING,
    'telephone_number'  =>  FILTER_SANITIZE_NUMBER_INT,
    'mobile_number'     =>  FILTER_SANITIZE_NUMBER_INT,
);

/*list optional fields or optional form inputs in array*/
$optional_fields = array(
    'middle_name'       => "",  'postal_address'    => "",
    'street_address'    => "",  'mobile_number'     => "",
    );

/*set error display message of each required element*/
$error_description = array(
    'first_name'        =>"Missing or incorrect First Name",
    'last_name'         =>"Missing or incorrect Last Name",
    'email_address'     =>"Missing or incorrect Email Address",
    'telephone_number'  =>"Missing or incorrect Telephone Number",
    );

/*sanitize all form inputs against form_filter*/
$form_data = filter_input_array(INPUT_POST, $form_filter);

/*check form inputs for filter validation errors*/
foreach ($form_data as $form_input => $value){
    /*check if filter failed (false), input not defined (null) or input missing ("")
    * and insert name of form input element into $invalid_array for error display
    */
    if($value === FALSE || $value === NULL || $value == ""){
        /*exclude error display for optional items with empty values*/
        if(!(array_key_exists($form_input, $optional_fields) && $value == "")){
            $invalid_inputs[] = $form_input;
        }
    }
}

/*unset filter validation control variable if no errors*/
if(empty ($invalid_inputs))
                $input_error_flag = false;

/*your calls to SQL functions for INSERT or UPDATE statements go here*/
if(!$input_error_flag){
    functionname::getInstance()->insert_contact_details($form_data);
}
}
?>

And finally the html form with the error display section

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <form action="sample.php" method="POST" id="sample">
    <label for="first_name">First Name*</label>
    <input type="text" name="first_name" id="first_name"
           value="<?php echo $form_data['first_name']; ?>"/><br/>
    <label for="middle_name">Middle Name</label>
    <input type="text" name="middle_name" id="middle_name"
           value="<?php echo $form_data['middle_name']; ?>"/><br/>
    <label for="last_name">Last Name*</label>
    <input type="text" name="last_name" id="last_name"
           value="<?php echo $form_data['last_name']; ?>"/><br/>
    <label for="email_address">Email Address*</label>
    <input type="text" name="email_address" id="email_address"
           value="<?php echo $form_data['email_address']; ?>"/><br/>
    <label for="postal_address">Postal Address</label>
    <input type="text" name="postal_address" id="postal_address"
           value="<?php echo $form_data['postal_address']; ?>"/><br/>
    <label for="street_address">Street Address</label>
    <input type="text" name="street_address" id="street_address"
           value="<?php echo $form_data['street_address']; ?>"/><br/>
    <label for="telephone_number">Telephone Number*</label>
    <input type="text" name="telephone_number" id="telephone_number"
           value="<?php echo $form_data['telephone_number']; ?>"/><br/>
    <label for="mobile_number">Mobile Number</label>
    <input type="text" name="mobile_number" id="mobile_number"
           value="<?php echo $form_data['mobile_number']; ?>"/><br/>
    <input type="submit" name="submit" value="submit"><br/>
        <?php
            //display input validation errors on your html form
            if ($input_error_flag){
                foreach($invalid_inputs as $key => $form_input){
                    if(array_key_exists($form_input, $error_description)){
                        echo $error_description[$form_input]."<br/>";
                    }
                }
            }
        ?>
    </form>
  </body>
</html>
like image 26
Alphonse Avatar answered Nov 14 '22 22:11

Alphonse


I ended up using a custom solution inspired by the answer of @VolkerK. I should have stated clearer what I wanted. I've update my question with this information.

I'm still looking for an easier solution.

First, I made some result arrays:

// errors to display
$errors = array();
// fields to ignore in the validation step
$ignore_fields = array();
// return values after validation
$returnvalues = array();

I first filtered for 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"; // value doesn't matter
  }
}

Then check for the empty fields and load them with a standard 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 final step, I will build a validation array, custom error messages and ignore the 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
like image 31
Scharrels Avatar answered Nov 15 '22 00:11

Scharrels