Icon für RSS-Feed Link zum XING-Profil
Wählen Sie eine Hintergrundfarbe:
Schwarzer Hintergrund Blauer Hintergrund Hellblauer Hintergrund Rose Hintergrund Grüner Hintergrund Grüner Hintergrund Olivfarbener Hintergrund Gelber Hintergrund Sandfarbiger Hintergrund Beiger Hintergrund Weisser Hintergrund
Texthintergrund:
Schwarzer Hintergrund Weisser Hintergrund Transparenter Hintergrund


Ladebild
Brick in the Wall

Captcha in PHP programmieren

Von Matu am 18. Mai, 2009 (01:37 Uhr) unter Kategorie: PHP

Captcha ist die Abkürzung für Completely Automated Public Turing test to tell Computers and Humans Apart und dient in Gästebüchern, Foren, Weblog und anderen Eingabe- bzw. Kontaktformularen als Möglichkeit zu entscheiden, ob die Eintragung der Daten durch einen Menschen oder maschinell durch ein Script ( BOT) erfolgt. Dazu wird ein Bild generiert, welches (meist verschleierte) Schriftzeichen enthält, die zur Überprüfung in ein Textfeld eingetragen werden müssen. Diese Aufgabe soll für den Menschen einfach zu bewältigen sein, für die Maschine dagegen eine Hürde darstellen und so vor Spam schützen.

Leider werden diese sogenannten Spam-Bots immer besser programmiert und setzen Mustererkennungs-Algorithmen ein, welche mittlerweile auch stark verschleierte Captchas auslesen können (wobei diese auch für den Mensch unleserlich werden) und somit den Schutz aufheben. Aus diesem Grund lassen sich Entwickler von Captchas immer neue Hürden einfallen, die dann im Gegenzug von der “dunklen” Seite wieder geknackt werden.

Um sich davon mal ein Bild machen zu können ist diese Seite interessant. In der mittleren Spalte wird angegeben, um wie viel Prozent das jeweilige Captcha keinen Schutz mehr bietet. Einen weiteren interessanten Artikel hierzu finden Sie auf der Seite der W3C Working Group (in Englisch).

Letztendlich kann man sagen, das Captchas nicht mehr “up to date” sind und vor allem hinsichtlich barrierefreiher Seiten wohl bald der Vergangenheit angehören. Vereinzelt sieht man auf Webseiten Captchas, welche auch eine Sprachausgabe erzeugen können … ein guter Schritt hinsichtlich der eben angesprochenen Barrierefreiheit wie ich finde.

Soll dennoch ein Captcha eingesetzt werden, dann sollte dieses mit weiteren “Hürden” kombiniert werden. Beispielsweise könnte ein weiteres Feld in das Formular eingebracht werden, welches durch CSS versteckt wird und frei bleiben muss. Da ein Spam-Bot in der Regel alles ausfüllt wäre er als Maschine entarnt und der Programmierer kann darauf eingehen. An vielen Stellen werden auch einfache Rechenaufgaben (Was ergibt 7+5?) oder Fragen gestellt (Das Gras ist …?). Eine weitere Möglichkeit besteht darin, einen Zeitwert beim Aufruf der Webseite zu speichern und diesen mit einem 2. Wert beim Abschicken des Formulars zu vergleichen. Spam-Bots füllen das Formular in wenigen Sekunden aus, ein Mensch benötigt da wesentlich mehr Zeit … hier sollte klar sein, was ich meine. Über die .htaccess-datei können ebenfalls Spam-Bots über die IP gesperrt werden …!

Aber eigentlich ging es bei diesem Artikel um das Programmieren eines Captchas. Ich hoffe, dass jetzt nicht die Lust dazu verflogen ist. Denn es ist eine schöne Übung, wie ich finde und zudem leicht verständlich. Außerdem wird ein guter Einstieg in die grafische Programmierung mit PHP geboten.

Auf gehts!

Wir programmieren ein Captcha

Öffnen Sie bitte Ihren gewohnten Standard-Editor, ich persönlich benutze dafür meist immer Notepad++. Der ist klein, fein und reicht mir. Für größere Projekte greife ich dann zumeist auf die PHP-Version von Eclipse zurück. In eine neue Datei geben wir den Anfang und den Endtag für PHP ein

<?php

?>

und speichern diese dann direkt an einem beliebigen Ort unter captcha.php ab. Danach sollte das Syntax-Highlighting aktiviert sein!

Für das Erzeugen der Zeichen bietet sich eine Funktion an

<?php
//capture.php
function generate(){

Zuerst erzeugen wir ein Array, welches wir mit Zeichen füllen

/*Beispiel-Array für die Zeichen und Zahlen*/
$zeichen = array('a','A','b','A','c','C','d','D','e','E','f','F',
                'g','G','h','H','i','I','j','J','k','l','m','n','o',
                'p','q','r','s','t','u','v','w','x','y','z',
                1,2,3,4,5,6,7,8,9);

Anstatt ein Array händig zu füllen könnte man auch mit ‘range’ die Zeichen/Zahlen erzeugen

/*
$abc=range("A","Z");
$abc2=range("a","z");
$zahlen=range(0,9);
...
*/

jedoch haben Sie mit dem Array was fürs Auge, daher kommentieren wir diesen Bereich aus.
Das Array mischen wir nun mit der PHP-Funktion shuffle

shuffle($zeichen);

Anschließend wählen wir 4 zufällige Einträge (array_rand) aus
dem Array aus. Und Sie haben Recht, ’shuffle’ könnte man sich somit auch sparen!

$rand_keys = array_rand($zeichen, 4);

Nun basteln wir aus den 4 Array-Einträgen einen String (Punkt-Operator) und wandeln die 4 Zeichen zu Großbuchstaben um (strtoupper ⇒ string to upper). Natürlich werden hierbei nur Buchstaben und keine Zahlen konvertiert. Lässt man diesen Schritt aus, dann können später auch Kleinbuchstaben (wie im Array angegeben) vorkommen.

return strtoupper($zeichen[$rand_keys[0]].$zeichen[$rand_keys[1]].
	$zeichen[$rand_keys[2]].$zeichen[$rand_keys[3]]);
}/* Schließende Klammer unserer Funktion nicht vergessen*/

Damit ist die Funktion für die Zeichen schon fertig. Ich habe hier bewusst PHP-Funktionen eingebaut, die eigentlich nicht nötig wären. Dazu gehört die shuffle-Funktion, da die array_rand-Funktion ebenfalls zufällige Zeichen aus dem Array raus zieht. Zudem schreiben wir auch Kleinbuchstaben in das Array und konvertieren diese dann vor der Rückgabe zu Großbuchstaben … ebenfalls unnötig. Aber so sehen Sie gleich mehrere Möglichkeiten, lernen mehr und können selber wählen, was Sie für richtig halten.
Damit ist der erste Schritt getan, kommen wir nun zum Bild.

Als erstes wird das Image erzeugt. Hierzu nutzen wir Funktion imagecreate(), wobei die Werte in der Klammer (Parameter) die Größe des Images in Pixel bestimmen .

$im = imagecreate(180, 100);// Image erzeugen

Darauf folgt die Erzeugung der Hintergrundfarbe mit der Funktion imagecolorallocate(), wobei hier als Parameter zunächst das zuvor erzeugte Image ($im) übergeben wird, welchem dann RGB-Werte zugeordnet werden:

$yellow = imagecolorallocate($im, 255, 255, 0);// Farben erzeugen
/*$black = imagecolorallocate($im, 0, 0, 0);*/

Damit ist das Image an sich schon fertig und könnte z.B mit imagegif() als gif-Datei abgespeichert werden (dazu gleich mehr).
Aber unser String fehlt noch und den erzeugen wir durch unsere zuvor erstellte Funktion, in dem wir diese einfach aufrufen:

$string = generate();// String erzeugen

Das war´s schon, in der Variablen (oder heißt es Variabel) ist nun unser zufällig erzeugter 4-Zeichen-String gespeichert und muss jetzt noch in das Image eingefügt werden. An dieser Stelle wird es ein klein wenig komplizierter. Die einzelnen Zeichen (oder auch Texte) werden einzeln nach und nach über eine for-Schleife in das Image eingefügt. Dafür nutzen wir die Funktion imagefttext(), welche mehrere Parameter beinhaltet:

imagefttext($im, $font_size, $rotation, $shadow_x, $shadow_y, $shadow_color, $font, $string[$i], array());
  • $im steht für unser Image
  • $font_size für die Schriftgröße
  • $rotation für den Drehungswinkel des Zeichens
  • $shadow_x und $shadow_y für die Position innerhalb vom Image
  • $shadow_color für die Farbe des jeweiligen Zeichens
  • $font für die Schriftart (die als .ttf-Datei vorliegen muss)
  • $string[$i] beinhaltet das jeweilige Zeichen
  • array() … keine Ahnung, aber nicht nötig

Schauen wir uns jetzt mal gemeinsam den Quelltext an:

for($i=1; $i <= 4; $i++)
{
	$ro = mt_rand(0, 90);// Zufallszahl Rotation
	$y = mt_rand(35, 100);// Zufallszahl y-Achse
	$font = rand(20, 40);// Schriftgröße
	$color = imagecolorallocate($im, rand(50,200), rand(50, 200), rand(50,200));
	/* Zufallsfarbe --> den RGB-End-Wert tiefer wählen, damit die Zeichen dunkler als der Hintergrund sind*/	

imagefttext ($im, $font, $ro, $i*36, $y, $color, 'arial.ttf', $string[$i-1]);
}

Zunächst beginnen wir mit einer for-Schleife, die genau 4x den Schleifenkörper durchläuft. Bei jedem einzelnen Durchlauf wird durch die imagefttext-Funktion ein Zeichen aus unserem Zeichen-Array in das Image geschrieben ($string[$i-1]). Beim ersten Durchlauf enthält die Zählvariable den Wert 1, der bei jedem weiteren Durchlauf um 1 ($i++) erhöht wird. Da unsere $string-Array aber mit dem Index 0 für das erste Zeichen beginnt, müssen wir den Wert wie oben angegeben ‘jede Runde’ um den Wert 1 reduzieren, um das jeweilige Zeichen zu erhalten. Ich denke, dass sollte klar sein.
Nun erzeugen wir die einzelnen Werte wie Rotation ($ro), Position ($y), Schriftgröße ($font) und Zeichenfarbe ($color) mit Hilfe der Zufalls-Funktion rand(), der wir als Parameter einen Wertebereich übergeben. So kann das jeweilige Zeichen zum Beispiel durch Zufall von 0°-90° gedreht werden (Rotation). Die y-Position verläuft innerhalb von 35-100 Pixel (also innerhalb vom Image, welches 100 Pixel hoch ist). Die Schriftgröße variiert zwischen 20 und 40 Pixel. Dazu kommt ein Zufalls-RGB-Wert für die Farbe des jeweilgen Zeichens. Hierbei wurde der Endwert bewußt auf maximal 200 (von möglichen 255 ⇒ weiss) beschränkt, damit das Zeichen nicht zu hell wird und somit vom Benutzer nur noch schlecht oder gar überhaupt nicht mehr gelesen werden kann (sollte der Hintergrund dunkel sein, verhält sich das entsprechend anders).
Der Wert für die x-Position (horizontal) wird einfach dadurch erzeugt, das wir den jeweiligen Wert der Zählvariable mit 36 multiplizieren. Damit bleibt das jeweilige Zeichen auf jeden Fall innerhalb von unserem Image (wir erinnern uns ⇒ 180 Pixel breit), wandert aber automatisch bei jedem neuen Schleifendurchlauf in Folge der höheren Zählvariable weiter auf der y-Achse nach rechts. Somit liegen die Zeichen nebeneinander und verdecken sich nicht eventuell untereinander.
Nun muss noch eine Schriftdatei eingebunden werden, die entweder im gleichen Ordner liegt (wie im Beispiel zu sehen) oder aber per Pfadangabe eingebunden wird. Diese finden Sie zum Beispiel bei den Betriebssystemen der Redmonder unter

C:\WINDOWS\FONTS\ bzw. C:\WINNT\Fonts\

Zum Abschluss wird das Image als gif-Datei gespeichert (hier sind auch andere Bildtypen möglich) und per echo-Befehl ausgegeben:

imagegif($im, "captcha.gif");
echo "<img src='captcha.gif' border='2'>";
}
?>

Das schöne daran ist, das bei jedem Neuaufruf unseres Captcha-Scriptes die vorherige Bild-Datei durch das neue Image überschrieben wird.

(Hier noch mal der gesamte Quellcode)
<?php
//capture.php

function generate()
{
	$zeichen = array('a','A','b','A','c','C','d',
      'D','e','E','f','F','g','G','h','H','i','I','j','J,
      'k','l','m','n','o','p','q','r','s','t',
      'u','v','w','x','y','z',1,2,3,4,5,6,7,8,9);
	/*
	$abc=range("A","Z");
	$abc2=range("a","z");
	$zahlen=range(0,9);
	*/

	shuffle($zeichen);
	$rand_keys = array_rand($zeichen, 4);

	return strtoupper($zeichen[$rand_keys[0]].$zeichen[$rand_keys[1]].
	$zeichen[$rand_keys[2]].$zeichen[$rand_keys[3]]);
}

//------------------------------------------------------------------------------------------

$im = imagecreate(180, 100);// Image erzeugen
$yellow = imagecolorallocate($im, 255, 255, 0);// Farben erzeugen
$black = imagecolorallocate($im, 0, 0, 0);

$string = generate();// String erzeugen

for($i=1; $i <= 4; $i++)
{
	$ro = mt_rand(0, 90);// Zufallszahl Rotation
	$y = mt_rand(35, 100);// Zufallszahl y-Achse
	$font = rand(20, 40);// Schriftgröße
	$color = imagecolorallocate($im, rand(50,200), rand(50, 200), rand(50,200));
	/* Zufallsfarbe --> den RGB-End-Wert tiefer wählen, damit die Zeichen dunkler als
                      der Hintergrund sind*/

	/* imagefttext($im, $font_size, $rotation, $shadow_x, $shadow_y, $shadow_color,
           $font, string[$i], array());*/
	imagefttext ($im, $font, $ro, $i*36, $y, $color, 'arial.ttf', $string[$i-1]);
}

imagegif($im, "captcha.gif");
echo '<img src="captcha.gif" border="2">';
?>

Das hier erstellte Captcha dürfte für viele Spam-Bots kein Hindernis darstellen. Aber da die Grundvoraussetzung für ein eigenes Captcha gelegt ist (hoffe ich zumindest) steht einer Variation von Ihnen nichts mehr im Wege.

Um das Captcha auszuwerten lediglich die Varible $string gegenprüfen.

Ich wünsche viel Spaß beim Ausprobieren!

Ein Beispiel findet sich hier.
Das dortige Formular ist übrigens ebenfalls selbst programmiert.

1 Star2 Stars3 Stars4 Stars5 Stars (6 votes, average: 5,00 out of 5)
Loading ... Loading ...

Deine Meinung ist mir wichtig!

Es besteht die Möglichkeit, Kommentare nachträglich innerhalb einer Zeitspanne von 5 Minuten zu ändern (Keine werblichen Kommentare)
Jeder 1. Kommentar muss freigeschaltet werden!

Smileys:spy:

Nach oben