Location: PHPKode > scripts > AntiBot an alternative to CAPTCHA > classe.AntiBot.php
<?php
/******************************************************************

Copyright (C) 2010 Andre Campos Rodovalho. All rights reserved.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>

******************************************************************/

/**
 * Esta classe tem o intuito de bloquear a acao de bots e robos de span, empregando taticas inteligentes
 * na deteccao de humanos
 *
 * @autor Andre Campos Rodovalho - hide@address.com
 * @date 02-08-10
 * @update 07-10-10
 * @version 3.5
 * @copyright Copyright (C) 2010 Andre Campos Rodovalho. All rights reserved.
 * @license GNU/LGPL, see COPYING.LESSER
 */
class AntiBot{

	var $coresString = array( 0=>'vermelho', 1=>'amarelo', 2=>'rosa', 3=>'verde', 4=>'marrom',
		5=>'laranja', 6=>'azul', 7=>'cinza' );
	var $coresHexa = array( 0=>'#FF0000', 1=>'#E0E000', 2=>'#FF00FF', 3=>'#339900', 4=>'#934900',
		5=>'#FB9600', 6=>'#0000FF', 7=>'#999999' );
	var $numerosString = array( 0=>'zero', 1=>'um', 2=>'dois', 3=>'tres', 4=>'quatro', 5=>'cinco',
		6=>'seis', 7=>'sete', 8=>'oito', 9=>'nove' );

	/**
	 * Cria uma instancia da classe e quando requisitado iniciar nova charada
	 * @param boolean $iniciarCharada Sinaliza quanto imprimir a charada
	 * @param boolean $charadasRandomicas Sinaliza quando randomizar charadas
	 * @param int $charadaChamar Quando $charadasRandomicas e false, chama metodo correspondente
	 */
	function AntiBot($iniciarCharada=true,$charadasRandomicas=true,$charadaChamar=0){
		@session_start();

		if( $charadasRandomicas )
			$charadaChamar = rand(0,3);

		if( $iniciarCharada ){
			switch( $charadaChamar ){
				case 0: echo $this->montaCharadaConta(); break;
				case 1: echo $this->montaCharadaContaLetra(); break;
				case 2: echo $this->montaCharadaCoresLetras(); break;
				case 3: echo $this->montaCharadaInverteTira(); break;
			}
		}
	}

	/**
	 * Gera uma charada randomica de operacao aritmetica e retorna string de pergunta (HTML para o
	 * formulario)
	 * @param string $guardarReposta Sinaliza quando guardar a reposta gerada
	 * @return string $pergunta
	 */
	function montaCharadaConta($guardarReposta=true){

		$operacoesString = array(0=>'mais',1=>'menos',2=>'vezes');

		$indiceNumero1 = rand(0,9);
		$indiceNumero2 = rand(0,9);
		$indiceOperacao = rand(0,2);

		$resposta = 0;
		switch($indiceOperacao){
		    case 0: $resposta = $indiceNumero1 + $indiceNumero2; break;
		    case 1: $resposta = $indiceNumero1 - $indiceNumero2; break;
		    case 2: $resposta = $indiceNumero1 * $indiceNumero2; break;
		}
		if( $guardarReposta ) $this->guardaResposta($resposta);

		$variavel = 'sujeira'.rand(0,2);
		$$variavel = $this->montaSujeira();

		$pergunta = 'Qual o n&uacute;mero inteiro ('.$sujeira2.'considerando o sinal)
			resultado'.$sujeira0.' da opera&ccedil;&atilde;o "'.
			$this->numerosString[$indiceNumero1].' '.$operacoesString[$indiceOperacao].' '.
			$this->numerosString[$indiceNumero2].'" ?'.$sujeira1;

		if( $guardarReposta ) { // evita chamadas recursivas
			$posicao = 'pos'.rand(0,1);
			$$posicao = '<span><div style="display:none">'.$this->montaCharadaContaLetra(false).
				'</div></span>';
		}

		return $pos1.'<span><div style="display:none">'.time().'</div>'.$pergunta.'</span>'.$pos0;
	}

	/**
	 * Guarda a resposta da charada em uma sessao
	 * @param string $resposta
	 * @return void
	 */
	function guardaResposta($resposta){
		$_SESSION['resposta'] = $resposta;
	}

	/**
	 * Confere se a resposta passada e a resposta correta, que esta guarda em uma sessao
	 * @param string $resposta
	 * @return boolean
	 */
	function verificaResposta($resposta){
		if( ($_SESSION['resposta'] == $resposta) && !empty($_SESSION['resposta']) ) return true;
		else{ $_SESSION['resposta'] = ''; return false; };
	}

	/**
	 * Gera uma charada randomica para contagem de ocorrencias de uma letra em uma palavra
	 * @param boolean $guardarReposta
	 * @return string $pergunta
	 */
	function montaCharadaContaLetra($guardarReposta=true){

		$tamanho_palavra = 9;
		$palavra = $this->geraPalavra($tamanho_palavra);

		$indiceSorteado = rand(1,$tamanho_palavra);

		$caracterSorteado = substr( $palavra, $indiceSorteado, 1 );
		$resposta = substr_count( $palavra, $caracterSorteado );
		if( $guardarReposta ) $this->guardaResposta($resposta);

		$variavel = 'sujeira'.rand(0,2);
		$$variavel = $this->montaSujeira();

		$pergunta = 'Quantas vezes '.$sujeira0.'(em n&uacute;mero) a letra '.$sujeira1.'"'.
			$caracterSorteado.'" aparece na express&atilde;o: '.$sujeira2.'<b>'.$palavra.
			'</b> ?';

		if( $guardarReposta ) {
			$posicao = 'pos'.rand(0,1);
			$$posicao = '<span><div style="display:none;">'.$this->montaCharadaConta(false).
				'</div></span>';
		}

		return $pos1.'<span><div style="display:none;">'.time().'</div>'.$pergunta.'</span>'.$pos0;
	}

	/**
	 * Gera uma palavra (miolo) dado como parametro o tamanho desejado
	 * @param int $tamanho_palavra
	 * @return string $palavra
	 */
    	function geraPalavra($tamanho_palavra=5){
		$vogais = array('a','e','i','o','u');
		$consoantes = array('b','c','d','f','g','h','nh','lh','ch','j','k','l','m','n','p','qu',
			'r','rr','s','ss','t','v','w','x','y','z');

		$palavra = '';
		$contar_silabas = 0;
		while($contar_silabas < $tamanho_palavra){

			$vogal = $vogais[rand(0,count($vogais)-1)];
			$consoante = $consoantes[rand(0,count($consoantes)-1)];
			$silaba = $consoante.$vogal;
			$palavra .=$silaba;
			$contar_silabas++;
			unset($vogal,$consoante,$silaba);
		}

		return $palavra;
	}

 	/**
	 * Gera uma expressao html randomica para "sujar" o a pergunta, e enganar provaveis bots
	 * @return string $sujeira
	 */
	function montaSujeira(){

		$abreTag = array('<p style="display:none">','<span style="display:none">',
			'<tt style="display:none">','<font style="display:none">',
			'<div style="display:none">','<cite style="display:none">');

		$fechaTag = array('</p>','</span>','</tt>','</font>','</div>','</cite>');

		$indiceTags = rand(0,5);

		if( rand(0,1) )
			$sujeira = time();
		else
			$sujeira = $this->geraPalavra( rand(4,11) );

		$sujeira = $abreTag[$indiceTags].$sujeira.$fechaTag[$indiceTags];
		if( rand(0,1) ) $sujeira = str_replace('">', ';">', $sujeira);
		if( rand(0,1) ) $sujeira = str_replace('none', ' none', $sujeira);

		return $sujeira;
	}

	/**
	 * Gera uma charada para digitar caracteres de determinada cor
	 * @param boolean $guardarReposta
	 * @return string $pergunta
	 */
	function montaCharadaCoresLetras($guardarReposta=true){

		$str = array();
		$tamanho = 15;
		$numeroDeColoridas = rand(1,5); //reposta
		$resposta = array();
		$indiceDaCor = rand(0,7); //sorteada
		$outrasCores = array();
		while(1){ //sorteia tres diferentes cores
			if( sizeof($outrasCores) > 2 )
				break;
			else{
				$indice = rand(0,7);
				if( $indice != $indiceDaCor )
					$outrasCores[] = $this->coresHexa[$indice];
			}
		}

		$verbete = $this->geraVerbete($tamanho);
		$verbete = str_split($verbete);

		$y = 0; // contador de quantas letras foram com a cor sorteada
		for( $i = 0; $i<$tamanho; $i++ ) { //loop que constroi um array "miolo" de charada

			$letra = $verbete[$i];

			// verifica se deve colocar cor sorteada
			if( ($y < $numeroDeColoridas) && ($numeroDeColoridas != 0) ){
				$cor = $this->coresHexa[$indiceDaCor];
				$resposta[$letra.$i] = $letra;
				$y++;
			}else{ // sortea cor sujeira
				$indice = rand(0,2);
				$cor = $outrasCores[$indice];
			}

			$str[$letra.$i] = '<font color="'.$cor.'">'.$letra.'</font> ';
		}

		ksort($resposta);
		ksort($str);
		$str = implode($str);
		$resposta = implode($resposta);
		if( $guardarReposta ) $this->guardaResposta($resposta);

		$variavel = 'sujeira'.rand(0,2);
		$$variavel = $this->montaSujeira();

		$pergunta = 'Digite os caracteres de cor '.$this->coresString[$indiceDaCor].
			', considerando mai&uacute;sculas e min&uacute;sculas presentes'.$sujeira0.
			' na express&atilde;o <br />( <strong>'.$str.$sujeira2.'</strong> )'.$sujeira1;

		if( $guardarReposta ) {
			$posicao = 'pos'.rand(0,1);
			$$posicao = '<span><div style="display: none">'.$this->montaCharadaInverteTira(false).
				'</div></span>';
		}

		return $pos1.'<span><div style="display: none">'.time().'</div>'.$pergunta.'</span>'.$pos0;
	}

	/**
	 * Gera um verbete (miolo) dado como parametro o tamanho desejado
	 * @param int $tamanho
	 * @return string $verbete
	 */
	function geraVerbete($tamanho=5){

		$verbete = '';
		srand( (double)microtime()*1000000 );
		$data = "AbcDE123IJKLMN67QRSTUVWXYZ";
		$data .= "aBCdefghijklmn123opq45rs67tuv89wxyz";
		$data .= "FGH45P89";

		for( $i = 0; $i<$tamanho; $i++ ) {
			$verbete .= substr($data, (rand()%(strlen($data))), 1);
		}

		return $verbete;
	}

	/**
	 * Gera uma charada para digitar os caracteres sem determinado numero, invertendo ou nao
	 * @param boolean $guardarReposta
	 * @return string $pergunta
	 */
	function montaCharadaInverteTira($guardarReposta=true){
		$caracteres = $this->geraVerbete(5);
		$caracteres = str_split($caracteres);
		$retirarEste = 0;

		foreach($caracteres as $char){ // acha um numero na str para retirar
			$char = $char *= 1; // converte pra int
			if( $char != 0 ){
				$retirarEste = $char;
				break;
			}
		}
		if( $retirarEste == 0 ){ // se nao tiver numeros, faz um
			$retirarEste = rand(1,9); // nao coloco zero
			$caracteres[] = $retirarEste;
		}

		$caracteres = implode($caracteres);
		$resposta = str_replace($retirarEste,'',$caracteres);
		if( rand(0,1) ) {
			$resposta = strrev( $resposta );
			$inverter = '<strong>inverta</strong> toda a sequ&ecirc;ncia e';
		}
		if( $guardarReposta ) $this->guardaResposta($resposta);

		$variavel = 'sujeira'.rand(0,2);
		$$variavel = $this->montaSujeira();

		$pergunta = 'Dada a cadeia <font color="'.$this->coresHexa[rand(0,7)].'">'.
			$caracteres.'</font> '.$inverter.' retire'.$sujeira1.' o n&uacute;mero
			<strong>'.$this->numerosString[$retirarEste].'</strong>'.$sujeira0.
			' - para a resposta, considere mai&uacute;sculas'.$sujeira2.' diferente de
			min&uacute;sculas';

		if( $guardarReposta ) {
			$posicao = 'pos'.rand(0,1);
			$$posicao = '<span><div style="display: none;">'.$this->montaCharadaCoresLetras(false).
				'</div></span>';
		}

		return $pos1.'<span><div style="display: none;">'.time().'</div>'.$pergunta.'</span>'.$pos0;
	}

}

Return current item: AntiBot an alternative to CAPTCHA