Data input error messages display in Form Validation


#1

I am trying to improve my form for the form validation. I do not display any result if the data is incorrectly submitted or when from all input fields even if one of them is missing. But I am displaying error message below like for input field like “email not correct format” and same for other fields (checkbox group and date field). I want to help the user get a better understanding of what they may have done wrong if their input is rejected. How shall I do this? I am thinking if any one input is wrong then I display message in detail and if all inputs are missing but I don’t understand how to do this.
Thanks in advance.

Here is my php file for validation:

<?php
// Global result of form validation
$valid = false;
// Global array of validation messages. For valid fields, message is ""
$val_messages = Array();

// Output the results if all fields are valid.
function the_results()
{
  global $valid;

  if($_SERVER["REQUEST_METHOD"]=="POST")
  { 
    
    if($valid == true){
        echo '<div class="results">'.'<div class="result-text">'."Your email address is ". $_POST['email'].'</div>'.'</div>';

        //For checkboxes selected values
        echo'<div class="results">'.'<div class="result-text">'."<ul>";
         for($i=0;$i<count($_POST["animals"]);$i++){
            echo "<li>{$_POST["animals"][$i]}</li>";
         }
        echo "</ul>".'</div>'.'</div>';

        echo '<div class="results">'.'<div class="result-text">'."<p> Your favourite date is ". $_POST['date']. "</p>".'</div>'.'</div>';
    } else{
        echo " ";
    }
  }
}

// Check each field to make sure submitted data is valid. If no boxes are checked, isset() will return false
function validate()
{
    global $valid;
    global $val_messages;
   
    // if email is valid, push "", else push "email is not valid"

    if($_SERVER['REQUEST_METHOD']== 'POST')
    {
      // Use these patterns to check email and date, or come up with your own.
      // email: '#^(.+)@([^\.].*)\.([a-z]{2,})$#'
      // date: '#^\d{4}/((0[1-9])|(1[0-2]))/((0[1-9])|([12][0-9])|(3[01]))$#'

       if(isset($_POST['email']) == true && isset($_POST['date']) == true){

         $emailValid = false;
         $dateValid = false;
         $animalValid = false;

          if(!preg_match('#^(.+)@([^\.].*)\.([a-z]{2,})$#', $_POST['email'])){
            $emailValid = false;
            $val_messages['email'] = "email not correct format";
          }
          else {
            $emailValid=true;
            $val_messages['email'] = "";
          }

          if(!preg_match('#^\d{4}/((0[1-9])|(1[0-2]))/((0[1-9])|([12][0-9])|(3[01]))$#', $_POST['date'])){
             $dateValid = false;
             $val_messages['date'] = "please enter a valid date in the format yyyy/mm/dd";
          } else{
              $dateValid = true;
              $val_messages['date'] = "";
          }

          if(!empty($_POST['animals'])){
            //Counting number of checked checkboxes
            $checked_count = count($_POST['animals']);
              if($checked_count >= 3){
                $animalValid = true;
                $val_messages['animals'] = "";
              } else{
                $animalValid = false;
                $val_messages['animals'] = "please choose atleast three animals";
              }
            }

          if(isset($_POST['animals']) == false){
             $animalValid = false;
             $val_messages['animals'] = "please choose atleast three animals";
          }

          if($emailValid == true && $dateValid == true && $animalValid == true){
            $valid = true;
          }
       }
    }
}

// Display error message if field not valid. Displays nothing if the field is valid.
function the_validation_message($type) {

  global $val_messages;

  if($_SERVER['REQUEST_METHOD'] == 'POST')
  {
     if($type == 'email'){
        echo "<div class = 'failure-message'>" .$val_messages['email']."</div>";
     } else if($type == 'animals'){
        echo "<div class = 'failure-message'>" .$val_messages['animals']. "</div>";
     } else if($type == 'date'){
        echo "<div class = 'failure-message'>" .$val_messages['date']. "</div>";
     } 
  }
}

#2

