A contact form is an essential component of any website. In this article, we show how to create a secure contact form using HTML, PHP, and AJAX, protected with a CSRF token to prevent security vulnerabilities.
<form id="contact-form">
<input type="hidden" id="csrf_token" name="csrf_token" value="">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<label for="message">Message:</label>
<textarea id="message" name="message" required></textarea>
<button type="submit">Submit</button>
</form>
<p id="response"></p>
We create a simple HTML form.
<?php
session_start();
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
echo json_encode(["csrf_token" => $_SESSION['csrf_token']]);
We add this code to a PHP file (csrf_token.php) to generate a CSRF token.
document.addEventListener("DOMContentLoaded", function () {
fetch("csrf_token.php")
.then(response => response.json())
.then(data => {
document.getElementById("csrf_token").value = data.csrf_token;
});
});
Then, we load the token when the page loads using JavaScript.
document.getElementById("contact-form").addEventListener("submit", function (e) {
e.preventDefault();
let formData = new FormData(this);
fetch("process_form.php", {
method: "POST",
body: formData
})
.then(response => response.json())
.then(data => {
document.getElementById("response").textContent = data.message;
})
.catch(error => console.error("Error:", error));
});
Now, we add a script that sends the form via AJAX to process_form.php.
<?php
session_start();
header("Content-Type: application/json");
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
echo json_encode(["message" => "Invalid request"]);
exit;
}
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(["message" => "CSRF validation failed"]);
exit;
}
$name = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
$message = filter_var($_POST['message'], FILTER_SANITIZE_STRING);
if (empty($name) || empty($email) || empty($message)) {
echo json_encode(["message" => "Please fill in all fields"]);
exit;
}
$to = "john.doe@example.com";
$subject = "New message from $name";
$headers = "From: $email\r\nReply-To: $email\r\nContent-Type: text/plain; charset=UTF-8";
$mailSent = mail($to, $subject, $message, $headers);
if ($mailSent) {
echo json_encode(["message" => "Message sent successfully!"]);
} else {
echo json_encode(["message" => "Error sending the message"]);
}
Here is the code for process_form.php to process the form and send the message.
We need an API key from Google reCAPTCHA
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<form id="contact-form">
<input type="hidden" id="csrf_token" name="csrf_token" value="">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<label for="message">Message:</label>
<textarea id="message" name="message" required></textarea>
<div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY"></div>
<button type="submit">Submit</button>
</form>
We add the reCAPTCHA script to the HTML form.
$recaptchaSecret = "YOUR_SECRET_KEY";
$recaptchaResponse = $_POST['g-recaptcha-response'];
$verifyResponse = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$recaptchaSecret}&response={$recaptchaResponse}");
$responseData = json_decode($verifyResponse);
if (!$responseData->success) {
echo json_encode(["message" => "Please verify reCAPTCHA"]);
exit;
}
We verify the reCAPTCHA token in process_form.php.
<input type="text" name="honeypot" style="display:none;">
We add a hidden input field to the HTML form.
if (!empty($_POST['honeypot'])) {
echo json_encode(["message" => "Spam detected!"]);
exit;
}
We check the honeypot in process_form.php.
session_start();
$_SESSION['form_time'] = time();
We initiate time-based validation in csrf_token.php.
if (time() - $_SESSION['form_time'] < 5) {
echo json_encode(["message" => "Form filled out too quickly, suspicious request!"]);
exit;
}
We verify time-based validation in process_form.php.
With this setup, you have a secure and modern contact form that uses AJAX to avoid page reloads and includes CSRF protection to prevent attacks. This ensures your contact form operates reliably and securely.
A CSRF token prevents Cross-Site Request Forgery (CSRF) attacks by ensuring that only authorized requests are accepted.
Yes, but without JavaScript, the page will reload upon submission. The form can also be processed with a traditional PHP POST request.
Check if your server supports the mail() function. Alternatively, you can use PHPMailer.
Add additional fields, enhance styling with CSS, or integrate with a database.
This example does not include spam protection. The article explains how to add spam protection.
Yes, but each form needs its own CSRF token, or you must make the token available for all forms.
Use the advanced WYSIWYG editor in Shopware 6. This editor enables easy embedding of media in descriptions and many additional features.
ab 7.99 €* / Month
Rent PluginOptimize your shop to create a better experience for your customers. This plugin minimizes your shop’s loading time and offers numerous configuration options.
ab 27.49 €* / Month
Rent PluginQuickly and easily create and edit your own template extensions in the administration. Displays existing storefront template paths and contents.
ab 3.99 €* / Month
Rent PluginNote: * All prices are exclusive of VAT
x