• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

softklin

[PHP]Captcha com somas

7 mensagens neste tópico

Boas!

Enquanto estive a tentar aprender algumas coisitas em PHP, na vista de OOP, tentei criar um codigozito que fizesse um captcha com somas, em vez das imagens que mal se percebem... Estive para não colocar isto, porque se calhar não seria muito útil, mas já agora, gostava que me dessem algumas sugestões.

O código funciona, após algumas investidas nas sessões  :P Pode ser adaptado para qualquer projecto vosso, sem qualquer problema.

<?php
class humanReadTest{
	private $HRTn1;
	private $HRTn2;
	public $HRTnumbers = array("zero","um","dois","três","quatro","cinco","seis","sete","oito","nove");

	function __construct(){
		if(session_id()=="") session_start();

		if($_SESSION['HRTsecret']=="" or $_POST['HRTanswer']==""){
			//gerar segredo (novo)
			$this->HRTn1 = rand(0,9);
			$this->HRTn2 = rand(0,9);
			$_SESSION['HRTsecret'] = $this->HRTn1 + $this->HRTn2;
		}else{
			//responde à questão
			if($_POST['HRTanswer']!=$_SESSION['HRTsecret']){
				echo "Resposta errada!";
				$_SESSION['HRTsecret']=="";
			}else{
				echo "Resposta certa ";
				$_SESSION['HRTsecret']=="";
			}
		}
	}

	public function showTheQuestion(){
		switch(rand(1,3)){
		case 1:
			echo "Qual é o resultado da soma de {$this->HRTnumbers[$this->HRTn1]} com {$this->HRTnumbers[$this->HRTn2]}?";
			break;
		case 2:
			echo "Quanto é que é {$this->HRTnumbers[$this->HRTn1]} + {$this->HRTnumbers[$this->HRTn2]}?";
			break;
		case 3:
			echo "A soma de {$this->HRTnumbers[$this->HRTn1]} mais {$this->HRTnumbers[$this->HRTn2]} dá:";
		}
	}
}

$protection = new humanReadTest();

if(!isset($_POST['submit'])){
$protection->showTheQuestion();
?>
<form method="POST">
<input type="text" name="HRTanswer">
<input type="submit" name="submit">	
</form>
<?php
}
?>

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Funcionar funciona, o problema é que é um captcha demasiado frágil pois não precisa de qualquer manipulação de imagem para o quebrar.

Em poucos minutos se faz um script para o quebrar.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Funcionar funciona, o problema é que é um captcha demasiado frágil pois não precisa de qualquer manipulação de imagem para o quebrar.

Em poucos minutos se faz um script para o quebrar.

Pois..  :P Eu inicialmente ptretendia fazer somas, subtracções, etc... para o tornar um pouco mais robusto... mas depois tinha de verificar se a  subtracção não dava um número negativo, ou números com casas decimais, no caso da divisão... O que pretendia mesmo, era ver o funcionamento das classes  :P

Mas obrigado pelo feedback, já agora há alguma maneira de tornar um captcha deste genero seguro, sem usar imagens?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Com operações matemáticas não estou a ver nenhuma forma pois é uma questão de fazer reverse engineering das tuas contas e calcula-las.

Uma forma que é relativamente eficiente é teres uma base de dados de perguntas, por exemplo:

Como se chama o gajo que escreveu Os Maias?

Que país fica ao lado de portugal?

De que cidade é o clube SL Benfica?

Mas isso dá muito trabalho, pois sem uma quantidade razoavel de perguntas actualizadas frequentemente, a captcha acaba por se tornar fragil.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

$_POST['HRTanswer']==""

Isto nunca se usa, porque se eu enviar um espaço, continua vazio, mas não é "". Para esse efeito, usa-se a função empty(): http://pt2.php.net/empty

if($_POST['HRTanswer']!=$_SESSION['HRTsecret']){

echo "Resposta errada!";

$_SESSION['HRTsecret']=="";

}else{

echo "Resposta certa :P";

$_SESSION['HRTsecret']=="";

}

Não é ==, mas =. E, para não tares a repetir código, podes fazer antes assim:

				if($_POST['HRTanswer']!=$_SESSION['HRTsecret']){
				echo "Resposta errada!";
			}else{
				echo "Resposta certa ";
			}
			$_SESSION['HRTsecret']="";

$this->HRTn1 = rand(0,9);

$this->HRTn2 = rand(0,9);

$_SESSION['HRTsecret'] = $this->HRTn1 + $this->HRTn2;

Era preferível usares antes o tamanho da array dos números e não especificares logo que é 9. E porque não fazes logo $_SESSION['HRTsecret'] = rand(0, count($this->HRTnumbers)-1) + rand(0, count($this->HRTnumbers)-1); ?

O código para gerar o captcha, na minha opinião, estando numa função à parte, iria expandir os horizontes da class.

Aqui fica a minha "versão" do teu script.

<?php
class humanReadTest{
	public $HRTnumbers = array("zero","um","dois","três","quatro","cinco","seis","sete","oito","nove");
	public $lastNumber = count($this->HRTnumbers)-1;
	public $questions = array("Qual é o resultado da soma de %s com %s?",
		"Quanto é %s + %s?",
		"A soma de %s mais %s dá:",
		"Quanto dá %s com %s?");
	public $questionsNumber = count($questions)-1;
	public $operation;

	function __construct(){
		if(empty(session_id())) session_start();

		if(empty($_SESSION['HRTsecret']) || empty($_POST['HRTanswer'])){
			$_SESSION['HRTsecret'] = $this->generate();
		}else
			echo ($this->verify()) ? 'Resposta correcta' : 'Resposta errada'; //responde à questão

	}

	public function generate(){
		return rand(0, $this->HRTnumbers) + rand(0, $this->HRTnumbers);
	}

	public function verify(){
		if($_POST['HRTanswer'] == $_SESSION['HRTsecret'])
			$return = true;
		else $return = false;
		unset($_SESSION['HRTsecret']);
		return $return;
	}

	public function showTheQuestion(){
		return $this->questions[rand(0, $this->$questionsNumber)};
	}

}

$protection = new humanReadTest();

$form = '<form method="POST">
<!-- question -->
<input type="text" name="HRTanswer">
<input type="submit" name="submit" value="Verificar">	
</form>';
if(!empty($_POST['submit'])) $form = str_replace("<!-- question -->", $protection->showTheQuestion(), $form);
echo $form;
<?php
}
?>

Não testei btw.

No entanto, tenho que concordar com o pedrotuga: este sistema é muito frágil. O ideal é mesmo um captcha visual. Se não queres usar captchas visuais, podes fazer as tais perguntas que o pedrotuga disse, porque, tirando esse tipo de perguntas, quebra-se isso num instante.

De notar que isto só funciona no PHP5.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

De notar que isto só funciona no PHP5.

Realmente tinha ai umas distracções graves  :-[... mas é bom, assim dá para por mais números, boa correcçãoe, mais perguntas facilmente  ;)

Mais quanto à parte que citei ,estive a ver e parece-me ser por causa do __construct... Mas então como fazer isso no PHP4 e inferiores?

$p = new humanReadTest();
$p.funcaoParaGerar();

ou há outro método?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não é só do __construct. As keywords public e private não se usam no PHP4. Em relação ao __construct, em vez de fazeres function __construct, fazes function humanReadTest :P

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora