简体   繁体   中英

Contact form with anti-spam field, PHP or JS issue

I have a bootstrap contact form that I added a simple math equation to prevent spam mail. The form is using a contact_me.js to process the form and call the contact_me.php file to validate and send the email. It is also using jqBootstrapValidation.js to validate the form. I used a basic bootstrap template and modified the template for my site, so I did not create the actual form or php (or js).

The form sends emails just fine, but the "human" math equation field that I added is not functioning, as it sends the email regardless if the math answer is correct or not. I know very little of PHP or JS, but I know HTML and CSS quite well - so I know the issue is with the PHP or JS. Can anyone help with what I need to update to fix the issue?

HTML form code:

<div class="form-group col-xs-12 floating-label-form-group controls">
        <label>Email Address</label>
        <input type="email" class="form-control" placeholder="Email Address" id="email" required data-validation-required-message="Please enter your email address.">
        <p class="help-block text-danger"></p>
    </div>
</div>
<div class="row control-group">
    <div class="form-group col-xs-12 floating-label-form-group controls">
        <label>Phone Number</label>
        <input type="tel" class="form-control" placeholder="Phone Number" id="phone" required data-validation-required-message="Please enter your phone number.">
        <p class="help-block text-danger"></p>
    </div>
</div>
<div class="row control-group">
    <div class="form-group col-xs-12 floating-label-form-group controls">
        <label>Message</label>
        <textarea rows="5" class="form-control" placeholder="Message" id="message" required data-validation-required-message="Please enter a message."></textarea>
        <p class="help-block text-danger"></p>
    </div>
</div>
<div class="row control-group">
    <div class="form-group col-xs-12 floating-label-form-group controls">
        <label>Human</label>
        <input type="text" class="form-control" placeholder="2 + 3 = ?" id="human" required data-validation-required-message="Please solve math equation to prove you are human">
        <p class="help-block text-danger"></p>
    </div>
</div>
 <br>
<div id="success"></div>
<div class="row">
    <div class="form-group col-xs-12">
        <button type="submit" class="btn btn-success btn-lg">Send</button>
    </div>
</div>
</form>

Contact_Me.php code:

<?php
// Check for empty fields
if(empty($_POST['name'])        ||
empty($_POST['email'])      ||
empty($_POST['phone'])      ||
empty($_POST['message'])    ||
empty($_POST['human'])  ||
!filter_var($_POST['email'],FILTER_VALIDATE_EMAIL))
{
echo "No arguments Provided!";
return false;
}

//Check if simple anti-bot test is correct
if ($human !== 5) {
   $errHuman = 'Your anti-spam is incorrect';
}   

$name = $_POST['name'];
$email_address = $_POST['email'];
$phone = $_POST['phone'];
$message = $_POST['message'];
$message = $_POST['human'];

// Create the email and send the message
$to = 'info@mysite.com'; // Add your email address inbetween the '' replacing yourname@yourdomain.com - This is where the form will send a message to.
$email_subject = "Portfolio Website Message:  $name";
$email_body = "You have received a new message from your portfolio website contact form.\n\n"."Here are the details:\n\nName: $name\n\nEmail: $email_address\n\nPhone: $phone\n\nMessage:\n$message";
$headers = "From: noreply@mysite.com\n"; // This is the email address the generated message will be from. We recommend using something like noreply@yourdomain.com.
$headers .= "Reply-To: $email_address"; 
mail($to,$email_subject,$email_body,$headers);
return true;            
?>

Contact_me.js code:

