views:

675

answers:

2

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.

+4  A: 

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.

VolkerK
+2  A: 

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
Scharrels