Der richtige Umgang mit Captchas
Wir zeigen, wie Sie CAPTCHAs auf Ihrer Webseite verwenden.

CAPTCHA ist das Akronym für Completely Automated Public Turing Test to tell Computers and Humans Apart. Mit Computers sind hauptsächlich Bots gemeint, die den Inhalt von Webseiten auswerten. Bösartige Bots sammeln z.B. E-Mail-Adressen, um sie für Werbezwecke auszunutzen. Für einen solchen Ro...
CAPTCHA ist das Akronym für Completely Automated Public Turing Test to tell Computers and Humans Apart. Mit Computers sind hauptsächlich Bots gemeint, die den Inhalt von Webseiten auswerten. Bösartige Bots sammeln z.B. E-Mail-Adressen, um sie für Werbezwecke auszunutzen.
Für einen solchen Robot ist es einfach, HTML-Text zu lesen. Bei Text in Bildern tut er sich viel schwerer. Deshalb platziert man im Formular eine CAPTCHA-Grafik zusammen mit einem Textfeld und nur dann, wenn der Benutzer die Zeichen des CAPTCHA korrekt in das Textfeld eingegeben hat, erfolgt der Versand an den Server.

Grafikfunktionen der GD Library
Das Skript, welches das CAPTCHA erzeugt, ist verhältnismäßig überschaubar. Alle benötigten Grafikfunktionen werden von der GD Library zur Verfügung gestellt. In der Regel müssen Sie nichts weiter tun, um die GD Library in PHP zu integrieren, sie ist in PHP 4 bereits enthalten und PHP 5 bietet sogar eine verbesserte Version GD2. Die Funktion phpinfo() zeigt Ihnen, ob Ihr Webhoster GD unterstützt.
Am besten lagern Sie die Auslosung der Zufallszeichen in eine Funktion aus. Im Beispiel ist es die Funktion zufallszeichen(). Die in Frage kommenden Zeichen speichern Sie in einem Array. Anschließend bestimmen Sie den Index mit der Funktion rand() und liefern das resultierende Zeichen als Rückgabewert (return $zeichen[$index];).
Das Array $zeichen enthält die Ziffern von 1 bis 9 sowie alle Großbuchstaben, außer dem J. Insgesamt sind es 34 Zeichen, sodass der Index von 0 bis 33 läuft. Wenn Sie wollen, können Sie das Array natürlich um die Kleinbuchstaben ergänzen und beim Aufruf von rand() den zweiten Parameter entsprechend anpassen.
Damit das Skript ausreichend flexibel zu verwenden ist, definieren Sie für die Anzahl der Zeichen, die im CAPTCHA erscheinen sollen, sowie für Höhe und Breite der Grafik jeweils Variablen.
Die Grafik selbst erzeugen Sie mit einer der beiden Funktionen imagecreate() oder imagecreatetruecolor(). Letztere steht nur in der GD-Version 2 zur Verfügung. Sofern Ihr Webhoster GD2 unterstützt, sollten Sie auf jeden Fall imagecreatetruecolor() verwenden. Beide Funktionen erwarten die gewünschte Höhe und Breite des Bildes als Parameter und geben einen Zeiger auf das entstandene Bild zurück. Die Aufrufe lauten also $bild = imagecreatetruecolor($width, $height); bzw. ohne GD2 $bild = imagecreate ($width, $height);.
Mobile Webseiten - Optimierung für Retina-Displays
Im Beispiel hat die CAPTCHA-Grafik eine Höhe von 100 Pixel und eine Breite von 200 Pixel. Den erhaltenen Zeiger ($bild) benötigen Sie im Weiteren für die anstehenden Zeichenoperationen. Zunächst definieren Sie mit der Funktion imagecolorallocate() die Farben, die Sie benötigen: für den Grafikhintergrund eine hellgraue Farbe und Schwarz für die Schriftzeichen. Im Aufruf übergeben Sie als ersten Parameter den Zeiger auf das Bild, die folgenden Parameter stellen die RGB-Werte der gewünschten Farbe dar.
$hellgrau = imagecolorallocate ($bild,
250, 250, 250);
$schwarz = imagecolorallocate ($bild,
0, 0, 0);
Beachten Sie, dass Sie imagecolorallocate() für jede Farbe, die Sie im Bild verwenden, separat aufrufen müssen. Mit der Anweisung imagefill($bild, 0, 0, $hellgrau); füllen Sie nun den Hintergrund der Grafik mit der zuvor definierten hellgrauen Farbe aus. Mit dem zweiten und dritten Parameter legen Sie den Startpunkt der Operation fest, hier also die linke obere Ecke, sodass die Grafik komplett ausgefüllt wird.
Mit den folgenden Anweisungen bestimmen Sie die Koordinaten für die Startposition des ersten auszugebenden Zeichens.
$x = $width / $anzahl_zeichen / 2 -
(imagefontwidth(20) / 2);
$y = $height / 2 + (imagefontheight(20)
/ 2);
Dabei teilen Sie zunächst die Bildbreite durch die Anzahl der auszugebenden Zeichen. Da das Zeichen in dem resultierenden Bereich in der Mitte stehen soll, müssen Sie diesen nochmals halbieren und wenn Sie es ganz genau machen wollen, ziehen Sie davon noch die Hälfte der Breite des Schriftzeichens (imagefontwidth(20) / 2) ab. Diese ermitteln Sie mit der Funktion imagefontwidth(), der Sie die Schriftgröße - im Beispiel 20 - übergeben. Die Funktion gibt den Wert für die Breite in der Einheit Pixel zurück.

