Archive for March, 2009
Captcha – Confirmação Visual
Depois de um bom tempo com o blog parado, vou voltar explicando um modo de desenvolver um captcha utilizando a biblioteca GD do php. O captcha é um teste de turing reverso, pois é a máquina que testa se o usuário é humano. Este teste evita que sistemas automatizados enviem spans pelos formulários de seu site.
A idéia é bem simples. Vamos ter um arquivo php que gera uma imagem, podendo ser exibido como se de fato fosse uma imagem:
<img src=”geraImagemConfirmacao.php” alt=”Captcha” />
Essa imagem será gerada, e o conteúdo gravado em um cookie. Este cookie será utilizado na ação de seu formulário, quando deverá ser comparado com o texto digitado pelo usuário. Vou procurar fazer o mais simples possível:
<form action=”acaoConfirmaCodigo.php” method=”post”><img src=”geraImagemConfirmacao.php” alt=”Captcha” />
<input name=”palavraUsuario” type=”text” /><input type=”submit” />
</form>
Salve este arquivo com um nome qualquer.
No arquivo acaoConfirmaCodigo.php, coloque algo do tipo:
<?php
$palavraUsuario = strtolower($_POST['palavraUsuario']);
$palavraGerada = strtolower($_COOKIE['palavraGerada']);if($palavraUsuario == $palavraGerada)
echo “Confirmação visual correta.”;
else
echo “Por favor, tente novamente.”;
?>
O que este arquivo faz nada mais é do que pegar a palavra digitada pelo usuário (enviada pelo POST) e a palavra armazenada no cookie, passando ambas para a forma minúscula, e então comparando-as.
Agora vamos à parte realmente interessante, o arquivo geraImagemConfirmacao.php:
<?php
$larguraImg = 100;
$alturaImg = 30;$espacoMinLetrasX = 15;
$espacoMaxLetrasX = 20;$espacoMinLetrasY = 5;
$espacoMaxLetrasY = 10;$numLetras = 4;
$letras = array(‘2′,’3′,’4′,’5′,’6′,’7′,’8′,’9′, ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘Z’, ‘K’, ‘M’, ‘X’);
// cria uma imagem
$imagem = imagecreate($larguraImg, $alturaImg);/* Cores para utilizar na imagem imagem */
$cinza = imagecolorallocate($imagem,0xF8,0xF8,0xF8);
$cinza_escuro = imagecolorallocate($imagem,0xAC,0xAC,0xAC);
$vermelho = imagecolorallocate($imagem,0xFF,0×00,0×00);
$azul = imagecolorallocate($imagem,0×0F,0×93,0xFF);
$verde = imagecolorallocate($imagem,0×00,0×66,0×00);
$preto = imagecolorallocate($imagem,0×00,0×00,0×00);
$laranja = imagecolorallocate($imagem,0xFF,0×8C,0×24);$cores = array($vermelho, $azul, $verde, $preto);
$tamanho_letras = count($letras)-1;
$tamanho_cores = count($cores)-1;/* Escrevendo as letras… */
$palavraGerada = ”;
$x = 0;for($i=0;$i<$numLetras;$i++){
$x += rand($espacoMinLetrasX, $espacoMaxLetrasX); //localizacao horizontal
$y = rand($espacoMinLetrasY, $espacoMaxLetrasY);$j = rand(0,$tamanho_cores);
$k = rand(0,$tamanho_letras);
$palavraGerada .= $letras[$k];imagestring($imagem, 5, $x, $y, $letras[$k], $cores[$j]); //escreve a letra na imagem
}setcookie(‘palavraGerada’, $palavraGerada, time()+7200);
header(“Content-type: image/jpeg”);
imagejpeg($imagem);
imagedestroy($imagem);
?>
A primeira parte é apenas para configurar a imagem que será gerada:
$larguraImg = 100;
$alturaImg = 30;
Note que essas dimensões têm que ser compatíveis com a quantidade de letras e o espaçamento das letras que você deseja gerar, caso contrário algumas letras ficarão fora da imagem simplesmente por falta de espaço.
$espacoMinLetrasX = 15;
$espacoMaxLetrasX = 20;
$espacoMinLetrasY = 5;
$espacoMaxLetrasY = 10;
$numLetras = 4;
Aqui são determinados os intervalos das posições das letras na imagem. Por exemplo, a posição horizontal (espaço entre as letras) irá variar de 15 a 20px. Para realizar essa variação, utilizamos a função rand(min, max) do php.
E também aqui é determinada a quantidade de letras que serão geradas na imagem.
$letras = array(‘2′,’3′,’4′,’5′,’6′,’7′,’8′,’9′, ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘Z’, ‘K’, ‘M’, ‘X’);
Esse array contém as letras que poderão ser sorteadas e aparecer na imagem. Procure evitar letras como O, I, L… e os números 0 e 1, pois podem ser confundidos com facilidade.
// cria uma imagem
$imagem = imagecreate($larguraImg, $alturaImg);/* Cores para utilizar na imagem imagem */
$cinza = imagecolorallocate($imagem,0xF8,0xF8,0xF8);
$cinza_escuro = imagecolorallocate($imagem,0xAC,0xAC,0xAC);
$vermelho = imagecolorallocate($imagem,0xFF,0×00,0×00);
$azul = imagecolorallocate($imagem,0×0F,0×93,0xFF);
$verde = imagecolorallocate($imagem,0×00,0×66,0×00);
$preto = imagecolorallocate($imagem,0×00,0×00,0×00);
$laranja = imagecolorallocate($imagem,0xFF,0×8C,0×24);$cores = array($vermelho, $azul, $verde, $preto);
Neste ponto, criamos a imagem, e associamos as cores que utilizaremos na imagem. Além disso, coloco no array $cores as cores que serão sorteadas para cada letra. (Note mais uma vez que você deve facilitar a vida do usuário, então utilize cores fortes nas letras).
$palavraGerada = ”;
$x = 0;
for($i=0;$i<$numLetras;$i++){$x += rand($espacoMinLetrasX, $espacoMaxLetrasX); //localizacao horizontal
$y = rand($espacoMinLetrasY, $espacoMaxLetrasY);$j = rand(0,$tamanho_cores);
$k = rand(0,$tamanho_letras);
$palavraGerada .= $letras[$k];imagestring($imagem, 5, $x, $y, $letras[$k], $cores[$j]); //escreve a letra na imagem
}
Aqui é onde acontece toda a mágica. É executado um laço, com o for varrendo a quantidade de letras de sua imagem, e para cada letra sortea-se a posição x e y, dentro do intervalo configurado. Note que o intervalo x deve ser incrementado a cada iteração, caso contrário todas as letras ficariam dentro de um mesmo intervalo na horizontal (experimente trocar o += por =, para ver como fica).
Também são sorteadas a letra e sua cor, dentro do array pré-determinado. Só então a letra é gravada na imagem, com a função imagestring() do php.
setcookie(‘palavraGerada’, $palavraGerada, time()+7200);
header(“Content-type: image/jpeg”);
imagejpeg($imagem);
Finalmente a imagem é gravada no cookie e criada na tela, utilizando o cabeçalho Content-type: image/jpeg. Pronto!
Se achar conveniente, você pode utilizar outras funções da GD como imagearc, imagelin.. para “dificultar” a visualização da imagem (cuidado para não deixar a imagem imcompreensível). Pode também utilizar outra fonte para as letras, outra cor de fundo na imagem..
