A minap, a projekt amin dolgozom megkövetelte, hogy mindenki számára elérhető űrlapokat védjünk le valamilyen szinten a webes spam illetve egyébb kereső robotok elől, mindezt azért, hogy ne tudjanak automatikusan beregsztrálni levelet küldeni azaz spammel ellátni. Ennek kivédésre egyre több helyen, alkalmaznak captcha megoldásokat.
Mi is ez a Captcha?
Biztos már mindenki találkozott azzal amikor szeretne regisztrálni, és a regisztrációs űrlapon lát egy képet, alatta mellette egy mezővel, hogy mi szerepel a képen? A képen általában deformált betük számok jelennek meg, ez azért jó mert a webet böngésző robotok még nem olyan kifinomultak, hogy a képen található betüket számokat ábrákat kiszűrjék s regisztrálni tudjanak. Mint mindenki más én is rákerestem a captcha Zend framework kulcszavakra googleban, ekkor bukkantam a következő http://blog.ekini.net/2007/10/29/simple-captcha-with-zend-framework/ oldalra, tökéletes egyszerű kis megoldás, annyi bajom volt vele, hogy a generatecaptchaAction() kimenete egy kép amit simán kiküld a böngésző adott oldalára és a header utasításban az oldal tartalma image/jpeg lesz ergó ezt így használni nem lehet űrlapok esetén, de az elgondolás az alapötlet remek.
Kis módosítással ezt mi is beletesszük a kapcsolat űrlapunkhoz, ugyanis nem spamáradatot várunk hanem ügyfeleket
Nem eseményként, készítjük el, hanem modelként azaz a korábban létrehozott, MVC modellünkben az application\models\ könyvtárban létrehozunk egy Captcha modelt, így ezt majd több űrlapon is használni tudjuk, a fenti említett blogon található kódot én kiegészítettem pár + vonallal, átméreteztem a képet, aki akarja át is színezheti kénye kedve alapján. Így a Captcha.php model obejtktumom tartalma a következőképpen néz ki:
<?php
class Captcha
{
public function generatecaptcha()
{
//Let's generate a totally random string using md5
$md5_hash = md5(rand(0,999));
//We don't need a 32 character long string so we trim it down to 5
$security_code = substr($md5_hash, 15, 5);
$captchaSession = new Zend_Session_Namespace('captcha');
$captchaSession->captcha = $security_code;
//Set the image width and height
$width = 70;
$height = 30;
//Create the image resource
$image = ImageCreate($width, $height);
//We are making three colors, white, black and gray
$white = ImageColorAllocate($image, 255, 255, 255);
$black = ImageColorAllocate($image, 0, 0, 0);
$grey = ImageColorAllocate($image, 204, 204, 204);
$mas = ImageColorAllocate($image, 23, 189, 45);
//Make the background black
ImageFill($image, 0, 0, $black);
//Add randomly generated string in white to the image
ImageString($image, 10, 10, 10, $security_code, $white);
//Throw in some lines to make it a little bit harder for any bots to break
ImageRectangle($image,0,0,$width-1,$height-1,$grey);
imageline($image, 0, $height/3, $width, $height/4, $grey);
imageline($image, 0, $height/5, $width, $height/2, $grey);
imageline($image, 0, $height/7, $width, $height/1, $grey);
imageline($image, $width/5, 0, $width/3, $height, $mas);
imageline($image, $width/2, 0, $width/6, $height, $mas);
//Output the newly created image in jpeg format
ImageJpeg($image, '../tmp/captcha.jpg');
imagedestroy($image);
}
}
?>
Apróbb változtatásokat eszközöltem sessionba a következőképpen teszem el pl.:
$captchaSession = new Zend_Session_Namespace('captcha');
$captchaSession->captcha = $security_code;
A header utasítás, kiszedtem mivel én lementem majd a képet a
ImageJpeg($image, '../tmp/captcha.jpg');
Utasítás segítségével lementem a tmp könyvtáramba captcha.jpg néven
Majd ezután az $image változót megszüntetem az imagedestroy() utasítás segítségével, a szerver memóriája felszabadul, fontos momentum, ha sokan használják az portálunk ne feledkezzünk meg róla!
Ennek az objektumnak, elengedhetetlen feltétele, hogy a szeverünkön a PHP GD kiterjesztés 1.8-as vagy annál újjabb kiterjesztése fusson, különben a futás elakad!
Most már van chaptcha képünk a hozzátartozó kódot a munkamenethez illesztettük, most ki kell rajzolni a képet a kapcsolat űrlap meghívása esetén, egy mezőt kell kitenni amibe a felhasználónk a captcha kódot be tudják írni, majd a feldolgozásnál ezt leellenőrizni.
Az IndexController/kapcsolatAction() eseményét egészítsük ki azzal, hogy a nézetnek (kapcsolat űrlap) számára elkészítünk egy új képet.
Az IndexController.php fájlunk elejére írjuk be a következőt:
require_once 'models/Captcha.php';
Ekkor a Controller számára elérhetővé válik a Captcha.php modelünk.
A kapcsolatAction() sorait egészítsük ki ezzel:
Captcha::generatecaptcha();
Azaz meghívjuk a captcha generáló függvényt, ami elkészíti a tmp könyvtárba az új captcha képet s a kódot a munkamenethez adja.
Ha ez megvan akkor a kapcsolatAction()-höz tartozó kapcsolat.phtml soraiban található űrlapot egészítsük ki a következővel:
<tr><td><?php echo $this->formLabel('captcha','Captcha Kód:');?></td>
<td><img src="../../tmp/captcha.jpg" /></td></tr>
<tr><td><?php echo $this->formLabel('entered_coded','Adja meg a képen látható karaktereket:');?></td>
<td><?php echo $this->formText('entered_coded', $this->escape($this->entered_coded), array('onFocus'=>'this.select();'));?></td></tr>
Két új sor a táblázatban a képpel és a beviteli mezővel:

