0

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('[email protected]');
        $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

8
  • PHPMailer has nothing to do with this. There is nothing in your PHP code that will prevent the message sending if recaptcha is ignored. You can't rely only on client-side checking for that, so you will need to check the status of the recaptcha input in the same place you check $_POST['submit'].
    – Synchro
    Commented Jun 23, 2022 at 13:04
  • Just a logic point as well, why would you go to the trouble of generating all the email object and attachments etc, only to reject it at the last minute because of the captcha? Waste of CPU. Check the captcha status first before you process any of the form or make any email objects etc.
    – ADyson
    Commented Jun 23, 2022 at 13:09
  • if (!$response->success || !$mail->send()); is gibberish, I've no idea what you think this is doing, but it doesn't do anything (except possibly cause the email to be sent, even though you then send it again later on). You are never verifying the catpcha with google either. You define $url but do nothing with it. There's no shortage of examples online using PHP and recaptcha to show how you should do this, so I can't really see why you'd be struggling.
    – ADyson
    Commented Jun 23, 2022 at 13:19
  • Thank you for the comments. I'm sorry I'm not as well versed in PHP as I need to be. My boss has asked me to build a website for a new division of the company and so I've been learning how to build a contact form with attachments and a Captcha. This has led to me only discovering the existence of PHPMailer in the past few weeks. Unfortunately, web development isn't a part of my job, so I'm only able to dip into the subject as and when. The last course I attended was back in 2005 (and that was on Flash!). My aim with this website is to push myself and brush up on my rusty skills. Commented Jun 23, 2022 at 15:20
  • Ok. But as we said, the issue at hand has nothing to do with PHPMailer. Follow one of the recaptcha tutorials in the link I provided above, that should help you sort out the captcha verification process.
    – ADyson
    Commented Jun 23, 2022 at 16:10

2 Answers 2

0

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).

8
  • Thanks very much for your time on this ADyson. Sorry that I've only just had the opportunity to get back onto this following my training. I've followed your recommendations and modified my code, but regardless of whether the Captcha is ticked or not, when I submit the form, I get the following error: Fatal error: Call to undefined method ReCaptchaTest::testCaptcha() in /homepages/10/d533748319/htdocs/lc/mail-script.php on line 55 For reference, the code is as follows: 54 $cTest = new ReCaptchaTest(); 55 $captchaResult = $cTest->testCaptcha($_POST['g-recaptcha-response']); Commented Jul 1, 2022 at 8:06
  • @neilwhitedesign Ah yes sorry, hopefully you can see (as I've just spotted) that's a typo on my part...in the class I've called the function testCaptchaResponse rather than testCaptcha. So just modify either one of them to match.
    – ADyson
    Commented Jul 1, 2022 at 8:50
  • Thanks very much for the response. I did as you suggested, which clears the line 55 error, but now brings up a different error: Fatal error: Call to undefined function curlRequest() in /homepages/10/d533748319/htdocs/lc/mail-script.php on line 21 This relates to: '$verifyRecaptcha = curlRequest($createGoogleUrl);' Have I understood correctly that both the code extracts from your Jun 24 post go into the same PHP file? Commented Jul 1, 2022 at 10:50
  • They can go into the same or different files, it doesn't matter. If you put them in different files then one file would need to include or requre the other, as per normal PHP procedure when combining multiple scripts. I get the impression you are missing a few of the fundamentals of the PHP language here, and/or possibly programming in general, and are fumbling around in the dark to implement one specific thing rather than getting hold of the core principles and information which would allow you to implement all kinds of things like this much more easily.
    – ADyson
    Commented Jul 1, 2022 at 10:57
  • But anyway sorry curlRequest($createGoogleUrl); was another typo / bit I forgot to change from the example I based this one. Hopefully you can guess that it was supposed to run the sendHttpRequest() function within the same class, since that uses cURL inside it. It should be changed to $this->sendHttpRequest($createGoogleUrl);. Apologies I didn't double-check this properly when I posted it, perhaps I was busy with something else.However if you've done a little bit of coding before it ought to be fairly easy to work out what these errors mean and what was intended, from a glance at the code
    – ADyson
    Commented Jul 1, 2022 at 11:01
0

@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...

1
  • Thanks, I've corrected the typo on my answer. Definitely shows the benefits of debugging (and the downside of PHP as a "loose" language which doesn't insist on variables being declared before being used - e.g. in C# or Java the compiler would have picked this up because $captchResult would never have been declared previously, so it would effectively point out that the variable doesn't exist or match what was created above).
    – ADyson
    Commented Jul 7, 2022 at 10:22

Not the answer you're looking for? Browse other questions tagged or ask your own question.