Für die Y-Koordinate halbieren Sie die Höhe der Grafik und addieren dazu die Hälfte der Höhe des Schriftzeichens, sodass das Zeichen genau in der Mitte steht. Addieren müssen Sie hier, weil der Wert des entsprechenden Parameters der Funktion imagettftext() den Abstand vom oberen Bildrand nach unten angibt. Die Höhe eines Schriftzeichens ermitteln Sie mit der Funktion imagefontheight(), die sich analog zur Funktion imagefontwidth() verhält.
Das Skript ordnet die auszugebenden Zeichen also erst einmal gleichmäßig nebeneinander an, so wie man es für normalen Text tun würde. Die gewünschten Irritationen erfolgen anschließend allein durch die Ausrichtung der einzelnen Zeichen (dritter Parameter der Funktion imagettftext()). Dies erscheint für den angestrebten Effekt völlig ausreichend, aber natürlich hätte man in geringem Ausmaß zusätzlich auch die Schriftgröße und die einzelnen Werte für die X- und Y-Koordinaten durch Zufallswerte anpassen können.
Ratgeber: Fehlersuche mit Firebug
Mittels einer for-Schleife sorgen Sie nun dafür, dass die Funktion imagettftext(), welche die Zeichen in das Bild schreibt, für jedes Zeichen genau einmal aufgerufen wird. Das muss so sein, weil jedes Zeichen verschieden zu behandeln ist, also imagettftext() bei jedem Aufruf andere Parameter erfordert. Für den Kopf der for-Schleife notieren Sie also
for($i = 0; $i < $anzahl_zeichen; $i++)
Mit der ersten Anweisung innerhalb der for-Schleife bestimmen Sie den Winkel des auszugebenden Zeichens, wobei der Wert, den Sie der Variablen $winkel zuweisen, zwischen -45 und +45 liegen soll.
$winkel = -45 + rand(0,90);
Danach erfolgt der Aufruf der Funktion imagettftext(), die nicht weniger als acht Parameter besitzt, von denen Sie alle angeben müssen. Als Erstes übergeben Sie den Zeiger auf die Grafik ($bild) und einen Wert für die gewünschte Schriftgröße. Die möglichen Werte werden aus einer TTF-Datei ausgelesen. Den Dateinamen, gegebenenfalls samt Pfad, geben Sie im vorletzten Parameter als String an. Möglicherweise möchten Sie an dieser Stelle auf das Font-Verzeichnis Ihres Webservers verweisen und vielleicht auch einen anderen Font verwenden.
Im Beispiel gehen wir davon aus, dass die Font-Datei VeraMono.ttf im Ausführungsverzeichnis liegt, womit die Pfadangabe entfällt. Der dritte Parameter der imagettftext()-Funktion übernimmt den Winkel für die Ausrichtung und zwar als Integerwert im Bereich von 0 (für 0 Grad) bis 360 (für 360 Grad), mit Drehung entgegen dem Uhrzeigersinn.

Der Wert 0 steht für eine normale Ausrichtung von links nach rechts, der Wert 90 richtet den Text von unten nach oben aus und bei dem Wert 180 erscheint die Schrift auf den Kopf gestellt. Um für das CAPTCHA die Irritationen in Grenzen zu halten, empfiehlt es sich, den Bereich der Gradzahlen entsprechend einzuschränken. Nichtdestotrotz können Sie auch hier andere Werte ausprobieren. Mit der Anweisung $winkel = -90 + rand(0,180); erweitern Sie den Wertebereich z.B. auf -90 bis +90 Grad.
Die Koordinaten des Startpunktes (vierter und fünfter Parameter) definieren bei der imagettftext()-Funktion die linke untere Ecke des ersten auszugebenden Zeichens. Mit dem sechsten Parameter geben Sie die gewünschte Schriftfarbe an. Für den letzten Parameter notieren Sie schließlich den auszugebenden Text, hier also genau ein Zeichen, das Sie sich von der selbstdefinierten Funktion zufallszeichen() geben lassen. Und so sieht der Aufruf der imagettftext()-Funktion im Code des Beispielskripts aus:
imagettftext($bild, 20, $winkel, $x,
$y, $schwarz, ,VeraMono.ttf', zufallszeichen());
Vor Beginn des nächsten Schleifendurchlaufs müssen Sie nun noch den Wert für die X-Koordinate anpassen. Das heißt, Sie rücken die Stelle für die Ausgabe des nächsten Zeichens in Abhängigkeit von der Gesamtzahl der auszugebenden Zeichen nach rechts. Dazu addieren Sie zum bestehenden Wert das Ergebnis aus Bildbreite durch Anzahl Zeichen und subtrahieren davon die Hälfte der Fontbreite.
$x += $width / $anzahl_zeichen -
(imagefontwidth(20) / 2);
Nachdem Sie somit alle notwendigen Zeichenoperationen durchgeführt haben, senden Sie das mit imagecreatetruecolor() bzw. mit imagecreate() erzeugte Bild mit der Funktion imagepng() im PNG-Format an den Browser. Die entsprechenden Funktionen lauten imagejpeg() für das JPEG-Format und imagegif() für das GIF-Format. Außerdem müssen Sie dem Browser noch mitteilen, dass es sich bei dem, was gesendet wird, um eine Grafik handelt.
Dazu verwenden Sie die PHP-header()-Funktion in der Form header("Content-type: image/png"); - das Format der Grafik geben Sie jeweils nach image/ an, für JPEGs notieren Sie also header("Content-type: image/jpeg"); und für GIFs header("Content-type: image/gif");. Beachten Sie, dass Sie die header()-Funktion aufrufen müssen, bevor Sie irgendwelche Ausgaben an den Browser senden.
Am besten, Sie platzieren den PHP-Code zum Erstellen von Grafiken ganz oben im Dokument und zwar noch vor einer eventuellen DOCTYPE-Angabe. Tatsächlich erweist sich diese im Kontext von Grafikausgaben als problematisch und auch die Ausgabepufferung mit ob_start() und ob_end_flush() scheint hier nicht zu funktionieren.
Störlinien einfügen
Versehen Sie Ihr CAPTCHA mit Störlinien, wird die Sicherheit zusätzlich erhöht. Die Linienfaben sind frei wählbar, die Ausrichtung kann frei sein. Störlinien fügt man mit imageline() ein. Hier ein Beispielskript:
$dunkelgrau = imagecolorallocate
($bild, 128, 128, 128);
for($i = 1; $i <= rand(10, 25); $i++)
{
$linienfarbe = (rand(1, 2) == 1) ?
$schwarz : $dunkelgrau;
imageline($bild, rand(5, $width
- 5), rand(5, $height - 5), rand(5, $width - 5), rand(5, $height - 5), $linienfarbe);
}
Die Funktion imageline() zeichnet Linien in eine Grafik. Mit dem zweiten und dritten Parameter legen Sie den Startpunkt und mit dem vierten und fünften Parameter den Endpunkt fest. Ob Sie die Koordinaten des Startpunktes als Erstes oder zuletzt angeben, spielt für das Ergebnis keine Rolle. Die Angabe der Koordinaten erfolgt hier wiederum per Aufruf der rand()-Funktion.

Als letzten Parameter übergeben Sie der imageline()-Funktion die Linienfarbe. Diese wird im Beispiel mit der Anweisung $linienfarbe = (rand(1, 2) == 1) ? $schwarz : $dunkelgrau; zufällig ermittelt. Da die schwarze Farbe bereits definiert ist, müssen Sie die Funktion imagecolorallocate() noch für Grau mit den entsprechenden RGB-Werten aufrufen ($dunkelgrau = imagecolorallocate($bild, 128, 128, 128);).
CAPTCHAs auf der Webseite einbinden
Wie verwenden Sie nun das CAPTCHA? Zunächst binden Sie die Grafik auf einem Formular ein. Dies kann per HTML mit dem image-Tag geschehen. Im src-Attribut geben Sie einfach die Skriptdatei an, die das CAPTCHA erzeugt. Außerdem definieren Sie ein Eingabefeld für die CAPTCHA-Zeichen.
<img src="captcha.php"><input name = "captcha" size = "25">
Das dies auf einer anderen Seite geschieht, müssen Sie dem Skript, welches anschließend die Formulardaten verarbeitet, irgendwie den ausgelosten CAPTCHA-String übermitteln. Die Lösung: Sie tun dies im Rahmen einer Session. Hierzu platzieren Sie an den Anfang jeder beteiligten Datei die PHP-Anweisung session_start();.
Im Skript, welches das CAPTCHA erzeugt, speichern Sie den CAPTCHA-Code in einer Session-Variablen. Die for-Schleife müssen Sie gegenüber dem obigen Skript etwas abändern, indem Sie die einzelnen Zeichen nach Aufruf der Funktion zufallszeichen() nach und nach in einer separaten Variablen $captchacode speichern. Nach Austritt aus der for-Schleife weisen Sie den in der Variablen $captchacode gespeicherten String der Session-Variablen $_SESSION["captchacode"] zu.
$captchacode = "";
for($i = 0; $i < $anzahl_zeichen;
$i++)
{
$z = zufallszeichen();
$winkel = -45 + rand(0,90);
imagettftext($bild, 20, $winkel,
$x, $y, $schwarz, ,VeraMono.ttf', $z);
$x += $width / $anzahl_zeichen -
(imagefontwidth(20) / 2);
$captchacode .= $z;
}
$_SESSION["captchacode"] = $captcha
code;
Auf die Session-Variable kann jedes Skript zugreifen, das an der Session beteiligt ist. Zunächst prüfen Sie im verarbeitenden Skript, ob das Formular abgesendet wurde: if(isset($_POST["captcha"])). Ist das der Fall, vergleichen Sie die Eingabe im CAPTCHA-Textfeld mit den ausgelosten Zeichen: if($_POST["captcha"] == $_SESSION[,captchacode']).