Captcha Klasse

B

Bgag

Guten Abend!
Ich habe ein kleines Problem. Ein Freund von mir brauchte eine Captcha Klasse für ein Forum. Ich habs versucht jedoch ohne viel Erfolg. Muss zudem gestehen, dass ich mich vorher nie mit den Imagefunktionen beschäftigt habe. Wäre nett wenn ihr mal über den Code schauen könntet und mir Fehler aufweisen könntet. Für ein Paar Tips zur Verbesserung bin ich natürlich auch offen. Ich suche jetzt schon seit zwei stunden und habe nichts richtiges gefunden. Wäre euch echt dankbar! Die Klasse sieht so aus:
PHP:
<?php
error_reporting(E_ALL);

/* The Captcha class */
class Captcha
{    
	/*Captcha Variables*/
	protected $font_face;
	protected $captcha_string;
	protected $blanko_image;
	protected $captcha_image;
	protected $captcha_width = 150;
	protected $captcha_height = 50;
	protected $captcha_highlights = 50;
    
	/**
	* Creates a string with letters and numbers
	* 
	* @name Captcha::create_string()
	* @access public
	* @return boolean
	*/
	public function create_string()
	{
		$letters = range('a','z');
		$numbers = range(1,26);
		$captcha = '';
		
		for ($i = strlen($captcha); $i < 3; $i++) 
		{
			$rnum = mt_rand(0,25);
			$captcha[] = $numbers[$rnum];
			unset($rnum);
			
			$rlet = mt_rand(0,25);
			$captcha[] = $letters[$rlet];
			unset($rlet);
		}
		
		shuffle($captcha);
		
		for ($i = 0; $i < count($captcha); $i++) 
		{
			$this->captcha_string .= $captcha[$i];
		}
		
		$_SESSION['captcha'] = $this->captcha_string;
		
		return true;
	}
    
	/**
	* Creates a blanko-image for the captcha
	* 
	* @name Captcha::create_blanko_image()
	* @access public
	* @return boolean
	*/
	public function create_blanko_image()
	{
		$font = mt_rand(1,5);
		$this->font_face = $font;
		
		$imgwidth = (strlen($this->captcha_string)*imagefontwidth($font)) + 10;
		$imgheight = imagefontheight($font) + 10;
		
		if ($imgwidth < $this->captcha_width) { $imgwidth = $this->captcha_width; }
		if ($imgheight < $this->captcha_height) { $imgheight = $this->captcha_height; }
		
		$blanko_image = imagecreate($imgwidth, $imgheight); 
		$this->blanko_image = $blanko_image;
		
		return true;
	}
    
	/**
	* Fills the blanko-image for the captcha
	* 
	* @name Captcha::fill_blanko_image()
	* @access public
	* @return boolean
	*/
	public function fill_blanko_image()
	{
		for ($i = 0; $i < $this->captcha_highlights; $i++) 
		{
			$colors[] = imagecolorallocate($this->blanko_image, mt_rand(0,255), mt_rand(0,255), mt_rand(0,255));
		}
		
		for ($i = 0; $i < $this->captcha_highlights; $i++) 
		{
			imagerectangle($this->blanko_image, mt_rand(0,$this->captcha_width),mt_rand(0,$this->captcha_height),mt_rand(0,$this->captcha_width),mt_rand(0,$this->captcha_height), $colors[$i]);
			imageline($this->blanko_image, mt_rand(0,$this->captcha_width),mt_rand(0,$this->captcha_height),mt_rand(0,$this->captcha_width),mt_rand(0,$this->captcha_height), $colors[$i]);
		}
		
		$captcha_image = imagestring($this->blanko_image,$this->font_face,10,10,$this->captcha_string,$colors[mt_rand(0,$this->captcha_highlights)]);
		$this->captcha_image = $captcha_image;
		
		return true;
	}
    
	/**
	* Shows the finished captcha
	* 
	* @name Captcha::show_captcha()
	* @access public
	* @return boolean
	*/
	public function show_captcha()
	{	
		
		header("content-type: image/gif");
		
		$this->create_string();
		$this->create_blanko_image();
		$this->fill_blanko_image();

		imagegif($this->captcha_image);
		imagedestroy($this->captcha_image);
		
		return true;
	}
}

