GD v praxi - Overovací kód v obrázku
GD v praxi - Overovací kód v obrázku
Po seriály "Práca s GD knižnicou" prichádza nový článok a to PHP v praxi. Cieľom bude dosiahnúť odoslanie dát prostredníctvom formuláru, ktoré bude fungovať iba v prípade, ak opíšete s obrázku náhodne vygenerovaný text.

Jelikož jsme si toho o GD řekli už dost měli bychom přejít k příkladům v praxi. Jistě znáte např. při přihlašování, psaní komentáře, že je tam obrázek, z kterého musíte opsat text aby jste mohli dále pokračovat. Tak přesně toto si dnes uděláme. Budeme k tomu potřebovat obrázek pojmenovaný pozadi2.png, pravděpodobně i font arial.ttf (naleznete ve složce s windows/fonts) a trochu času.
Pozadi2.png
Budeme používat pár funkcí, o kterých jsme si ještě neřekli. A to rand a char.
Rand (od, do)
Funkce generuje náhodné číslo v zadaném rozmezí.
Char (cislo)
Funkce převede číslo na znak podle ascii tabulky. V ascii tabulce je každý znak reprezentován nějakým číslem. ASCII tabulkou se dále nebudu zabývat (to není náplní tohoto článku). Tuto funkci použijeme proto, že funkce rand dokáže generovat pouze náhodné číslo. A mi potřebujeme i písmena A-Z, a-z. Zde vidíte tabulku bez netisknutelných znaků (proto začíná až číslem 32)
A jdeme na to…...
<?php
session_start();
$obrazek = imagecreatefrompng("pozadi2.png");
Jelikož nějak musíme ověřit, zdali bylo zadáno správné heslo použijeme pro to
session. Vytvoříme obrázek z našeho pozadi2.png.
for ($i=0;$i<5;$i++)
{
while(strlen($str)!=1){
$random=rand(48,123);
if( ($random>47 && $random<58) || ($random>96 && $random<123) ||
($random>64 && $random<91) ){
$str.=chr($random);
}
}
$text .= $str;
$textcolor = imagecolorallocate($obrazek,rand(0,130),rand(0,130),rand(0,130));
imagettftext ($obrazek,rand(15,25),rand(-45,45),15+($i*38),35, $textcolor,"arial.ttf",$str) ;
$str = NULL;
}
Následuje cyklus for, který nám zajistí vygenerování 5 znaků do obrázku. Cyklus
While se bude provádět tak dlouho dokud se do $radon nevygeneruje číslo které
podle ascii přestavuje námi požadované znaky. Když se vygeneruje správné číslo
provede se $str.=chr($random); což nám do $str přiřadí znak z vygenerovaného
čísla podle ascii. Když už se to provede přidá se písmeno do proměnné $text
(abychom i na konci cyklu for věděli jaký text jsme vygenerovali. Poté se provede
imagecolorallocate kde se pomocí funkce rand vygenerují hodnoty pro barvu
(abychom v obrázku měli různé barvy). No a nakonec se to vypíše velikostí 15-25,
pod úhlem -45° až 45° fontem arial. $str se vynuluje a to celé se opakuje 5*.
$_SESSION['string']=$text;
header("Content-type: image/png");
imagepng($obrazek);
imagedestroy ($obrazek)
?>>
Nyní se do session uloží $text ve které je zapsán celý vygenerovaný text. Odešle
se hlavička, obrázek a uvolní se systémové prostředky. Tak a máme celý kód na
generování obrázku.
Jedinou chybu na kráse to má že díky odesílání session nemůžeme před kód dát nic jiného. Takže kód je ještě potřeba trochu upravit, aby se session mohlo odeslat i když je kód třeba v formuláři. To už nechám na vás…. Následující kód představuje jak by jste to mohli udělat.
<?php
session_start();
if (!isset($_GET['generuj'])) {
for ($i=0;$i<5;$i++)
{
while(strlen($str[$i])!=1){
$random=rand(48,123);
if( ($random>47 && $random<58) || ($random>96 && $random<123) ||
($random>64 && $random<91) ){
$str[$i] = chr($random);
}
}
$text .= $str[$i];
}
$_SESSION['string']= $text;
$GLOBALS['text'] = $text;
}
elseif (isset($_GET['generuj'])){
$GLOBALS['text'] = $_SESSION['string'];
$obrazek = imagecreatefrompng("pozadi2.png");
for ($i=0; $i<5; $i++){
$textcolor = imagecolorallocate($obrazek,rand(0,130),rand(0,130),rand(0,130));
$pismenko = substr($GLOBALS['text'],0+$i,1);
imagettftext ($obrazek,rand(15,25),rand(-45,45),15+($i*38),35, $textcolor,"arial.ttf",$pismenko) ;
}
header("Content-type: image/png");
imagepng($obrazek);
imagedestroy ($obrazek);
exit();
};
?>
<?php echo '<?xml version="1.0" encoding="ISO-8859-2"?>'; ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="cz">
<head>
<!-- meta tags and language -->
<meta http-equiv="content-language" content="cz" />
<meta name="language" content="cz" />
<meta name="document-language" content="cz" />
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-2" />
<title>Ukázkový formulář</title>
</head>
<body>
<form method="post" action="kontrola.php">
<fieldset>
<img src = "formular.php?generuj" alt="code"/><br/>
Opis kod:<input type="text" name="kod" size="24"/> <br/>
Vase zprava:<br/>
<textarea rows="7" name="text" cols="31"></textarea><br/>
<input type="submit" value="Odeslat" name="odeslat"/>
<input type="reset" value="Obnovit" name="obnovit"/>
</fieldset>
</form>
</body>
</html>
A nakonec jen soubor kontrola.phpZde stačí dát něco ve smyslu.
<?
if( $_SESSION['string'] == $_POST['kod'] )
{
echo 'Ano kód jsi opsal správně. Gratuluji';
// váše zpracování zprávy
}
else
{
echo 'Spamery nemám rád.... Zadal jsi špatný kód';
}
?>
Výsledky(príklady):
A na úplný závěr si zde můžete stáhnout celý skript i s pokusným formulářem. Nebo se na skript podívat na: http://vyrvarimweb.wz.cz/formular.php(formulář) a http://vyrvarimweb.wz.cz/kod.php (jen generování obrázku). Celý zdrojový kód si můžete stáhnout zde.
Autor: Los.Pavlos ·
Kategória: Programovanie ·
Dátum: 16.07.2005 16:42


![Hlasová verzia [Pre internetový prehliadač Opera] Voice](modules/items/voice.png)
Komentáre
Niektorí to majú vyriešené tak, že príspevok sa môže poslať emailom, pokiaľ nevidia obrázok. A to všetko by malo byť práve v title="".
Inak, veľmi dobrý úvodný seriál ku GD. Nebude podrobnejšie pokračovanie?
Představ si že tuhle captchu použiju při odeslání komentáře k článku. Přijdu na index s mým oblíbeným Firefoxem, dostanu od php svoje PHPSSID, naklikám si články do tabů a budu třeba u dvou z nich chtít přidat komentář.
Jenomže - právě protože jsem si stránku rozklikal do tabů, mám u každé stejný phpssid - a s každým generováním se mi v session přepíše hodnota stringu který se porovnává při validaci...
Takže validace proběhne správně jen u naposledy generovaného obrázku (v tomhle příkladě u tabu který jsem si otevřel naposledy). Všechny ostatní taby budou sice zobrazovat v captche unikátní kód, ale při porovnání budou očekávat jen ten jeden poslední...
Špatně se to vysvětluje, proto tady píšu jak by mělo vypadat ověřování - snad to pochopíte z něj...
if( $_SESSION[$unikatni_id]['string'] == $_POST['kod'])
Z toho ovšem vyvstává problém že ono $unikatni_id musí být předáno zároveň s formulářem, ale to také není problém. Úplně totiž stačí přidat:
<input type="hidden" name="unikatni_id" value="<?=$unikatni_id>">
Na generování unikátního ID jsem si já osobně napsal takovou sladkou funkci
function getMyUID(){
return substr(md5(time()+rand(0,100)), rand(0,16), rand(17,32));
}
Navíc, představ si že odešlu spam. Obrázek musím opsat jen poprvé, pak už stačí se jakkoliv vyhnout znovuvygenerování obrázku který by mi přepsal session (případně pokud kód rozšíříš o mnou navrhované unikatni_id tak si ani s tím nemusím lámat hlavu) a můžu zvesela používat k validaci starý kód znova a znova a znova a znova.
Řešení je také prosté, stačí jednoduše po dokončení validace přidat
unset($_SESSION[$unikatni_id]['string']);Jinak až na tuhle chybnou implementaci super tutorial, naučil mě jak se naklápí písmenka
Ahoj prostrednictvom toho inputu s typom hidden by som to nerobil lebo v html je mozne vycitat hodnotu kodu s unikatnym kodom a to potom uz sa nemusa ani ta captcha pouzivat