Sick Gaming
[Tut] Contact Form with Custom Image Captcha Validation like Google reCaptcha - Printable Version

+- Sick Gaming (https://www.sickgaming.net)
+-- Forum: Programming (https://www.sickgaming.net/forum-76.html)
+--- Forum: PHP Development (https://www.sickgaming.net/forum-82.html)
+--- Thread: [Tut] Contact Form with Custom Image Captcha Validation like Google reCaptcha (/thread-93231.html)



[Tut] Contact Form with Custom Image Captcha Validation like Google reCaptcha - xSicKxBot - 01-21-2020

Contact Form with Custom Image Captcha Validation like Google reCaptcha

<div style="margin: 5px 5% 10px 5%;"><img src="https://www.sickgaming.net/blog/wp-content/uploads/2020/01/contact-form-with-custom-image-captcha-validation-like-google-recaptcha.png" width="550" height="461" title="" alt="" /></div><div><p>Last modified on January 9th, 2020 by Vincy.</p>
<p>A contact form on a website is a medium to the users to contact the site admin or maintainer. It acts as a medium of communication. For many a websites, it is a critical factor in getting a sale.</p>
<p>The Captcha in a form is a mechanism to prevent bots or malicious users from submitting the form. It protects the site from security abuses.</p>
<p>There are components available in the market to render captcha in a form. <a href="https://www.google.com/recaptcha/intro/v3.html" target="_blank" rel="noopener noreferrer">Google reCAPTCHA</a> is a popular and unbeatable service to make your form captcha-enabled.</p>
<ol>
<li>Different websites use different types of captcha.</li>
<li>Displaying random alpha-numeric characters.</li>
<li>Requesting to solve puzzles, Google reCAPTCHA-like image captcha.</li>
</ol>
<p>I created an example code for a contact form in PHP with the reCAPTCHA-like image captcha mechanism.</p>
<p><img class="alignnone size-large wp-image-11051" src="https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-captcha-550x461.png" alt="Contact Form In Php With Captcha" width="550" height="461" srcset="https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-captcha-550x461.png 550w, https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-captcha-300x251.png 300w, https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-captcha-768x644.png 768w, https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-captcha.png 940w" sizes="(max-width: 550px) 100vw, 550px"></p>
<h2>What is inside?</h2>
<ol>
<li><a href="https://phppot.com/php/contact-form-with-custom-image-captcha-validation-like-google-recaptcha/#existing-contact-form-component">Existing contact form component</a></li>
<li><a href="https://phppot.com/php/contact-form-with-custom-image-captcha-validation-like-google-recaptcha/#about-this-example">About this example</a></li>
<li><a href="https://phppot.com/php/contact-form-with-custom-image-captcha-validation-like-google-recaptcha/#file-structure">File structure</a></li>
<li><a href="https://phppot.com/php/contact-form-with-custom-image-captcha-validation-like-google-recaptcha/#html-code-to-show-contact-form-with-image-captcha">HTML code to show contact form with image captcha</a></li>
<li><a href="https://phppot.com/php/contact-form-with-custom-image-captcha-validation-like-google-recaptcha/#php-code-to-validate-image-captcha-and-send-contact-mail">PHP code to validate image captcha and send contact mail</a></li>
<li><a href="https://phppot.com/php/contact-form-with-custom-image-captcha-validation-like-google-recaptcha/#contact-form-captcha-image-database-script">Contact form captcha image database script</a></li>
<li><a href="https://phppot.com/php/contact-form-with-custom-image-captcha-validation-like-google-recaptcha/#contact-form-output-with-custom-image-captcha">Contact form output with custom image captcha</a></li>
</ol>
<p>Ready-made contact form components are existing huge in number around the web. If you want to get one among them, then we need to be sure about the security and robustness of the code.</p>
<p>I have created a <a href="https://phppot.com/shop/contact-form-iris/">secure spam-free contact form script, Iris</a>. I coded this component to easily integrate and configure with your application. If you are looking for a contact form that controls spam without using a captcha, then you will like it.</p>
<p>This also component includes Google reCAPTCHA. You can enable or disable this feature on a need basis. In similar ways, it comes with loads of features that is configurable in minutes.</p>
<h2 id="about-this-example">About this example</h2>
<p>This example code has the Name, Email, Subject and Message fields. These are some basic fields that we have seen with other <a href="https://phppot.com/php/php-contact-form/">PHP contact form example</a> earlier.</p>
<p>Added to these fields, I have added an image captcha section in this code. This section will show five random images and ask to choose one.&nbsp;The random images are from the database.</p>
<p>I used jQuery script to validate the form field data before posting it to the PHP.</p>
<p>In PHP, it validates the captcha image clicked by the user. Based on the server-side captcha validation, the PHP will respond to the user.</p>
<h2 id="file-structure">File structure</h2>
<p>The PHP contact form with an image captcha example includes less number of files.</p>
<p>The file structure is in the below screenshot. You can see that it has a systematic code with a conventional structure.</p>
<p><img class="alignnone size-full wp-image-11061" src="https://phppot.com/wp-content/uploads/2020/01/contact-form-with-image-captcha-file-structure.jpg" alt="Contact Form with Image Captcha File Structure" width="309" height="329" srcset="https://phppot.com/wp-content/uploads/2020/01/contact-form-with-image-captcha-file-structure.jpg 309w, https://phppot.com/wp-content/uploads/2020/01/contact-form-with-image-captcha-file-structure-282x300.jpg 282w" sizes="(max-width: 309px) 100vw, 309px"></p>
<p>This code snippet shows the HTML part of the <em>index.php,</em> the landing page.&nbsp;</p>
<p>This contact form contains some basic fields with custom captcha in PHP.</p>
<p>The captcha section shows the&nbsp;<em>SVG</em> image markup from the database. It displays five random images and requests the user to select one.</p>
<p>The HTML form has the specification of a jQuery validation handler. The form-submit event will invoke this handler to <a href="https://phppot.com/php/php-form-validation/">process the form validation</a>.</p>
<p>This HTML includes the response containers to display notifications to the user. These notifications acknowledge the user about the captcha validation or other responses.</p>
<p class="code-heading">index.php (contact form HTML)</p>
<pre class="prettyprint lang-php">&lt;html&gt; &lt;head&gt; &lt;title&gt;Contact Us Form&lt;/title&gt; &lt;link rel="stylesheet" type="text/css" href="assets/css/contact-form-style.css" /&gt; &lt;link rel="stylesheet" type="text/css" href="assets/css/phppot-style.css" /&gt; &lt;script src="vendor/jquery/jquery-3.2.1.min.js"&gt;&lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;div class="phppot-container"&gt; &lt;h1&gt;PHP contact form with captcha images&lt;/h1&gt; &lt;form name="frmContact" id="captcha-cnt-frm" class="phppot-form" frmContact"" method="post" action="" enctype="multipart/form-data" onsubmit="return validateContactForm()"&gt; &lt;div class="phppot-row"&gt; &lt;div class="label"&gt; Name &lt;span id="userName-info" class="validation-message"&gt;&lt;/span&gt; &lt;/div&gt; &lt;input type="text" class="phppot-input" name="userName" id="userName" value="&lt;?php if(!empty($_POST['userName'])&amp;&amp; $type == 'error'){ echo $_POST['userName'];}?&gt;" /&gt; &lt;/div&gt; &lt;div class="phppot-row"&gt; &lt;div class="label"&gt; Email &lt;span id="userEmail-info" class="validation-message"&gt;&lt;/span&gt; &lt;/div&gt; &lt;input type="text" class="phppot-input" name="userEmail" id="userEmail" value="&lt;?php if(!empty($_POST['userEmail'])&amp;&amp; $type == 'error'){ echo $_POST['userEmail'];}?&gt;" /&gt; &lt;/div&gt; &lt;div class="phppot-row"&gt; &lt;div class="label"&gt; Subject &lt;span id="subject-info" class="validation-message"&gt;&lt;/span&gt; &lt;/div&gt; &lt;input type="text" class="phppot-input" name="subject" id="subject" value="&lt;?php if(!empty($_POST['subject'])&amp;&amp; $type == 'error'){ echo $_POST['subject'];}?&gt;" /&gt; &lt;/div&gt; &lt;div class="phppot-row"&gt; &lt;div class="label"&gt; Message &lt;span id="userMessage-info" class="validation-message"&gt;&lt;/span&gt; &lt;/div&gt; &lt;textarea name="content" id="content" class="phppot-input" cols="60" rows="6"&gt;&lt;?php if(!empty($_POST['content'])&amp;&amp; $type == 'error'){ echo $_POST['content'];}?&gt;&lt;/textarea&gt; &lt;/div&gt; &lt;?php if (! empty($result)) { ?&gt; &lt;div class="phppot-row"&gt; &lt;div class="captcha-container &lt;?php if(!empty($border)){ echo $border;} ?&gt;"&gt; &lt;p&gt; Select the &lt;span class="text-color"&gt;&lt;?php echo $result[0]['name'];?&gt; &lt;/span&gt;&lt;span id="captcha-info" class="validation-message"&gt;&lt;/span&gt; &lt;/p&gt; &lt;input type="hidden" name="captcha_code" value="&lt;?php echo $result[0]['name'];?&gt;"&gt; &lt;?php shuffle($captchaOutput); if (! empty($captchaOutput)) { foreach ($captchaOutput as $value) { ?&gt; &lt;div class="svg-padding"&gt; &lt;div class="svg"&gt;&lt;?php echo $value['captcha_icon'];?&gt; &lt;input type="hidden" class="icons" value="&lt;?php echo $value['name'];?&gt;"&gt; &lt;/div&gt; &lt;/div&gt; &lt;?php }}?&gt; &lt;/div&gt; &lt;/div&gt; &lt;?php }?&gt; &lt;div class="phppot-row"&gt; &lt;input type="submit" name="send" class="send-button" value="Send" /&gt; &lt;/div&gt; &lt;input type="hidden" name="captcha_chosen" id="captcha-chosen" value=""&gt; &lt;/form&gt; &lt;?php if(!empty($message)) { ?&gt; &lt;div id="phppot-message" class="&lt;?php echo $type; ?&gt;"&gt;&lt;?php if(isset($message)){ ?&gt; &lt;?php echo $message; }}?&gt; &lt;/div&gt; &lt;/div&gt; &lt;script src="assets/js/captcha.js"&gt;&lt;/script&gt; &lt;/body&gt; &lt;/html&gt; </pre>
<h3>jQuery script to validate contact form and highlight captcha selection</h3>
<p>This section shows the jQuery script for validation and captcha selection.</p>
<p>The <em>validateContactForm() </em>function is&nbsp;handling the form validation.&nbsp;All the contact form fields are mandatory. This function is making sure about the non-empty state of the form fields.</p>
<p>On selecting one of the lists of captcha images, the script puts the selected value in a form field. Also, it highlights the selected by adding CSS via script.</p>
<p>If the user selects no captcha, then the validation will return false.</p>
<p class="code-heading">assets/js/captcha.js</p>
<pre class="prettyprint lang-php">function validateContactForm() { var valid = true; $("#userName").removeClass("error-field"); $("#userEmail").removeClass("error-field"); $("#subject").removeClass("error-field"); $("#content").removeClass("error-field"); $("#userName-info").html("").hide(); $("#userEmail-info").html("").hide(); $("#subject-info").html("").hide(); $("#content-info").html("").hide(); $(".validation-message").html(""); $(".phppot-input").css('border', '#e0dfdf 1px solid'); $(".captcha-container").css('border', '#e0dfdf 1px solid'); var userName = $("#userName").val(); var userEmail = $("#userEmail").val(); var subject = $("#subject").val(); var content = $("#content").val(); var captcha = $("#captcha-chosen").val(); if (userName.trim() == "") { $("#userName-info").html("required.").css("color", "#ee0000").show(); $("#userName").css('border', '#e66262 1px solid'); $("#userName").addClass("error-field"); valid = false; } if (userEmail.trim() == "") { $("#userEmail-info").html("required.").css("color", "#ee0000").show(); $("#userEmail").css('border', '#e66262 1px solid'); $("#userEmail").addClass("error-field"); valid = false; } if (!userEmail.match(/^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/)) { $("#userEmail-info").html("invalid email address.").css("color", "#ee0000").show(); $("#userEmail").css('border', '#e66262 1px solid'); $("#userEmail").addClass("error-field"); valid = false; } if (subject == "") { $("#subject-info").html("required.").css("color", "#ee0000").show(); $("#subject").css('border', '#e66262 1px solid'); $("#subject").addClass("error-field"); valid = false; } if (content == "") { $("#userMessage-info").html("required.").css("color", "#ee0000").show(); $("#content").css('border', '#e66262 1px solid'); $("#content").addClass("error-field"); valid = false; } if (captcha == "") { $("#captcha-info").html("required."); $(".captcha-container").css('border', '#e66262 1px solid'); valid = false; } if (valid == false) { $('.error-field').first().focus(); valid = false; } return valid; } $(".svg-padding").on('click', function() { $(".svg").removeClass('captcha-selected'); $(this).find(".svg").addClass('captcha-selected'); var icons = $(this).find(".icons").val(); $("#captcha-chosen").val(icons); }); </pre>
<h3>CSS created for contact form example</h3>
<p>These are the exclusive styles created to present the contact form. Mostly, it contains styles for the captcha section.</p>
<p>I used a generic CSS template for designing other common form components. You can find this CSS in the downloadable.</p>
<p class="code-heading">assets/css/contact-form-style.css</p>
<pre class="prettyprint lang-php">.svg-padding { display: inline-block; } .svg { cursor: pointer; padding: 5px 5px 5px 5px; border-radius: 3px; margin: 0px 5px 0px 5px; border: 1px solid #FFF; } .text-color { font-weight: bold; } .captcha-container { background: #fff; padding: 15px; border: 1px solid #9a9a9a; width: 270px; border-radius: 3px; padding-top: 0px; } .error-field { border: 1px solid #d96557; } .send-button { cursor: pointer; background: #3cb73c; border: #36a536 1px solid; color: #FFF; font-size: 1em; width: 100px; } .captcha-selected { color: #1cb87b; background-color: #e3e3e3; border: #d7d7d7 1px solid; } .border-error-color { border: 1px solid #e66262; } </pre>
<p>On loading the contact form, the PHP code reads the random captcha images from the database. In PHP, it picks one image from the random results as the captcha code.</p>
<p>The HTML form contains a hidden field to have this code.</p>
<p>When the user selects an image and posts it to the PHP, it will validate the selected captcha.</p>
<p>The user-selected captcha is matched with the pre-loaded code, then the PHP code will return true. Then, it will process the contact email sending script.</p>
<p class="code-heading">index.php (Captcha Validation and Mail sending)</p>
<pre class="prettyprint lang-php">&lt;?php namespace Phppot; require_once ("Model/Contact.php"); $contact = new Contact(); if (! empty($_POST['send'])) { if ($_POST['captcha_code'] == $_POST['captcha_chosen']) { $contact-&gt;sendContactMail($_POST); $message = "Hi, we have received your message. Thank you."; $type = "success"; } else { $message = "Invalid captcha. Please select the correct image."; $type = "error"; $border = "border-error-color"; } } $result = $contact-&gt;getRecord(); $termId = $result[0]['id']; $captchaResult = $contact-&gt;getCaptchaIcons($termId); $randomCaptchaResult = $contact-&gt;getRandomCaptchaId($termId); $captchaOutput = array_merge($captchaResult, $randomCaptchaResult); ?&gt; </pre>
<p>In this PHP model class, it has the functions to read random captcha images from the database.</p>
<p>The&nbsp;<em>getRecord()&nbsp;</em>method reads a single random record to load captcha code on the page load.</p>
<p>The&nbsp;<em>sendContactMail()&nbsp;</em>function send the contact mail. I used <a href="https://phppot.com/php/php-mail/">PHP mail()</a> function for this example. If you want to use <a href="https://phppot.com/php/send-email-in-php-using-gmail-smtp/">SMTP for sending the email</a>, you can see the example in the linked article.</p>
<p class="code-heading">Model/Contact.php</p>
<pre class="prettyprint lang-php">&lt;?php namespace Phppot; use Phppot\DataSource; class Contact { private $ds; function __construct() { require_once __DIR__ . './../lib/DataSource.php'; $this-&gt;ds = new DataSource(); } function getRecord() { $query = "SELECT * FROM tbl_term ORDER BY RAND() LIMIT 1"; $result = $this-&gt;ds-&gt;select($query); return $result; } function getCaptchaIcons($id) { $query = "SELECT tbl_captcha_images.*, tbl_term.name FROM tbl_captcha_images JOIN tbl_term ON tbl_captcha_images.term_id = tbl_term.id WHERE term_id != " . $id . " ORDER BY RAND() LIMIT 4"; $captchaResult = $this-&gt;ds-&gt;select($query); return $captchaResult; } function getRandomCaptchaId($id) { $query = "SELECT tbl_captcha_images.*, tbl_term.name FROM tbl_captcha_images JOIN tbl_term ON tbl_captcha_images.term_id = tbl_term.id WHERE term_id = " . $id . " ORDER BY RAND() LIMIT 1"; $captcha = $this-&gt;ds-&gt;select($query); return $captcha; } function sendContactMail($postValues) { $name = $postValues["userName"]; $email = $postValues["userEmail"]; $subject = $postValues["subject"]; $content = $postValues["content"]; $toEmail = "SITE_ADMIN_EMAIL"; // Put in place the recipient email $mailHeaders = "From: " . $name . "&lt;" . $email . "&gt;\r\n"; mail($toEmail, $subject, $content, $mailHeaders); } } </pre>
<p class="code-heading">lib/Datasource.php</p>
<pre class="prettyprint lang-php">&lt;?php namespace Phppot; /** * Generic datasource class for handling DB operations. * Uses MySqli and PreparedStatements. * * @version 2.3 */ class DataSource { // PHP 7.1.0 visibility modifiers are allowed for class constants. // when using above 7.1.0, declare the below constants as private const HOST = 'localhost'; const USERNAME = 'root'; const PASSWORD = ''; const DATABASENAME = 'contact_form_captcha'; private $conn; /** * PHP implicitly takes care of cleanup for default connection types. * So no need to worry about closing the connection. * * Singletons not required in PHP as there is no * concept of shared memory. * Every object lives only for a request. * * Keeping things simple and that works! */ function __construct() { $this-&gt;conn = $this-&gt;getConnection(); } /** * If connection object is needed use this method and get access to it. * Otherwise, use the below methods for insert / update / etc. * * @return \mysqli */ public function getConnection() { $conn = new \mysqli(self::HOST, self::USERNAME, self::PASSWORD, self::DATABASENAME); if (mysqli_connect_errno()) { trigger_error("Problem with connecting to database."); } $conn-&gt;set_charset("utf8"); return $conn; } /** * To get database results * * @param string $query * @param string $paramType * @param array $paramArray * @return array */ public function select($query, $paramType = "", $paramArray = array()) { $stmt = $this-&gt;conn-&gt;prepare($query); if (! empty($paramType) &amp;&amp; ! empty($paramArray)) { $this-&gt;bindQueryParams($stmt, $paramType, $paramArray); } $stmt-&gt;execute(); $result = $stmt-&gt;get_result(); if ($result-&gt;num_rows &gt; 0) { while ($row = $result-&gt;fetch_assoc()) { $resultset[] = $row; } } if (! empty($resultset)) { return $resultset; } } } </pre>
<p>This SQL script includes the structure and data of the tables used to display custom captcha. The <em>tbl_captcha_images</em> table contains the <em>SVG</em> markup of the captcha images.</p>
<p>I have used another table&nbsp;<em>tbl_term&nbsp;</em>to hold the captcha term and title. The captcha term is for stating the user what to select. The captcha title is a slug to add it with a title attribute.</p>
<p class="code-heading">sql/contact_form_captcha.sql</p>
<pre class="prettyprint lang-php">-- -- Database: `contact_form_captcha` -- -- -------------------------------------------------------- -- -- Table structure for table `tbl_captcha_images` -- CREATE TABLE `tbl_captcha_images` ( `id` int(11) NOT NULL, `term_id` int(11) NOT NULL, `captcha_icon` text NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `tbl_captcha_images` -- INSERT INTO `tbl_captcha_images` (`id`, `term_id`, `captcha_icon`) VALUES (1, 1, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 512\"&gt;&lt;path fill=\"currentColor\" d=\"M192 384h192c53 0 96-43 96-96h32c70.6 0 128-57.4 128-128S582.6 32 512 32H120c-13.3 0-24 10.7-24 24v232c0 53 43 96 96 96zM512 96c35.3 0 64 28.7 64 64s-28.7 64-64 64h-32V96h32zm47.7 384H48.3c-47.6 0-61-64-36-64h583.3c25 0 11.8 64-35.9 64z\"&gt;&lt;/path&gt;&lt;/svg&gt;'), (2, 2, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\"&gt;&lt;path fill=\"currentColor\" d=\"M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z\"&gt;&lt;/path&gt;&lt;/svg&gt;'), (3, 3, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\"&gt;&lt;path fill=\"currentColor\" d=\"M377.33 375.429L293.906 288H328c21.017 0 31.872-25.207 17.448-40.479L262.79 160H296c20.878 0 31.851-24.969 17.587-40.331l-104-112.003c-9.485-10.214-25.676-10.229-35.174 0l-104 112.003C56.206 134.969 67.037 160 88 160h33.21l-82.659 87.521C24.121 262.801 34.993 288 56 288h34.094L6.665 375.429C-7.869 390.655 2.925 416 24.025 416H144c0 32.781-11.188 49.26-33.995 67.506C98.225 492.93 104.914 512 120 512h144c15.086 0 21.776-19.069 9.995-28.494-19.768-15.814-33.992-31.665-33.995-67.496V416h119.97c21.05 0 31.929-25.309 17.36-40.571z\"&gt;&lt;/path&gt;&lt;/svg&gt;'), (4, 4, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 640 512\"&gt;&lt;path fill=\"currentColor\" d=\"M624 352h-16V243.9c0-12.7-5.1-24.9-14.1-33.9L494 110.1c-9-9-21.2-14.1-33.9-14.1H416V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48v320c0 26.5 21.5 48 48 48h16c0 53 43 96 96 96s96-43 96-96h128c0 53 43 96 96 96s96-43 96-96h48c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zM160 464c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm320 0c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm80-208H416V144h44.1l99.9 99.9V256z\"&gt;&lt;/path&gt;&lt;/svg&gt;'), (5, 5, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"&gt;&lt;path fill=\"currentColor\" d=\"M512 176.001C512 273.203 433.202 352 336 352c-11.22 0-22.19-1.062-32.827-3.069l-24.012 27.014A23.999 23.999 0 0 1 261.223 384H224v40c0 13.255-10.745 24-24 24h-40v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24v-78.059c0-6.365 2.529-12.47 7.029-16.971l161.802-161.802C163.108 213.814 160 195.271 160 176 160 78.798 238.797.001 335.999 0 433.488-.001 512 78.511 512 176.001zM336 128c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48-48 21.49-48 48z\"&gt;&lt;/path&gt;&lt;/svg&gt;'), (6, 6, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"&gt;&lt;path fill=\"currentColor\" d=\"M499.991 168h-54.815l-7.854-20.944c-9.192-24.513-25.425-45.351-46.942-60.263S343.651 64 317.472 64H194.528c-26.18 0-51.391 7.882-72.908 22.793-21.518 14.912-37.75 35.75-46.942 60.263L66.824 168H12.009c-8.191 0-13.974 8.024-11.384 15.795l8 24A12 12 0 0 0 20.009 216h28.815l-.052.14C29.222 227.093 16 247.997 16 272v48c0 16.225 6.049 31.029 16 42.309V424c0 13.255 10.745 24 24 24h48c13.255 0 24-10.745 24-24v-40h256v40c0 13.255 10.745 24 24 24h48c13.255 0 24-10.745 24-24v-61.691c9.951-11.281 16-26.085 16-42.309v-48c0-24.003-13.222-44.907-32.772-55.86l-.052-.14h28.815a12 12 0 0 0 11.384-8.205l8-24c2.59-7.771-3.193-15.795-11.384-15.795zm-365.388 1.528C143.918 144.689 168 128 194.528 128h122.944c26.528 0 50.61 16.689 59.925 41.528L391.824 208H120.176l14.427-38.472zM88 328c-17.673 0-32-14.327-32-32 0-17.673 14.327-32 32-32s48 30.327 48 48-30.327 16-48 16zm336 0c-17.673 0-48 1.673-48-16 0-17.673 30.327-48 48-48s32 14.327 32 32c0 17.673-14.327 32-32 32z\"&gt;&lt;/path&gt;&lt;/svg&gt;'), (7, 7, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\"&gt;&lt;path fill=\"currentColor\" d=\"M414.9 24C361.8 24 312 65.7 288 89.3 264 65.7 214.2 24 161.1 24 70.3 24 16 76.9 16 165.5c0 72.6 66.8 133.3 69.2 135.4l187 180.8c8.8 8.5 22.8 8.5 31.6 0l186.7-180.2c2.7-2.7 69.5-63.5 69.5-136C560 76.9 505.7 24 414.9 24z\"&gt;&lt;/path&gt;&lt;/svg&gt;'), (8, 8, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\"&gt;&lt;path fill=\"currentColor\" d=\"M488 312.7V456c0 13.3-10.7 24-24 24H348c-6.6 0-12-5.4-12-12V356c0-6.6-5.4-12-12-12h-72c-6.6 0-12 5.4-12 12v112c0 6.6-5.4 12-12 12H112c-13.3 0-24-10.7-24-24V312.7c0-3.6 1.6-7 4.4-9.3l188-154.8c4.4-3.6 10.8-3.6 15.3 0l188 154.8c2.7 2.3 4.3 5.7 4.3 9.3zm83.6-60.9L488 182.9V44.4c0-6.6-5.4-12-12-12h-56c-6.6 0-12 5.4-12 12V117l-89.5-73.7c-17.7-14.6-43.3-14.6-61 0L4.4 251.8c-5.1 4.2-5.8 11.8-1.6 16.9l25.5 31c4.2 5.1 11.8 5.8 16.9 1.6l235.2-193.7c4.4-3.6 10.8-3.6 15.3 0l235.2 193.7c5.1 4.2 12.7 3.5 16.9-1.6l25.5-31c4.2-5.2 3.4-12.7-1.7-16.9z\"&gt;&lt;/path&gt;&lt;/svg&gt;'), (9, 9, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"&gt;&lt;path fill=\"currentColor\" d=\"M349.565 98.783C295.978 98.783 251.721 64 184.348 64c-24.955 0-47.309 4.384-68.045 12.013a55.947 55.947 0 0 0 3.586-23.562C118.117 24.015 94.806 1.206 66.338.048 34.345-1.254 8 24.296 8 56c0 19.026 9.497 35.825 24 45.945V488c0 13.255 10.745 24 24 24h16c13.255 0 24-10.745 24-24v-94.4c28.311-12.064 63.582-22.122 114.435-22.122 53.588 0 97.844 34.783 165.217 34.783 48.169 0 86.667-16.294 122.505-40.858C506.84 359.452 512 349.571 512 339.045v-243.1c0-23.393-24.269-38.87-45.485-29.016-34.338 15.948-76.454 31.854-116.95 31.854z\"&gt;&lt;/path&gt;&lt;/svg&gt;'), (10, 10, '&lt;svg width=\"25px\" height=\"25px\" aria-hidden=\"true\" role=\"img\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\"&gt;&lt;path fill=\"currentColor\" d=\"M472 200H360.211L256.013 5.711A12 12 0 0 0 245.793 0h-57.787c-7.85 0-13.586 7.413-11.616 15.011L209.624 200H99.766l-34.904-58.174A12 12 0 0 0 54.572 136H12.004c-7.572 0-13.252 6.928-11.767 14.353l21.129 105.648L.237 361.646c-1.485 7.426 4.195 14.354 11.768 14.353l42.568-.002c4.215 0 8.121-2.212 10.289-5.826L99.766 312h109.858L176.39 496.989c-1.97 7.599 3.766 15.011 11.616 15.011h57.787a12 12 0 0 0 10.22-5.711L360.212 312H472c57.438 0 104-25.072 104-56s-46.562-56-104-56z\"&gt;&lt;/path&gt;&lt;/svg&gt;'); -- -------------------------------------------------------- -- -- Table structure for table `tbl_term` -- CREATE TABLE `tbl_term` ( `id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `slug` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `tbl_term` -- INSERT INTO `tbl_term` (`id`, `name`, `slug`) VALUES (1, 'cup', 'cup-1'), (2, 'star', 'star-2'), (3, 'tree', 'tree-3'), (4, 'truck', 'truck-4'), (5, 'key', 'key-5'), (6, 'car', 'car-6'), (7, 'heart', 'heart-7'), (8, 'house', 'house-8'), (9, 'flag', 'flag-9'), (10, 'plane', 'plane-10'); -- -- Indexes for dumped tables -- -- -- Indexes for table `tbl_captcha_images` -- ALTER TABLE `tbl_captcha_images` ADD PRIMARY KEY (`id`); -- -- Indexes for table `tbl_term` -- ALTER TABLE `tbl_term` ADD PRIMARY KEY (`id`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `tbl_captcha_images` -- ALTER TABLE `tbl_captcha_images` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11; -- -- AUTO_INCREMENT for table `tbl_term` -- ALTER TABLE `tbl_term` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11; COMMIT; </pre>
<p><a href="https://phppot.com/wp-content/uploads/2020/01/contact-form-captcha-image-database.jpg"><img class="alignnone wp-image-11066 size-large" src="https://phppot.com/wp-content/uploads/2020/01/contact-form-captcha-image-database-550x204.jpg" alt="Contact Form Captcha Image Database" width="550" height="204" srcset="https://phppot.com/wp-content/uploads/2020/01/contact-form-captcha-image-database-550x204.jpg 550w, https://phppot.com/wp-content/uploads/2020/01/contact-form-captcha-image-database-300x111.jpg 300w, https://phppot.com/wp-content/uploads/2020/01/contact-form-captcha-image-database-768x284.jpg 768w, https://phppot.com/wp-content/uploads/2020/01/contact-form-captcha-image-database.jpg 1024w" sizes="(max-width: 550px) 100vw, 550px"></a></p>
<p>This screenshot shows the output of this PHP contact form example. It displays the custom image captcha in the form.</p>
<p>It focuses on the captcha section because of the form submitted with invalid captcha.</p>
<p><img class="alignnone size-large wp-image-11057" src="https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-image-captcha-550x413.jpg" alt="Contact Form in PHP with Image Captcha" width="550" height="413" srcset="https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-image-captcha-550x413.jpg 550w, https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-image-captcha-300x225.jpg 300w, https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-image-captcha-768x577.jpg 768w, https://phppot.com/wp-content/uploads/2020/01/contact-form-in-php-with-image-captcha.jpg 1024w" sizes="(max-width: 550px) 100vw, 550px"></p>
<p><a class="download" href="https://phppot.com/downloads/contact-form-with-custom-image-captcha.zip">Download</a></p>
<p> <!-- #comments --> </p>
<div class="related-articles">
<h2>Popular Articles</h2>
</p></div>
<p> <a href="https://phppot.com/php/contact-form-with-custom-image-captcha-validation-like-google-recaptcha/#top" class="top">↑ Back to Top</a> </p>
</div>


https://www.sickgaming.net/blog/2020/01/09/contact-form-with-custom-image-captcha-validation-like-google-recaptcha/