How to make a PHP Guestbook with Math Captcha Security

Tutorials

Today I will tell you how to create your own guestbook with spam protection system – math captcha. This will and easy for your members and also good new protection from bots. In our guestbook we will use mySQL to store records.

Here are samples and downloadable package:

Live Demo
download in package

Ok, download the source files and lets start coding !


Step 1. SQL

Firstly – we should prepare SQL table to store records of our guestbook. Execute next SQL:

1 CREATE TABLE `s_guestbook` (
2 `id` INT(11) NOT NULL AUTO_INCREMENT,
3 `ip` varchar(16) NOT NULL default '',
4 `namevarchar(32) NOT NULL default '',
5 `message` text  NOT NULL,
6 `whenINT(11) NOT NULL,
7 PRIMARY KEY (`id`)
8 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

We will be storing IP of sender, his name, message itself, and time of adding post (timestamp)

Step 2. CSS

Here are used CSS styles. Just few styles for our demo page:

css/main.css

1 body{background:#eee;font-family:VerdanaHelveticaArialsans-serif;margin:0;padding:0}
2 .example{background:#FFF;width:625px;font-size:80%;border:1px #000 solid;margin:3.5em auto 2em;padding:1em 2em 2em}
3 .post {border:1px #DDD dashed;margin:5px;padding:5px;font-size:11px;width:95%}
4 .example form div{margin-bottom:5px;}

Step 3. PHP

Ok, here are all used PHP file:

index.php

01 <?php
02
03 // set error reporting level
04 if (version_compare(phpversion(), '5.3.0''>=') == 1)
05   error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
06 else
07   error_reporting(E_ALL & ~E_NOTICE);
08
09 require_once('inc/guestbook.inc.php');
10 $oGuestbook new Guestbook();
11
12 $sRes '<h2>You can add your post here</h2>';
13 if ($_POST['post'] != '' && $_POST['name'] != '' && $_POST['captcha'] != '') { // if something posted
14     $iCaptcha = (int)$_POST['captcha'];
15     $iCaptchaHash = md5($iCaptcha);
16     session_start();
17     $iOldCaptchaHash $_SESSION['captcha_res'];
18
19     if ($iCaptchaHash == $iOldCaptchaHash) { // perform posting
20         $oGuestbook->addPost($_POST['name'], $_POST['post']);
21         $sRes '<h2>Your post successfully posted</h2>';
22     else {
23         $sRes '<h2>Captcha incorrect</h2>';
24     }
25 }
26
27 list($sQuestion$iRes) = $oGuestbook->getMathCaptcha();
28 $sPosts $oGuestbook->getAllPosts();
29
30 // our page template
31 $sPageCode = <<<EOF
32 <link rel="stylesheet" href="css/main.css" type="text/css" />
33 <div class="example">
34     <h3><a href="#">PHP Guestbook with using math captcha</a></h3>
35     <div>
36         <div style="margin-bottom:10px;">
37             <h4>{result}</h4>
38             <form method="post" action="index.php">
39                 <div>Your name:</div>
40                 <div><input type="text" name="name" value="" /></div>
41                 <div>Your guestbook post:</div>
42                 <div><textarea name="post"></textarea></div>
43                 <div>Captcha:</div>
44                 <div>{captcha}</div>
45                 <div>Verification (Type what you see):</div>
46                 <div><input type="text" name="captcha" value="" /></div>
47                 <div><input type="submit" name="submit" value="Submit" /></div>
48             </form>
49         </div>
50         <div>
51             <h4>Other Guestbook posts</h4>
52             {guestbook_posts}
53         </div>
54     </div>
55 </div>
56 EOF;
57
58 $aReplaces array(
59     '{captcha}' => $sQuestion,
60     '{result}' => $sRes,
61     '{guestbook_posts}' => $sPosts,
62 );
63 echo strtr($sPageCode$aReplaces);
64
65 ?>

This file draw us posting form with math captcha, also it checking typed posted captcha value, and if all fine – then allow to add post. Also, as you noticed, I started using ‘strtr’ function in generation of result HTML code. Very easy to replace keys to values in template file via array of replaces.

inc/guestbook.inc.php

01 <?php
02
03 // guestbook class
04 class Guestbook {
05
06     // DB variables
07     var $sDbName;
08     var $sDbUser;
09     var $sDbPass;
10
11     // constructor
12     function Guestbook() {
13         $this->sDbName = 'DB_NAME';
14         $this->sDbUser = 'DB_USER';
15         $this->sDbPass = 'DB_PASS';
16     }
17
18     // adding to DB table posted record
19     function addPost($sNameUnsafe ''$sPostUnsafe '') {
20         if ($sPostUnsafe != '') {
21             $vLink = mysql_connect('localhost'$this->sDbUser, $this->sDbPass); // the host, name, and password for your mysql
22             mysql_select_db($this->sDbName); // select the database
23             $sName = mysql_real_escape_string(strip_tags($sNameUnsafe));
24             $sMessage = mysql_real_escape_string(strip_tags($sPostUnsafe));
25             $iVisitorIp $this->getVisitorIp();
26             if ($sMessage != '' && $iVisitorIp)
27                 mysql_query("INSERT INTO `s_guestbook` SET `ip`='{$iVisitorIp}', `name`='{$sName}', `message`='{$sMessage}', `when`=UNIX_TIMESTAMP()");
28
29             mysql_close($vLink);
30         }
31     }
32
33     function getAllPosts() {
34         $vLink = mysql_connect('localhost'$this->sDbUser, $this->sDbPass);
35         mysql_select_db($this->sDbName); // select the database
36         $vRes = mysql_query('SELECT * FROM `s_guestbook` ORDER BY `id` DESC LIMIT 15'); // returning the last 15 posts
37
38         $sMessages '';
39         if ($vRes) {
40             while($aMessages = mysql_fetch_array($vRes)) {
41                 $sWhen date('H:i:s'$aMessages['when']);
42                 $sMessages .= '<div class="post">' $aMessages['name'] . ': ' $aMessages['message'] . '<span> (' $sWhen ')</span></div>';
43             }
44         else {
45             $sMessages 'DB error, create SQL table before';
46         }
47         mysql_close($vLink);
48         return $sMessages;
49     }
50
51     function getMathCaptcha() {
52         $aOps array('+''-''*'); // possible operators
53         $iVal1 = rand(1,10); // first variable
54         $iVal2 = rand(1,10); // second variable
55
56         $i array_rand($aOps, 1); // random operator index
57         $sRandOp $aOps[$i]; // random operator
58         $sQuestion "{$iVal1} {$sRandOp} {$iVal2}"// generation of question
59         $sQuestionEval "\$iRes = {$iVal1} {$sRandOp} {$iVal2};";
60         eval($sQuestionEval);
61
62         session_start();
63         $sHashRes = md5($iRes);
64         $_SESSION['captcha_res'] = $sHashRes// store md5 result in session param
65
66         return array($sQuestion$iRes);
67     }
68
69     function getVisitorIp() {
70         $ip '0.0.0.0';
71         if ((isset($_SERVER['HTTP_X_FORWARDED_FOR'])) && (! empty($_SERVER['HTTP_X_FORWARDED_FOR']))) {
72             $ip $_SERVER['HTTP_X_FORWARDED_FOR'];
73         elseif ((isset($_SERVER['HTTP_CLIENT_IP'])) && (! empty($_SERVER['HTTP_CLIENT_IP']))) {
74             $ip explode('.',$_SERVER['HTTP_CLIENT_IP']);
75             $ip $ip[3].'.'.$ip[2].'.'.$ip[1].'.'.$ip[0];
76         elseif ((! isset($_SERVER['HTTP_X_FORWARDED_FOR'])) || (empty($_SERVER['HTTP_X_FORWARDED_FOR']))) {
77             if ((! isset($_SERVER['HTTP_CLIENT_IP'])) && (empty($_SERVER['HTTP_CLIENT_IP']))) {
78                 $ip $_SERVER['REMOTE_ADDR'];
79             }
80         }
81         return $ip;
82     }
83 }
84
85 ?>

This is library class for our Guestbook. It contain several necessary functions: addPost – for adding new posts, getAllPosts – return us last 15 records from database, getMathCaptcha – get math capthca, getVisitorIp – get visitor IP (which we will storing for records)


Live Demo
download in package

Conclusion

I hope that made interesting sample today, its contain two interesting ideas – creating Guestbook itself plus Math captcha to protect from bots. Good luck!

Rate article