?>
Der Aufruf dieser Klasse sieht so aus:
PHP:
<?php
	include ('Captcha.php');
	$cap = new Captcha();
	$cap->show_captcha();
?>
MfG, Andy
 
Hi,
öhm was tut denn nicht?

Wenn ich was verbessern würde, dann höchstens etwas ideologisches ;)
Also ich würde eine rein statische Klasse schreiben.
Finde den Code "schöner" und kleine Vorteile sind:
- Es werden weniger Resourcen beansprucht, da keine Instanz erzeugt wird.
- Es muß beim "Aufruf" nicht instanziert werden.

Auch bin ich bei Namensgebung pingelig (Das hast Du nun davon, wenn Du nach "Tips" frägst ;) )
Bei mir würde der Aufruf demnach so aussehen:

PHP:
<?php
    include ('Captcha.php'); // *
    Captcha::run(); // **
?>

*) Den Include kann man übrigens seit PHP5 automatisieren (grade bei größeren Projekten sehr zu empfehlen):
http://www.php.net/manual/de/function.spl-autoload.php

**) "einfacher und sparsamer", dadurch, dass noch weitere Methoden der Klasse aufgerufen werden, entsteht ein Ablauf, welchen ich persönlich mit "run" definiere. "show" wäre eine selbstständige Methode dieser Klasse. Ok, jetzt reicht es, sonst werde ich noch zu abstrakt :)

Aber nun zum Problem, einfach mal schildern, dann wissen wir "wo suchen".

Gruß tyg3r
 
Zuletzt bearbeitet:
Guten Morgen!

Ich weiß leider selber nicht, was bzw. welcher Bereich nicht richtig funktioniert. Ich erhalte nur folgende Fehlermeldung:
Code:
Die Grafik "http://www.puk.de/redway/captcha/captchatest.php" kann nicht angezeigt werden, weil sie Fehler enthält.
Dürfte dich auch nicht richtig weiter bringen. Oder?

Was verstehst du unter rein statischer Klasse? Oder verstehst du darunter das alle Methoden statisch sind, nur Konstanten verwendet werden und sich eine Methode auf die Klasse als solches bezieht?
Oder sollen die Farben festgelegt sein. Also nicht per zufallsprinzip gewählt werden? Wäre nett wenn du ein Beispiel bringen könntest.

Den link sehe ich mir mal an und werde dann das Script demnach ändern.

Hätte dann aber noch eine Frage. Und zwar wie kann ich die Buchstaben und Ziffern, die ich in das Captcha eintrage rotieren? Und wie bekomme ich im Hintergrund diesen Rauscheffekt hin, den viele Captchas verwenden?

MfG, Andy
 
Verwende mal als Inhaltstyp „text/plain“ um mögliche Fehlermeldungen lesen zu können.
 
Für das Rauschen ist es am besten, ein paar Hintegründe in Photoshop, Gimp oder dem Grafikprogramm deiner Wahl zu erstellen und dann per [phpf]imagecreatefromjpeg[/phpf] oder ähnlicher Funktion zu laden, da sonst viel Rechenleistung verschwendet wird, wenn du sie von PHP on the fly generieren lässt.
 
Morgen!
Also wenn ich, wie von Gumbo vorgeschlagen den Header ändere erhalte ich folgende Fehlermeldungen:
Code:
Warning: Cannot modify header information - headers already sent by (output started at /home/redway/www/captcha/Captcha.php:2) in /home/redway/www/captcha/Captcha.php on line 129

Warning: imagegif(): supplied argument is not a valid Image resource in /home/redway/www/captcha/Captcha.php on line 135

Warning: imagedestroy(): supplied argument is not a valid Image resource in /home/redway/www/captcha/Captcha.php on line 136
Die Klasse von Felix Jakobi hilft mir nur bedingt weiter, denn dann müsste ich ja noch eine weitere klasse Programmieren, die diese nutzt um dann ein Captcha zu erstellen. Jedoch ist dort die Idee von Font-color garnicht so schlecht.

Nach dem Punkt "Buchstaben rotieren" habe ich nochmal selbst gesucht jedoch nichts gefunden. kann mir da jemand helfen?

Änder gerade nochmal die Klasse. Stell sie dann heute abend nochmal in der neuen Version rein.

MfG, Andy
 
Die [phpf]imagestring[/phpf]-Funktion gibt entweder true oder false zurück. Deswegen musst du in der Captcha::showCaptcha()-Funktion folgendes ändern:
PHP:
        imagegif($this->blanko_image);
        imagedestroy($this->blanko_image);
 
Hi,

PHP:
<?php
error_reporting(E_ALL);

/* The Captcha class */
class Captcha
{    
	/* public vars */
	public static $length = 6;
	
	/* private vars */
	private static $font;
	private static $width = 150;
	private static $height = 50;
	private static $highlights = 50;
    
	/**
	* Run captcha application
	* 
	* @name Captcha::run()
	* @access public
	* @return boolean
	*/
	public static function run(){    

		header("content-type: image/gif");

		$str = self::create_string();
		$img = self::create_blanko_image($str);
		$img = self::fill_blanko_image($img, $str);

		imagegif($img);
		imagedestroy($img);

		return true;
	}
    
	/**
	* Creates a string with letters and numbers
	* 
	* @name Captcha::create_string()
	* @access private
	* @return string
	*/
	private static function create_string(){

		$chars = array_merge(
						range('0', '9'), 
						range('a', 'z')
					);
		mt_srand((double)microtime()*1000000);
		for ($i = 1; $i <= (count($chars)*2); $i++){
			$_key = mt_rand(0,count($chars)-1);
			$_tmp = $chars[$_key];
			$chars[$_key] = $chars[0];
			$chars[0] = $_tmp;
		}
		return substr(implode('',$chars),0,self::$length);
	}
    
	/**
	* Creates a blanko-image for the captcha
	* 
	* @name Captcha::create_blanko_image()
	* @access private
	* @param String $str
	* @return img object
	*/
	private static function create_blanko_image($str){

		self::$font = mt_rand(1,5);

		$imgwidth = (strlen($str)*imagefontwidth(self::$font)) + 10;
		$imgheight = imagefontheight(self::$font) + 10;

		if ($imgwidth < self::$width) 
			$imgwidth = self::$width;
		if ($imgheight < self::$height) 
			$imgheight = self::$height;

		return imagecreate($imgwidth, $imgheight);
	}
    
	/**
	* Fills the blanko-image for the captcha
	* 
	* @name Captcha::fill_blanko_image()
	* @access private static
	* @param img object $img
	* @param String $str
	* @return img object
	*/
	private static function fill_blanko_image($img, $str){

		for ($i = 0; $i < self::$highlights; $i++) {
		    $colors[] = imagecolorallocate($img, mt_rand(0,255), mt_rand(0,255), mt_rand(0,255));
		}

		for ($i = 0; $i < self::$highlights; $i++) {
		    imagerectangle($img, mt_rand(0,self::$width),mt_rand(0,self::$height),mt_rand(0,self::$width),mt_rand(0,self::$height), $colors[$i]);
		    imageline($img, mt_rand(0,self::$width),mt_rand(0,self::$height),mt_rand(0,self::$width),mt_rand(0,self::$height), $colors[$i]);
		}
		
		return imagestring($img,self::$font,10,10,$str,$colors[mt_rand(0,self::$highlights)]);
	}
    
}

?>

Das verstehe ich unter statisch, also Methoden und Variablen statisch.

Der Aufruf wäre dann wie folgt möglich:
PHP:
<?php
    include ('Captcha.php');
    Captcha::$length = 10;
    Captcha::run();
?>

Ist halt stark Geschmackssache =)
Mir gefällt es so besser. In den meisten Fällen benötigt man keine Objekte der Klassen.

Wegen dem Fehler, versuch doch mal das Blanco auszugeben:

PHP:
<?php
    $img = self::create_blanko_image($str);
    imagegif($img);
?>

Gruß tyg3r
 
Hallo!

Danke nochmal für eure tollen Tipps und Anregungen. Ich werde das in meine Klasse einbauen und einiges nochmal ändern. Ich poste dann die fertige Klasse heute Abend nochmal hier im Forum, da ich jetzt erstma weg muss.

MfG, Andy
 
Zurück