You start with an empty error array : $error = [ ];
Trim the POST array
Then you add each error to the error array as it happens like so

    if (empty($_POST['username']))
    {
        $error['username'] = 'Username Required.';
    }
    if (empty($_POST['password']))
    {
        $error['password'] = 'Password Required.';
    }

Then check if the array is empty or not. If it is not empty, display all the errors by looping over the error array.

if ($error){
// There are errors. Handle the error display
} else{
//process form
}

#3

Hello @benanamen,
I do not understand by trimming the POST array. What do u mean by that?


#4

http://php.net/manual/en/function.trim.php

If a user enters a blank space in the form field, the field is not empty so it will pass a validation check for empty. By removing blank spaces you can make sure a user is actually submitting something other thank a blank.


#6

Oh I see. ok :slightly_smiling_face:
The validation is now working.
Thank You


#7

I’ll go one further:

$required = [
    'username',
    'password',
];

foreach($required as $val) {
    if(!isset($_POST[$val])) {
        $error[$val] = ucfirst($val) . ' Required';
    }
}

#8

Very nice @astonecipher.

I see your further and raise you another further. Add an array (whitelist) of acceptable/expected fields. If a submitted field is not in your whitelist, error out, something fishy going on.

One little problem though. As is, a user could submit a blank space and it will pass the required validation check. As I posted in this thread, you should trim the POST array and then check for empty. The foreach should then be modified as so…

foreach($required as $val) {
    if(empty($_POST[$val])) {
        $error[$val] = ucfirst($val) . ' Required';
    }

A little something (This does not have the empty check I mentioned)

<?php

if($_SERVER['REQUEST_METHOD'] == 'POST'){

$allowedFields = array(
    'firstname'
);

$requiredFields = array(
    'firstname' => 'First name is required.',
);

$errors = [];

// fetch required data
// array_intersect_key - Computes the intersection of arrays using keys for comparison
// array_intersect_key() returns an array containing all the entries of array1 which have keys that are present in all the arguments.
$requiredData = array_intersect_key( $_POST, $requiredFields );

// run checks ( complete ? solid ? )
// array_keys - Return all the keys or a subset of the keys of an array
$isCompleteRequest = array_keys($requiredData) === array_keys($requiredFields);
$isSolidRequest = array_keys($_POST) === $allowedFields;

if ( $isCompleteRequest && $isSolidRequest ) {
// Process Form
}
else {

    // general validation failed, pull errors
    // array_diff_key — Computes the difference of arrays using keys for comparison
    // Returns an array containing all the entries from array1 whose keys are absent from all of the other arrays.
    $errors = array_diff_key( $requiredFields, $requiredData );

    // add general Errors
    if ( !$isSolidRequest ) {
        $errors[] = 'The last request contains unwanted fields.';
    }

}

var_dump(array_keys($_POST));
var_dump($allowedFields);
var_dump($isSolidRequest);
var_dump($errors);
}
?>

<form method="post">
 <input name="firstname">
  <input name="HackedFormField">
 <input  type="submit" value="Submit">
</form>

#9

Hello @astonecipher,
What does the ucfirst($val) .'Required; mean here?
I don’t understand this part


#10

Wow nice this is a complicated solution and some of the code is new to me :slight_smile:


#11

ucfirst capitalizes the first letter. So, ‘username’ be comes Username, and the the Required is appended on, without having to write it all out.


#12

Oh I see. I understood it. Thank You :slight_smile:


#13

Here is a slightly modified version of @astonecipher’s code. This will handle names with underscore separators. Take note of the comma first formatting as well. One thing I forget to mention before is, that in a properly coded form the fields will always be isset when submitted even if nothing is entered in the field so the code using isset will not work which is another reason to trim the POST array and check for empty.

<?php declare(strict_types=1);

// Assumes POST array has been trimmed

$required = [
      'username'
    , 'password'
    , 'first_name'
    , 'last_name'
];

foreach($required as $val) {
    if(empty($_POST[$val])) {
        $msg = ucwords(str_replace("_"," ",$val));
        $error[$val] =$msg . ' Required';
    }
}

echo '<pre>', print_r($error, true), '</pre>';