RegalCoding.com

A Programming Blog

Hello mobile user!

Contact form and simple captcha authentication

In order to allow visitors to contact me, I needed some type of email link or contact form on the site.

The simplest way to accomplish this is by just placing an email link on the site somewhere; however to me this doesn't look quite as nice as an integrated email form, and it opens the door for other problems.

For one thing, simply placing your email address on a site invites scrapers and crawlers to find it, at which point you'll start getting lots of spam emails. Encoding the email address with javascript used to be an effective deterrent to the scrapers, however modern scrapers can now parse javascript and decode the address anyway.

In light of that, my favorite method is an integrated email form with a custom captcha. Why not just use recaptcha or something commercially available? Well, it's fairly trivial to make my own, and it works well enough to prevent the majority of automated requests.

Here's some code snippets to illustrate how I added this email form, CSS style has been removed for clarity:

<form action='/mailer.php' method='post' name='form1' id='form1'>
Your e-mail:<br>
<input name='from' type='text' id='from' value=''><br><br>
Subject:<br>
<input name='subject' type='text' id='subject' value=''><br><br>
Type verification image:<br>
<input name='verif_box' type='text' id='verif_box'>
<?php echo "<img src='verificationimage.php?". rand(0, 9999)." alt='verification image, type it in the box' width='60' height='24' align='absbottom'><br><br>n";
//if the variable "wrong_code" is sent from previous page then display the error field
if (isset($_GET['wrong_code'])) {
	echo "<div>Wrong verification code</div><br>n";
}
?>
Message:<br>
<textarea name='message' cols='6' rows='5' id='message'></textarea>
<input name='Submit' type='submit'  value='Send Message'>
</form>


The code above contains a reference to verificationimage.php, the code of which is listed below:

<?php
header('Content-type: image/jpeg');

$width = 60;
$height = 24;

$my_image = imagecreatetruecolor($width, $height);

imagefill($my_image, 0, 0, 0xFFFFFF);
// add noise
$red=mt_rand(0,125);
$green=mt_rand(0,125);
$blue=mt_rand(0,125);
$color1=imagecolorallocate($my_image,$red,$green,$blue);
$red=mt_rand(125,255);
$green=mt_rand(125,255);
$blue=mt_rand(125,255);
$color2=imagecolorallocate($my_image,$red,$green,$blue);
for ($c = 0; $c < 480; $c++) {
	if ($c%2==0) {
		$color=$color1;
	} else $color=$color2;
    $x = rand(0, $width-1);

    $y = rand(0, $height-1);

	imagesetpixel($my_image, $x, $y, $color);
    //imagesetpixel($my_image, $x, $y, 0x000000);
}

$x = rand(1, 10);
$y = rand(1, 10);
$rand_string = rand(10000, 99999);
imagestring($my_image, 5, $x, $y, $rand_string, 0x000000);

setcookie('tntcon', (md5($rand_string) . 'a4xn'));

imagejpeg($my_image);
imagedestroy($my_image);

?>

This just produces an image containing a random number in a slightly random location, and it gets dithered with some dots of random color pairs. It also sets a cookie containing a salted hash of the random number, so that the form may verify your input.

Finally, that form posts to another file called mailer.php, which is similar to the code below:

<?php
if (!function_exists(GetSerializedArray)) {
    function GetSerializedArray($path)
    {
        $str = get_contents_flock($path);
        $array = @unserialize($str);
        if (is_array($array)) {
            return $array;
        } else return false;
    }
}

if (!function_exists(get_contents_flock)) {
    function get_contents_flock($file)
    {
        if (@file_exists($file)) {
            $fp = @fopen($file, 'rt');
            if ($fp === false) {
                return false;
            } else {
                if (@flock($fp, LOCK_SH) === false) {
                    return false;
                } else {
                    $contents = @file_get_contents($file);
                    if ($contents === false) {
                        return false;
                    } else {
                        @flock($fp, LOCK_UN);
                        @fclose($fp);
                        return $contents;
                    }
                }
            }
        } else return false;
    }
}

// load the variables form address bar
$subject = $_POST["subject"];
$subject = filter_var($subject, FILTER_SANITIZE_SPECIAL_CHARS);
$message = $_POST["message"];
$message = filter_var($message, FILTER_SANITIZE_SPECIAL_CHARS);
$from = $_POST["from"];
$from = filter_var($from, FILTER_SANITIZE_EMAIL);
$verif_box = $_POST["verif_box"];
// remove the backslashes that normally appears when entering " or '
$message = stripslashes($message);
$subject = stripslashes($subject);
$from = stripslashes($from);
// check to see if verificaton code was correct
if (md5($verif_box) . 'a4xn' == $_COOKIE['tntcon']) {
    // if verification code was correct send the message and show this page
    $Config_Global = GetSerializedArray("path/to/file.dat");
    $ScriptDomain = $_SERVER["HTTP_HOST"];
	if (stripos($ScriptDomain, "www.") === 0) {
	    $ScriptDomain = substr($ScriptDomain, 4);
	}
    mail("$Config_Global[eMail]", $ScriptDomain.' Form: ' . $subject, $_SERVER['REMOTE_ADDR'] . "nn" . $message, "From: $from");
    // delete the cookie so it cannot sent again by refreshing this page
    setcookie('tntcon', '');
?>
<!DOCTYPE html>
<!-- Created Sun Nov 10 21:31:49 2019 -->
<HTML>
<HEAD>
<TITLE><?php echo $ScriptDomain; ?> Form</TITLE>
<meta http-equiv = "refresh" content = "1; url = https://regalcoding.com" />
</HEAD>
<BODY BGCOLOR="#FFFFFF" TOPMARGIN=0>
<center>Thank you, your message has been sent.</center>
</body>
</HTML>
<?php
} else if (isset($message) and $message != "") {
    // if verification code was incorrect then return to contact page and show error
    header("Location:" . $_SERVER['HTTP_REFERER'] . "&subject=$subject&from=$from&wrong_code=true&message=$message");
    exit;
} else {
    echo "no variables received, this page cannot be accessed directly";
    exit;
}

?>


The mailer.php will either generate an error message, or send the email, issue a confirmation response, and then forward back to the index.

It would probably be a bit easier to simply integrate recaptcha or something like that from a 3rd party. The reason I chose this method is twofold; one, I already had the code from previous projects, and two, since this blog is supposed to showcase my programming abilities it should contain primarily my own code.

Category: Cms