$(function() {

$("input,textarea").jqBootstrapValidation({
    preventSubmit: true,
    submitError: function($form, event, errors) {
        // additional error messages or events
    },
    submitSuccess: function($form, event) {
        // Prevent spam click and default submit behaviour
        $("#btnSubmit").attr("disabled", true);
        event.preventDefault();

        // get values from FORM
        var name = $("input#name").val();
        var email = $("input#email").val();
        var phone = $("input#phone").val();
        var message = $("textarea#message").val();
        var human = $("textarea#human").val();
        var firstName = name; // For Success/Failure Message
        // Check for white space in name for Success/Fail message
        if (firstName.indexOf(' ') >= 0) {
            firstName = name.split(' ').slice(0, -1).join(' ');
        }
        $.ajax({
            url: "././mail/contact_me.php",
            type: "POST",
            data: {
                name: name,
                phone: phone,
                email: email,
                message: message,
                human: human
            },
            cache: false,
            success: function() {
                // Enable button & show success message
                $("#btnSubmit").attr("disabled", false);
                $('#success').html("<div class='alert alert-success'>");
                $('#success > .alert-success').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>&times;")
                    .append("</button>");
                $('#success > .alert-success')
                    .append("<strong>Your message has been sent. </strong>");
                $('#success > .alert-success')
                    .append('</div>');

                //clear all fields
                $('#contactForm').trigger("reset");
            },
            error: function() {
                // Fail message
                $('#success').html("<div class='alert alert-danger'>");
                $('#success > .alert-danger').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>&times;")
                    .append("</button>");
                $('#success > .alert-danger').append("<strong>Sorry " + firstName + ", it seems that my mail server is not responding. Please try again later!");
                $('#success > .alert-danger').append('</div>');
                //clear all fields
                $('#contactForm').trigger("reset");
            },
        })
    },
    filter: function() {
        return $(this).is(":visible");
    },
});

$("a[data-toggle=\"tab\"]").click(function(e) {
    e.preventDefault();
    $(this).tab("show");
});
});

// When clicking on Full hide fail/success boxes
$('#name').focus(function() {
$('#success').html('');
});

The jqBootstrapValidation.js is a plugin for automating validation on Bootstrap forms and is located at: http://ReactiveRaven.github.com/jqBootstrapValidation/

To prevent the PHP from sending the mail you need to exit the script before it is called. From your code it appears that

if ($human !== 5) {
    $errHuman = 'Your anti-spam is incorrect';
}  

is where you are told whether the math answer is correct or not. So you need to replace it with:

if ($_POST['human'] != 5) {
    $errHuman = 'Your anti-spam is incorrect';
    return false;
}

Edit

