Mosaic Mosaic - 5 months ago 9
PHP Question

PHP Show error messages in order and re-display correct fields

I have an email form that checks three fields, name, valid email and comments. But the way it's set up now, since name and comments are in one function it first checks name and comments even if email is not valid, how can I re-write it so it checks the fields in order. Also, I would like to re-display the fields that have no errors, so the user doesn't have to type again. Please help. Thanks

<?php
$myemail = "comments@myemail.com";
$yourname = check_input($_POST['yourname'], "Enter your name!");
$email = check_input($_POST['email']);
$phone = check_input($_POST['phone']);
$subject = check_input($_POST['subject']);
$comments = check_input($_POST['comments'], "Write your comments!");

if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/", $email))
{
show_error("Enter a valid E-mail address!");
}

exit();

function check_input($data, $problem='')
{
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
if ($problem && strlen($data) == 0)
{
show_error($problem);
}
return $data;
}

function show_error($myError)
{
?>
<!doctype html>
<html>
<body>
<form action="myform.php" method="post">
<p style="color: red;"><b>Please correct the following error:</b><br />
<?php echo $myError; ?></p>
<p>Name: <input type="text" name="yourname" /></P>
<P>Email: <input type="text" name="email" /></p>
<P>Phone: <input type="text" name="phone" /></p><br />
<P>Subject: <input type="text" style="width:75%;" name="subject" /></p>
<p>Comments:<br />
<textarea name="comments" rows="10" cols="50" style="width: 100%;"></textarea></p>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
<?php
exit();
}
?>

Answer

First off, I would suggest you validate ALL of the fields at once, and display all appropriate error messages on the form. The primary reason is that it can be bad user experience if they have to submit your form a whole bunch of times because they have to address one error at a time. I'd rather correct my email address, password, comments, and selection in one try instead of fixing one at a time just to reveal what the next error is.

That said, here are some pointers on validating the form like you want. This is typically how I approach a form doing what you want to do. This assumes your form HTML and form processor (PHP) are together in the same file (which is what you have now). You can split the two, but the methods for doing that can be a bit different.

  • Have one function or code block that outputs the form and is aware of your error messages and has access to the previous form input (if any). Typically, this can be left outside of a function and can be the last block of code in your PHP script.
  • Set up an array for error messages (e.g. $errors = array()). When this array is empty, you know there were no errors with the submission
  • Check to see if the form was submitted near the top of your script before the form is output.
  • If the form was submitted, validate each field one at a time, if a field contained an error, add the error message to the $errors array (e.g. $errors['password'] = 'Passwords must be at least 8 characters long';)
  • To re-populate the form inputs with the previous values, you have to store the entered values somewhere (you can either just use the $_POST array, or sanitize and assign the $_POST values to individual variables or an array.
  • Once all the processing is done, you can check for any errors to decide whether the form can be processed at this point, or needs new input from the user.
  • To do this, I typically do something like if (sizeof($errors) > 0) { // show messages } else { // process form }
  • If you are re-displaying the form, you simply need to add a value="" attribute to each form element and echo the value that was submitted by the user. It is very important to escape the output using htmlspecialchars() or similar functions

With those things in place, here is some re-work of your form to do that:

<?php
$myemail = "comments@myemail.com";
$errors  = array();
$values  = array();
$errmsg  = '';

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    foreach($_POST as $key => $value) {
        $values[$key] = trim(stripslashes($value)); // basic input filter
    }

    if (check_input($values['yourname']) == false) { 
        $errors['yourname'] = 'Enter your name!';
    }

    if (check_input($values['email']) == false) {
        $errors['email'] = 'Please enter your email address.';
    } else if (!preg_match('/([\w\-]+\@[\w\-]+\.[\w\-]+)/', $values['email'])) {
        $errors['email'] = 'Invalid email address format.';
    }

    if (check_input($values['comments']) == false) {
        $errors['comments'] = 'Write your comments!';
    }

    if (sizeof($errors) == 0) {
        // you can process your for here and redirect or show a success message
        $values = array(); // empty values array
        echo "Form was OK!  Good to process...<br />";
    } else {
        // one or more errors
        foreach($errors as $error) {
            $errmsg .= $error . '<br />';
        }
    }
}

function check_input($input) {
    if (strlen($input) == 0) {
        return false;
    } else {
        // TODO: other checks?

        return true;
    }
}
?>
<!doctype html>
<html>
<body>
<form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="post">
 <?php if ($errmsg != ''): ?>
 <p style="color: red;"><b>Please correct the following errors:</b><br />
 <?php echo $errmsg; ?>
 </p>
 <?php endif; ?>

 <p>Name: <input type="text" name="yourname" value="<?php echo htmlspecialchars(@$values['yourname']) ?>" /></P>
 <P>Email: <input type="text" name="email" value="<?php echo htmlspecialchars(@$values['email']) ?>" /></p>
 <P>Phone: <input type="text" name="phone" value="<?php echo htmlspecialchars(@$values['phone']) ?>"/></p><br />
 <P>Subject: <input type="text" style="width:75%;" name="subject" value="<?php echo htmlspecialchars(@$values['subject']) ?>" /></p>
 <p>Comments:<br />
 <textarea name="comments" rows="10" cols="50" style="width: 100%;"><?php echo htmlspecialchars(@$values['comments']) ?></textarea></p>
 <p><input type="submit" value="Submit"></p>
</form>
</body>
</html>

I have a more advanced example which you can see here that may give you some guidance as well.

Hope that helps.

Comments