how to combine form validation and phpmailer …?

2019-08-01 22:05发布

问题:

I am trying to email a basic contact form using PHPMailer.

This form works for me:

 <?php

$first_name = $_POST['first-name'];
$last_name = $_POST['last-name'];
$email = $_POST['email'];
$message = nl2br($_POST['message']);

require 'PHPMailerAutoload.php';

$mail = new PHPMailer;

//$mail->SMTPDebug = 3;                               // Enable verbose debug output

$mail->isSMTP();                                      // Set mailer to use SMTP
$mail->Host = '';  // Specify main and backup SMTP servers
$mail->SMTPAuth = true;                               // Enable SMTP authentication
$mail->Username = '';                 // SMTP username
$mail->Password = '';                           // SMTP password
$mail->SMTPSecure = 'tls';                            // Enable TLS encryption, `ssl` also accepted
$mail->Port = 587; 

$mail->addReplyTo( $email, $first_name );
$mail->addAddress( $email, $first_name );
$mail->addAddress( 'blah@fake.org', 'Staff' );
$mail->From = 'blah@fake.org';
$mail->FromName = 'Staff';


$mail->isHTML(true);                                  // Set email format to HTML

$mail->Subject = 'Hotel Room Request';
$mail->Body    = $message; 

$mail->AltBody = 'To view the message, please use an HTML compatible email viewer!';

if(!$mail->send()) {
    header('location: a_url_here');

} else {
    header('location: a_url_here');

}

Now, I'm trying to combine it with error-checking. Don't know how to combine it and still make it work. This is what I have so far, and it blanks out upon submittal. I wasn't sure where to put check_input function, so I put it in the else part at the bottom. How do I make this form functional so not only does it validate user's input but email it out?

<?php

$first_name = check_input($_POST['first-name'], "Please enter your name");
$last_name = check_input($_POST['last-name'], "Please enter your last name");
$email = check_input($_POST['email'], "Please enter your email address");
$message = check_input(nl2br($_POST['message']), "Please enter your message");


require 'PHPMailerAutoload.php';

$mail = new PHPMailer;

//$mail->SMTPDebug = 3;                               // Enable verbose debug output

$mail->isSMTP();                                      // Set mailer to use SMTP
$mail->Host = '';  // Specify main and backup SMTP servers
$mail->SMTPAuth = true;                               // Enable SMTP authentication
$mail->Username = '';                 // SMTP username
$mail->Password = '';                           // SMTP password
$mail->SMTPSecure = 'tls';                            // Enable TLS encryption, `ssl` also accepted
$mail->Port = 587; 

$mail->addReplyTo( $email, $first_name );
$mail->addAddress( $email, $first_name );
$mail->addAddress( 'blah@fake.org', 'Staff' );
$mail->From = 'blah@fake.org';
$mail->FromName = 'Staff';


$mail->isHTML(true);                                  // Set email format to HTML

$mail->Subject = 'Hotel Room Request';
$mail->Body    = $message; 

$mail->AltBody = 'To view the message, please use an HTML compatible email viewer!';

if(!$mail->send()) {
    header('location: a_url_here');

} else {

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

}
?>

回答1:

Create so-called validator class:

class Validator {

    // set of rules for validator
    // syntax: <field-name> => '<list-of-rules, joined-with-pipe>',
    protected $rules = [
        'first-name' => 'required',
        'last-name' => 'required',
        'message' => 'required',
        'email' => 'required|email',
    ];

    // message to show if concrete field-rule failed
    // ":field" will be replaced with field actual name
    protected $messages = [
        'required' => 'Field :field is required',
        'nonzero' => 'Field :field must not be zero'
        'email' => 'Field :field must represent an emai address'
    ]; 

    protected $errors;

    // call this to validate provided $input
    function validate($input) {

        $errors = [];

        // for each defined field-ruleset
        foreach ($this->rules as $field => $rules) {
            $rules = explode('|', $rules);
            // for each rule
            foreach ($rules as $rule)
                // call function with name "checkNameofrule"
                if (!$this->{"check" . ucfirst($rule)}($input, $field))
                    // memorize error, if any
                    $errors[$field][] = $this->error($field, $rule);
        }

        // validation passed if there are no errors
        return !($this->errors = $errors);
    }

    function errors() {
        return $this->errors;
    }

    function error($field, $error) {
        return str_replace(':field', $field, $this->messages[$field]);
    }

    // check for required fields
    function checkRequired($input, $field) {
        if (!isset($input[$field]))
            return false;

        return trim(htmlspecialchars(stripslashes($input[$field]))) != '';
    }

    // check for valid email
    function checkEmail($input, $field) {
        return !!preg_match('#.+@[^.]+\..+#', @$input[$field]);
    }

    // other custom checks
    function checkNonzero($input, $field) {
        return intval(@$input[$field]) != 0;
    }

}

And use it like this:

$validator = new Validator();

// validating...
if (!$validator->validate($_POST)) {
    // looks like there are errors in input

    echo "<div class=\"errors\">";
    echo "<b>Looks like you have errors in input:</b><br />";
    foreach ($validator->errors() as $field => $errors) {
        foreach ($errors as $error)
            echo "<p>{$error}</p>";
    }
    echo "</div>";

} else {

    // input had passed validation, send email...

    require 'PHPMailerAutoload.php';

    $mail = new PHPMailer;

    ...

    if(!$mail->send()) {
        header('location: a_url_here');
    } else {
        header('location: a_url_here');
    }

}


回答2:

You should not validate and render the form in one file. It leads to poor maintainability and mixes responsibilities in a nasty way. Try structuring your project like so:

form.php
validate-and-send.php

The form contains <form action=validate-and-send.php ...><input .... The other file contains logic for validating and sending. Something like this:

<?php
$email = filter_var($_REQUEST['email'], FILTER_VALIDATE_EMAIL);

if ($email) {
    ....
}

if (/*all fields valid*/) {
   // phpmailer code
} else {
   // redirect back to form
}

The tricky part is redirect back to form. You can either redirect with a header and set all valid fields through get-parameters Location form.php?name=validname or you can stuff them in $_SESSION and output them in the form from session.

Taking it one step farther would be submitting via AJAX and responding with the validation result as JSON, for example. So the flow would be like

1. form.submit() -> ajax -> validate-and-send.php
2a. validate-and-send.php -> "OK" -> form.php
2b. validate-and-send.php -> JSON: { errors: [ {reason: "bad name"}, {reason: "bad email"}]} 
      -> form.php
3. Display what happened with JS.