First of all add die($_POST['human']); to your php (it doesn't matter where).

Then in your jquery add a data parameter into the success and error functions. Followed by a console.log(data); like :

function(data) { 
    console.log("Success: "+data);
    ...

Please change the "Success: " respectively.

When you have done these edits run it and have a look at your log.

In the html form I can see no field for name yet it is referenced in both the php code and the javascript. For testing I added this field to my version of your form. The code below is based upon your original and, other than sending the actual mail ( no local mailserver! ), it processes the submission as expected. however, in a couple of places you echo out messages and then return false - does the javascript use this echoed content?

<?php

    session_start();/* required if using session based captcha image */

    /* If the page is accessed by GET etc then display error, otherwise process form input */
    if( $_SERVER['REQUEST_METHOD']=='POST' ){


        function message( $message=false, $errors=array() ){
            if( $message ) return json_encode( array( 'message' => $message, 'errors'=>$errors ) );
        }

        $errors=array();
        $options = array( 'flags' => FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_ENCODE_HIGH );


        /* Filter all submitted fields */
        foreach( $_POST as $field => $value ){
            switch( $field ){
                case 'name': $name=filter_input( INPUT_POST, $field, FILTER_SANITIZE_SPECIAL_CHARS, $options ); break;
                case 'email': $email=filter_input( INPUT_POST, $field, FILTER_VALIDATE_EMAIL ); break;
                case 'phone': $phone=filter_var( filter_input( INPUT_POST, $field, FILTER_SANITIZE_NUMBER_FLOAT ), FILTER_VALIDATE_FLOAT ); break;
                case 'message': $message=filter_input( INPUT_POST, $field, FILTER_SANITIZE_SPECIAL_CHARS, $options ); break;
                case 'human': $human=filter_var( filter_input( INPUT_POST, $field, FILTER_SANITIZE_NUMBER_INT ), FILTER_VALIDATE_INT ); break;
                default:
                    $errors[]='Unknown field: '.$field;
                break;
            }
        }

        /* check each value is acceptable / has a value */
        $variables=array($name,$email,$phone,$message,$human);
        foreach( $variables as $value ){
            if( !isset( $value ) or empty( $value ) ){
                $errors[]='Missing parameter';
            }
        }

        /* Integer test */
        if( floatval( $human )!==floatval( $_SESSION['simple_maths_captcha'] ) ) {
            $errors[]='Anti-Spam verification failed';
        }

        if( !empty( $errors ) ) exit( message( 'Unable to send email', $errors ) );


        $to = 'info@mysite.com';
        $email_subject = "Portfolio Website Message: " . $name;
        $email_body = "You have received a new message from your portfolio website contact form.\n\n
            Here are the details:\n\n
            Name: ".$name."\n\n
            Email: ".$email_address."\n\n
            Phone:".$phone."\n\n
            Message:\n".$message;
        $headers = "From: noreply@mysite.com\n";
        $headers .= "Reply-To: ".$email_address; 

        /* should return either true or false */
        $result = @mail( $to, $email_subject, $email_body, $headers );


        exit( message( 'Your message has been sent: '.$result, $errors ) );


    } else {
        header( 'HTTP/1.0 405 Method Not Allowed', TRUE, 405 );
        $errors[]='Incorrect method';
        exit( message( 'Method not allowed', $errors ) );
    }         
?>

I notice also that there is this line in your javascript code:-

var human = $("textarea#human").val();

As the input type is a standard text field I don't know if it will make any difference but this should be:-

var human = $("input#human").val();

With regards to the actual captcha challenge unless this number changes then it provides very little protection from spammers. Typically one would ( or at least I do ) use PHP to create an image that contains the challenge puzzle and set a session variable which is then tested for once the form is submitted - thus it is different every time.

For example

<?php
    /* captcha.php */
    session_start();
    header('Content-type: image/png');



    function challenge( $full=false, $low1=1, $high1=20, $low2=1, $high2=20 ){
        /* Generate an arithmetic challenge with random numbers and a random method */
        $ops=array( '+','-' );
        if( $full==true ) $ops=array_merge( $ops, array( '/', 'x' ) );

        $numbers=array( rand( $low1, $high1 ), rand( $low2, $high2 ) );
        rsort( $numbers, SORT_NUMERIC );
        $key=rand( 0, count( $ops )-1 );

        $question="{$numbers[0]} {$ops[ $key ]} {$numbers[1]}";

        switch( $ops[ $key ] ){
            case '+': $answer=( $numbers[0] + $numbers[1] ); break;
            case '-': $answer=( $numbers[0] - $numbers[1] ); break;
            case '/': $answer=( $numbers[0] / $numbers[1] ); break;
            case 'x': $answer=( $numbers[0] * $numbers[1] ); break;
        }
        $obj=new stdClass;
        $obj->question=$question;
        $obj->answer=$answer;

        return $obj;
    }

    /* Calculate question and answer */
    $captcha=call_user_func( 'challenge', false, 1, 50, 1, 30 );
    $question=$captcha->question;
    $answer=$captcha->answer;

    /* Set the session variable that will be tested for */
    $_SESSION['simple_maths_captcha']=$answer;

    /* Render an image with this challenge */
    $oImg = @imagecreate( 80, 30 ) or die("unable to create image");
    $background = imagecolorallocate( $oImg, 255, 255, 255 );
    $colour = imagecolorallocate( $oImg, 0, 0, 0 );

    imagestring( $oImg, 4, 5, 5,  $question, $colour );
    imagepng( $oImg );
    imagedestroy( $oImg );
?>

If you saved the above code as "captcha.php" you could then refer to that image in your html using a standard image tag.

<img src='captcha.php' alt='' width=80 height=30 />

( or, by using a rewrite rule in your .htaccess file similar to the following you could refer to it as if it were a standard png image. Experienced coders would probably identify this as a php generated image but... )

htaccess rewrite
----------------
RewriteRule ^images/maths\.png$ /captcha.php [NC,L]

<img src='/images/maths.png' alt='' width=80 height=30 />

Within your html you would still need the text input field to recieve the answer, having added the image in the appropriate place within the form and then test in php for the correct answer. So, rather than:-

    if( intval( $human )!==5 ) {
        echo 'Anti-Spam verification failed';
        return false;
    }

You could test like this:-

    if( floatval( $human )!==floatval( $_SESSION['simple_maths_captcha'] ) ) {
        echo 'Anti-Spam verification failed';
        return false;
    }

I notice that within the jqBootstrapValidation.js code that the ajax function has a datatype set as json and the callback function has a data parameter. I changed the above code to return json if there are errors and a json success message if the form processing goes ok. I do not use jQuery so perhaps I misunderstood the javascript code but I wonder if the callback is expecting a json encoded response from the form processing? No doubt someone well versed in jQuery can answer that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM