简体   繁体   中英

PHP Mailer 6 Contact Form sends message and attachments, but reCaptcha V2 is ignored

I was hoping I could solve this myself, but nothing I've tried works.

I've managed to cobble together a contact form using PHPMailer with the option of adding multiple attachments which works perfectly.

However, when I try adding a reCaptcha V2, it gets completely ignored and the contact form submits regardless of whether the Captcha is ticked or not.

I've tried numerous different methods posted online, but these just stop the form from submitting at all.

Could someone please advise where I'm going wrong:

HTML part of form:

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>Contact Us:</title>

<link rel="canonical" href="" />
<link rel="stylesheet" type="text/css" href="css/normalise.css" />
<link rel="stylesheet" type="text/css" href="css/style.css" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>

<body>

  <div class="contact_form_container">
    All fields marked with <span class="required">*</span> are required
    <form id="form" action="mail-script.php" method="post" enctype="multipart/form-data">
    
    <div class="elem-group">
      <label class="form_label">Name <span class="required">*</span></label>
      <input class="form-control form-control-name form_field" type="text" name="name" required>
    </div>
    
    <div class="elem-group">
      <label class="form_label">Company</label>
      <input class="form-control form-control-subject form_field" type="text" name="company">
    </div>
    
    <div class="elem-group">
      <label class="form_label">Email Address <span class="required">*</span></label>
      <input class="form-control form-control-email form_field" type="email" name="email" required>
    </div>
    
    <div class="elem-group">
      <label class="form_label">Phone Number</label>
      <input class="form-control form-control-phone form_field" type="tel" name="phone" pattern="\d*">
    </div>
    
    <div class="elem-group">
      <label class="form_label">Message <span class="required">*</span></label>
      <textarea name="message" rows="7" required class="form-control form-control-message form_field">
      </textarea>
    </div>
    
    <div class="elem-group">
      <label class="form_label">Upload Your Files</label> 
      <input type="file" name="attachment[]" class="form-control" multiple>
    </div>
      
    <div class="elem-group">
      <label class="form_label">&nbsp;</label>
      <div class="g-recaptcha" data-sitekey="xxxxxx"></div>    
    </div>                         
    
    <div class="elem-group">
      <label class="form_label cft">&nbsp;</label>
      <button class="btn-primary button" type="submit" value="Send" name="submit" >Send Message</button>
    </div>

    </form>
  </div>
      
</body>
</html>

PHP

<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require './src/Exception.php';
require './src/PHPMailer.php';
require './src/SMTP.php';

class CaptchaTest
{
  private $captchaSecretKey = 'XXX';

  //call this function and pass in the response value from the form in order to get Google to test the captcha. Will return true or false.
  public function testCaptchaResponse($captchaResponse)
  {
    //generate URL as per Google's documentation
    $createGoogleUrl = 'https://www.google.com/recaptcha/api/siteverify?secret='.urlencode($this->captchaSecretKey).'&response='.urlencode($captchaResponse);
    //send request to Google and get back the raw JSON response.
    $verifyRecaptcha = $this->sendHttpRequest($createGoogleUrl);
    //decode the JSON into a PHP array so we can examine individual data items within it
    $decodeGoogleResponse = json_decode($verifyRecaptcha,true);

    //examine the response from Google and return true/false accordingly.
    if($decodeGoogleResponse['success'] == 1) return true;
    else return false;
  }
  
  //send a HTTP request to the specified URL using cURL
  private function sendHttpRequest($url)
  {
    $ch = curl_init();
    $getUrl = $url;
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_URL, $getUrl);
    curl_setopt($ch, CURLOPT_TIMEOUT, 80);
    
    $response = curl_exec($ch);
    curl_close($ch);
    return $response;
  }
}


//check form button and captcha field were submitted
if(isset($_POST['submit'], $_POST['g-recaptcha-response'])) {

    //test the captcha
    $cTest = new CaptchaTest();
    $captchaResult = $cTest->testCaptchaResponse($_POST['g-recaptcha-response']); }

    if ($captchaResult == true) {

        $mail = new PHPMailer(true);
        $mail->SMTPDebug = 0;
        $mail->Host = 'in-v3.mailjet.com';
        $mail->SMTPAuth = true;
        $mail->Username = 'XXX';
        $mail->Password = 'XXX';
        $mail->SMTPSecure = 'tls';
        $mail->Port = 587;
        $mail->setFrom($_POST['email'], $_POST['name']);
        $mail->addAddress('XXX@XXX.co.uk');
        $mail->addReplyTo($_POST['email'], $_POST['name']);
        

        //Attach multiple files one by one
        for ($ct = 0; $ct < count($_FILES['userfile']['tmp_name']); $ct++) {
          $uploadfile = tempnam(sys_get_temp_dir(), hash('sha256', $_FILES['userfile']['name'][$ct]));
          $filename = $_FILES['userfile']['name'][$ct];
    
          if (move_uploaded_file($_FILES['userfile']['tmp_name'][$ct], $uploadfile)) {
            $mail->addAttachment($uploadfile, $filename);
          } 
        }

        $mail->isHTML(true);
        $mail->Subject = 'Website Enquiry';
        $mail->Body = "<p>You received an enquiry from:</p>
          <b>Name:</b>  $_POST[name]<br><br>
          <b>Company:</b>  $_POST[company]<br><br>
          <b>Phone Number:</b>  $_POST[phone]<br><br>
          <b>E-Mail:</b> $_POST[email]<br><br>
          <b>Message:</b> $_POST[message]";
          
        try {
             $mail->send();
header('Location: thank.html');
exit('Redirecting you to thank.html');
        } catch (Exception $e) {
            echo "Your message could not be sent! PHPMailer Error: {$mail->ErrorInfo}";
        }
    } 
    else
    {
        echo "Captcha failed, please try again";
    }
    
?>

Thanks in advance

At the moment your PHP code doesn't test the captcha value at all. As per Google's documentation you need to send the submitted captcha value (provided in your form's POST data) to Google's server so they can verify it, and give you a yes/no response as to whether the user passed the test or not. Once you know that, you can decide whether to proceed with sending the email or not.

I suggest encapsulating this functionality into a small class which you can then call from your main code flow, to perform the check. Something like this:

class ReCaptchaTest
{
  private $captchaSecretKey = 'XXXXXXXXX';

  //call this function and pass in the response value from the form in order to get Google to test the captcha. Will return true or false.
  public function testCaptchaResponse($captchaResponse)
  {
    //generate URL as per Google's documentation
    $createGoogleUrl = 'https://www.google.com/recaptcha/api/siteverify?secret='.urlencode($this->captchaSecretKey).'&response='.urlencode($captchaResponse);
    //send request to Google and get back the raw JSON response.
    $verifyRecaptcha = $this->sendHttpRequest($createGoogleUrl);
    //decode the JSON into a PHP array so we can examine individual data items within it
    $decodeGoogleResponse = json_decode($verifyRecaptcha,true);

    //examine the response from Google and return true/false accordingly.
    if($decodeGoogleResponse['success'] == 1) return true;
    else return false;
  }
  
  //send a HTTP request to the specified URL using cURL
  private function sendHttpRequest($url)
  {
    $ch = curl_init();
    $getUrl = $url;
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_URL, $getUrl);
    curl_setopt($ch, CURLOPT_TIMEOUT, 80);
    
    $response = curl_exec($ch);
    curl_close($ch);
    return $response;
  }
}

Then in your main code, first check that the captcha value was definitely submitted, and then run the check before you try to do anything with the email:

//check form button and captcha field were submitted
if(isset($_POST['submit'], $_POST['g-recaptcha-response'])) {

  //test the captcha
  $cTest = new CaptchaTest();
  $captchaResult = $cTest->testCaptchaResponse($_POST['g-recaptcha-response']);

  if ($captchResult == true) {
    // go ahead with all your email code here
  }
  else
  {
    echo "Captcha failed, please try again";
}
else
{
  echo "Please submit the form with all required fields";
}

Credit to this tutorial for the inspiration. Getting this code working also relies on you completing all the setup steps in your Google developer account in order to register your site with reCaptcha (as shown in the tutorial).

@ADyson I did as you suggested and had a detailed look for errors when I got the opportunity. The problem simply proved to be a missing 'a' in '$captchaResult'.

Thanks so much for getting me this far, I'm extremely grateful for your efforts and advice, as there's no way I could have achieved this on my own.

If it's helpful for anyone else, the working PHP code is below (I've also managed to tag on the feature where submitting the form without ticking the reCaptacha throws up an error message in a pop-up box, then sends you back to the completed form to try again):

'''

<?php

    use PHPMailer\PHPMailer\PHPMailer;
    use PHPMailer\PHPMailer\Exception;

    require './src/Exception.php';
    require './src/PHPMailer.php';
    require './src/SMTP.php';

class CaptchaTest
{
  private $captchaSecretKey = 'XXXXX';

  //call this function and pass in the response value from the form in order to get Google to test the captcha. Will return true or false.
  public function testCaptchaResponse($captchaResponse)
  {
    //generate URL as per Google's documentation
    $createGoogleUrl = 'https://www.google.com/recaptcha/api/siteverify?secret='.urlencode($this->captchaSecretKey).'&response='.urlencode($captchaResponse);
    //send request to Google and get back the raw JSON response.
    $verifyRecaptcha = $this->sendHttpRequest($createGoogleUrl);
    //decode the JSON into a PHP array so we can examine individual data items within it
    $decodeGoogleResponse = json_decode($verifyRecaptcha,true);

    //examine the response from Google and return true/false accordingly.
    if($decodeGoogleResponse['success'] == 1) return true;
    else return false;
  }
  
  //send a HTTP request to the specified URL using cURL
  private function sendHttpRequest($url)
  {
    $ch = curl_init();
    $getUrl = $url;
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_URL, $getUrl);
    curl_setopt($ch, CURLOPT_TIMEOUT, 80);
    
    $response = curl_exec($ch);
    curl_close($ch);
    return $response;
  }
}


//check form button and captcha field were submitted
if(isset($_POST['submit'], $_POST['g-recaptcha-response'])) {

  //test the captcha
  $cTest = new CaptchaTest();
  $captchaResult = $cTest->testCaptchaResponse($_POST['g-recaptcha-response']); }

  if ($captchaResult == true) {

        $mail = new PHPMailer(true);
        $mail->SMTPDebug = 0;
        $mail->Host = 'in-v3.mailjet.com';
        $mail->SMTPAuth = true;
        $mail->Username = 'XXXXX';
        $mail->Password = 'XXXXX';
        $mail->SMTPSecure = 'tls';
        $mail->Port = 587;
        $mail->setFrom($_POST['email'], $_POST['name']);
        $mail->addAddress('XXXXX');
        $mail->addReplyTo($_POST['email'], $_POST['name']);
        

//Attach multiple files one by one
    for ($ct = 0; $ct < count($_FILES['userfile']['tmp_name']); $ct++) {
     $uploadfile = tempnam(sys_get_temp_dir(), hash('sha256', $_FILES['userfile']['name'][$ct]));
     $filename = $_FILES['userfile']['name'][$ct];
       if (move_uploaded_file($_FILES['userfile']['tmp_name'][$ct], $uploadfile)) {
          $mail->addAttachment($uploadfile, $filename);
        } }

        $mail->isHTML(true);
        $mail->Subject = 'Website Enquiry';
        $mail->Body = "<p>You received an enquiry from:</p>
    <b>Name:</b>  $_POST[name]<br><br>
    <b>Company:</b>  $_POST[company]<br><br>
    <b>Phone Number:</b>  $_POST[phone]<br><br>
    <b>E-Mail:</b> $_POST[email]<br><br>
    <b>Message:</b> $_POST[message]";
            
  
        try {
             $mail->send();
header('Location: thank.html');
exit('Redirecting you to thank.html');
        } catch (Exception $e) {
            echo "Your message could not be sent! PHPMailer Error: {$mail->ErrorInfo}";
        }
        
    } 
    
else
  {
    

    echo "<script>
          alert('Captcha Error!, returning you to the Contact page')
          history.back()
          </script>";
}

    
?>

'''

Apologies if the final code isn't as elegant as it could be, I'm still at sub-Dummy level when it comes to PHP...

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