Idea
After a handfull of small javascript-projects, I also wanted to work a bit with php now. I decided to create a simple contact-form. Of course, I wanted it to be as spam-save as possible, so I used some of the ideas I found online (honeypott and some sort of CAPTCHA).
I realized the CAPTCHA-idea in the following way: Every time the user loads the contact-page a simple math-problem is created randomly and the user has to enter the correct solution to submit the form.
The Code
Minimal working example
<!DOCTYPE html>
<html lang='en'>
<!-- Head -->
<head>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Contact</title>
<link rel='stylesheet' type='text/css' href='style.css'>
</head>
<body>
<main>
<div style='margin:30px; margin-top: 50px'>
<h2>Contact</h2>
<div>
<form method="POST" action="send.php" class='input'>
<label>Your Name:</label><br>
<input type="text" name="myName" placeholder="Name" required/><br><br>
<label>Your Email:</label><br>
<input type="text" name="myEmail" placeholder="E-Mail" required/><br><br>
<!-- Honeypott -->
<input type="text" id="website" name="website"/>
<label>Message:</label><br>
<textarea rows="8" name="myMessage" style='width: 100%; resize: none; border: 1px solid Gray; border-radius: 4px; box-sizing: border-box; padding: 10px 10px;' placeholder="Message" required></textarea><br><br>
<!-- For sending the simple math-exercise to the server -->
<input id='read' name='read' value='read' style='display: none;'/>
<label id='exercise'></label><br>
<input type='number' id='solution' name='solution' placeholder="Solution" required/>
<div style='display: inline-block; text-align: left;'>
<input type="checkbox" id="consent" name="consent" value="consent" required="">
<label>I agree with saving and sending this message according to the privacy policy.
</label>
</div>
<input style='' type="submit" value="Send"/>
</form>
</div>
</div> <!-- End main-div -->
<script>
//Two random numbers for simple math-problem (spam-prevention)
let array = ["one", "two", "three",
"four", "five", "six",
"seven", "eight", "nine",
"ten"];
let item1 = array[Math.floor(Math.random() * array.length)];
let item2 = array[Math.floor(Math.random() * array.length)];
document.getElementById('exercise').innerHTML = item1 + " + " + item2 + " = ?";
document.getElementById("read").value = item1 + " + " + item2;
</script>
</main>
</body>
</html>
@media (max-width: 1000px) {
.input {
width: 100%;
padding: 10px 20px;
margin: 10px 0;
display: inline-block;
border: 1px solid black;
border-radius: 5px;
box-sizing: border-box;
background: LightGray;
}
}
@media (min-width: 1001px) {
.input {
width: 30%;
padding: 10px 20px;
margin: 10px 0;
display: inline-block;
border: 1px solid black;
border-radius: 5px;
box-sizing: border-box;
background: LightGray;
}
}
input[type=text] {
width: 100%;
padding: 10px 10px;
margin: 10px 0;
display: inline;
border: 1px solid Gray;
border-radius: 5px;
box-sizing: border-box;
}
input[type=submit] {
width: 100%;
padding: 10px 10px;
margin: 10px 0;
display: inline;
border: 1px solid Gray;
border-radius: 5px;
box-sizing: border-box;
}
input[type=number] {
width: 100%;
padding: 10px 10px;
margin: 10px 0;
display: inline;
border: 1px solid Gray;
border-radius: 5px;
box-sizing: border-box;
}
#website {
display: none;
}
PHP-Code
<?php
//Get simple math-problem (e.g. four + six)
$str = $_REQUEST['read'];
$first = strpos($str, " ");
//Get first number (e.g. four)
$substr1 = substr($str, 0, $first);
//Get second number (e.g. six)
$substr2 = substr($str, $first + 3, strlen($str) - $first - 3);
$arr = array("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten");
/*
* Convertring strings to numbers, e.g.
* four -> 4
* six -> 6
*/
$x = 0;
$y = 0;
for($i = 0; $i <= 10; $i++) {
if(strcmp($substr1, $arr[$i]) == 0) {
$x = $i;
break;
}
}
for($i = 0; $i <= 10; $i++) {
if(strcmp($substr2, $arr[$i]) == 0) {
$y = $i;
break;
}
}
$z = intval($_POST['solution']);
//Did user enter right solution?
if($z == ($x + $y)) {
//Bot filled the honeypott-tree
if(!empty($_POST['website'])) {
echo "Something went wrong";
die();
}
$userName = $_POST['myName'];
$userEmail = $_POST['myEmail'];
$userMessage = $_POST['myMessage'];
//Did user enter a valid email-adress?
if(!filter_var($userEmail, FILTER_VALIDATE_EMAIL)) {
echo "Something went wrong";
die();
}
//Creating message
$to = "[email protected]";
$subject = "New Contact-form message";
$body = "Content:";
$body .= "\n\n Name: " . $userName;
$body .= "\n\n Email: " . $userEmail;
$body .= "\n\n Message: " . $userMessage;
//Trying to send message
if(mail($to, $subject, $body)){
echo "Thank you for your message";
die();
} else{
echo "Something went wrong";
die();
}
}
echo "Something went wrong";
?>
Question(s)
I am especially interested in suggestions to improve the php-code.
- Did I follow best-practices?
- Is anything in the code a really bad idea?
Another thing I am interested in is the safety of this approach. How can it improved further?
Of course all other suggestions are appreciated as well.