Zend Framework Captcha - Demó Kft - kapcsolat űrlap
Most le kell kezelnünk a captcha kód helyességét, azaz látogassunk el processKapcsolatAction() eseményre. Szedjük ki az űrlapelemekből a begépelt captcha mező tartalmát így:
$entered_captcha = Zend_Filter::get($this->getRequest()->getPost('entered_coded'), 'StripTags');
Ha ez megvan, az űrlap kitöltését ellenörző if utasítást módosítsuk erre:
if($k_email=='' || $k_targy=='' || $k_uzenet=='' || $entered_captcha==''){
Ekkor leellenőrzödik, hogy minden mező kitöltésre került e. Ha minden rendben van az email küldés előtt ellenőrizzük le a captcha kódot, azaz az felhasználó által begépelt kód megegyezik e a munkamenethez csatolt kóddal. Kiszedjük a munkamenethez csatolt kódot és lementjük captchakod néven:
$captchaSession = new Zend_Session_Namespace('captcha');
if($captchaSession->captcha) {
$captchakod = $captchaSession->captcha;
}
Ha ez megvan nyitunk egy új if utasítást, ahol leellenőrizzük a begépelt és a munkamenetben található kód egyezőségét. Ha nem egyeznek meg, a felhasználónak egy “A captcha kód nem megfelelő!” hibaüzenet jelenik meg és visszadobjuk a kapcsolat oldalra:
if ($entered_captcha != $captchakod) {
$this->_helper->flashMessenger->addMessage("A captcha kód nem megfelelő!");
$this->_redirect('/index/kapcsolat');
}
ha megfelel akkor az if utasítás else ága fut, le azaz az email küldés megtörténik. Lássuk egybe az IndexController/processKapcsolatAction ját:
public function processKapcsolatAction()
{
$entered_captcha = Zend_Filter::get($this->getRequest()->getPost('entered_coded'), 'StripTags');
$k_email = Zend_Filter::get($this->getRequest()->getPost('k_email'), 'StripTags');
$k_targy = Zend_Filter::get($this->getRequest()->getPost('k_targy'), 'StripTags');
$k_uzenet = Zend_Filter::get($this->getRequest()->getPost('k_uzenet'), 'StripTags');
if($k_email=='' || $k_targy=='' || $k_uzenet=='' || $entered_captcha==''){
//ha van olyan mező ami nincs kitöltve akkor "Kérem töltsön ki minden mezőt!"
//felírat jelenjen meg
$this->_helper->flashMessenger->addMessage("Kérem töltsön ki minden mezőt!");
$this->_redirect('index/kapcsolat');
}
else{
//minden mező ki van töltve
$captchaSession = new Zend_Session_Namespace('captcha');
if($captchaSession->captcha) {
$captchakod = $captchaSession->captcha;
}
if ($entered_captcha != $captchakod) {
$this->_helper->flashMessenger->addMessage("A captcha kód nem megfelelő!");
$this->_redirect('/index/kapcsolat');
}
else{
$emailValidator = new Zend_Validate_EmailAddress();
if ($emailValidator->isValid($k_email)) {
//ha valid
$mail = new Zend_Mail();
$mail->setBodyText($k_uzenet);
$mail->setFrom($k_email);
$mail->addTo('info@demokft.hu');
$mail->setSubject($k_targy);
$mail->send();
$this->_helper->flashMessenger->addMessage("Az üzenet sikeresen elküldésre került! Munkatársunk, hamarosan felveszi önnel a kapcsolatot");
$this->_redirect('index/kapcsolat');
}
else{
//minden más esetben
$this->_helper->flashMessenger->addMessage("Az email cím nem felel meg!");
$this->_redirect('index/kapcsolat');
}
}
return true;
}
} // public function processKapcsolatAction()
Ezzel a megoldással, valamilyen szinten sikerült levédenünk kapcsolat oldalunkat a webet böngésző spamrobotok elől.
Minden egyes kapcsolat oldal megtekintésnél, mindig új képet generálunk le,a mit ugyanoda mentünk le captcha.jpeg néven. Webszerver esetén, ne feledkezzünk meg tmp könyvtárunkra írási jogot adjunk, ugyanis ha ezt nem tesszük meg, alkalmazásunk nem tud képet menteni oda. Ennek következménye képpen a kép nem jelenik meg a kapcsolat oldalon, a felhasználónk nem tud mit begépelni s mindig hibaüzenetet kap ez a jobbik eset. Rosszabbik esetben a kapcsolat oldal és így a portálunk sem jelenik meg. Egy szó mint száz figyeljünk, arra hogy tmp könyvtárunkra írási jogunk legyen!