Teil von  SELFPHP
  +++ SELFPHP CronJob-Service :: Jetzt auch als Professional-Version verfügbar! +++



:: Anbieterverzeichnis ::

Globale Branchen

Informieren Sie sich über ausgewählte Unternehmen im Anbieterverzeichnis von SELFPHP  

 

:: SELFPHP Forum ::

Fragen rund um die Themen PHP? In über 120.000 Beiträgen finden Sie sicher die passende Antwort!  

 

:: Newsletter ::

Abonnieren Sie hier den kostenlosen SELFPHP Newsletter!

Vorname: 
Name:
E-Mail:
 
 

:: Qozido ::

Die Bilderverwaltung mit Logbuch für Taucher und Schnorchler.   

 
 
Captcha – Der Unterschied zwischen Mensch und Maschine


Systemvoraussetzung
  • Linux
  • Windows
  • PHP 4 >= 4.0.0RC2
  • PHP 5
  • GDBibliothek (> gd1.6)
  • FreeTypeBibliothek

Datei(en)

captcha.php, captcha_check.php, captcha_demo.php

Problem

Sie haben ein Webformular und wollen sicher sein, dass dieses Formular wirklich von einem Menschen ausgefüllt wurde und nicht etwa durch ein Skript auf einem anderen Server. Dieses Szenario kommt häufiger vor, als Sie denken. Gerade im Bereich Gewinnspiele wird diese Variante immer wieder gerne ausgenutzt.

Ein Mitglied bezahlt z. B. 15 Euro im Monat und wird dafür automatisch, also mithilfe eines Skripts, in mehreren 1000 Gewinnspielen eingetragen. Dieses Mitglied war nie auf einer der betreffenden Seiten und ist nicht an den Produkten auf dieser Seite interessiert – es will nur einen Gewinn „abstauben“. Verlierer sind dann die ehrlichen Mitspieler, die das Formular wirklich selbst ausgefüllt haben. Sie können den Eintragungsdiensten aber mit ein wenig Aufwand entgegenwirken.

Im Kapitel CURL werden Sie später ein Programm sehen, das genau diese Aufgabe erledigt, also sich auf einer fremden Seite einträgt, ohne dass Sie dafür etwas machen müssen. Wir zeigen Ihnen dieses Programm nur, damit Sie Ihre Formulare besser schützen können.

Lösung

Das Zauberwort für das Problem der Eintragungsdienste heißt Captcha (Completely Automated Public TuringTest to Tell Computers and Humans Apart). Dabei geht es darum, eine Aufgabe zu stellen, die es zu lösen gilt. Die Aufgabe sollte so schwer sein, dass Sie ein Computer (z. B. ein Bot) nur schwer, ein Mensch dagegen leicht lösen kann.

Nachfolgend stellen wir einen solchen Captcha vor. Im Buch sehen Sie bei den Beispielen nur die Graustufen – tatsächlich aber erzeugt der hier vorgestellte Programmcode Bilder mit Farbverläufen und jeweils unterschiedlichen Farben für jeden Buchstaben.

Der Mensch wird aufgefordert, die nachfolgenden Buchstaben und Zahlen in ein Textfeld einzugeben. Nach dem Senden des Formulars wird dann geprüft, ob das Captcha einwandfrei gelöst wurde.



Diese Aufgabe ist relativ leicht, denn der Mensch muss nur die Buchstaben in der richtigen Reihenfolge in das Textfeld schreiben. In der Regel unterscheidet man dabei nicht zwischen Groß- und Kleinschreibung, da dieser Unterschied nicht immer sofort ersichtlich ist. Sie sehen an dem „S“ im Bild, das man nicht mit hundertprozentiger Sicherheit sagen kann, ob es sich um einen Groß- oder Kleinbuchstaben handelt.

Weiterhin sollte man nicht alle Buchstaben und Zahlen für einen Captcha heranziehen – auch dort besteht Verwechslungsgefahr. Folgende Buchstaben und Zahlen sollten ausgeschlossen werden.

  • L und l das kleine und große L
  • I und i das kleine und große I
  • O und o das kleine und große O
  • 1 Die Zahl eins
  • 0 Die Zahl null

Eine weitere Möglichkeit ist auch die nachfolgende Variante. Dabei muss der Mensch die folgende leichte Rechenaufgabe lösen.



Die Aufgabe sollte für einen Menschen leicht sein. Die Lösung kann also in diesem Fall nur 27 sein. Sie könnten die Aufgabe auch noch erschweren und Ihren Captcha mit mehreren Möglichkeiten ausstatten.

  • Addition
  • Subtraktion
  • Multiplikation
  • Division

Wenn Sie diese Möglichkeiten mischen, erschweren Sie die Aufgabe. Bitte denken Sie aber daran, dass die Aufgabe nicht zu schwer wird. Es ist nicht sinnvoll, wenn Ihre Besucher frustriert das Formular nicht ausfüllen, weil sie die Aufgaben nicht lösen können.

Eines sollten Sie berücksichtigen! Menschen mit einer Sehstörung werden Sie bei dieser Variante ausschließen, sie benötigen einen Captcha, der z. B. einen Text aufsagt. Dieser gesprochene Text muss dann in ein Formularfeld eingegeben werden.

Wir wollen uns nun dem Programmcode widmen und schauen uns erst einmal die Funktionen an, die für den Aufbau des CaptchaBildes verantwortlich ist.

function MakeAlphabet()
   @return   array   $alphabet

Die Funktion MakeAlphabet() soll uns ein Array erzeugen, in dem Klein, Großbuchstaben und Zahlen enthalten sind. Allerdings wollen wir wegen der Verwechslungsgefahr nicht alle Buchstaben und Zahlen haben. Daher greifen wir auf die asciiTabelle zu und lassen zuerst alle Großbuchstaben in das Array schreiben (45). Die Großbuchstaben in der asciiTabelle befinden sich an der Position 6590. Da wir das I, das L und das O ausschließen wollen, berücksichtigen wir das mit einer Abfrage (44).

Im nächsten Schritt erstellen wir die Kleinbuchstaben. In der asciiTabelle finden wir diese Buchstaben an der Stelle 97122. Auch hier schließen wir das i, das l und das o mit einer IFAbfrage aus (50) und speichern die restlichen Buchstaben in unser Array (51).

Zum Schluss müssen wir nur noch die Zahlen speichern. In der asciiTabelle finden wir die Zahlen an der Position 4857. Wegen der Verwechslungsgefahr schließen wir hier die 1 und die 0 aus (56) und speichern die restlichen Zahlen in unser Array (57).

Momentan befinden sich alle Buchstaben und Zahlen noch geordnet in dem Array. Später werden wir das Array durchmischen, sodass wir willkürliche Ausgaben erzeugen können.

Sie hätten die geraden erzeugten Buchstaben und Zahlen auch mit range() erzeugen können, ich finde die beschriebene Variante allerdings besser, da Sie hier gezielter Einfluss auf die Ausgabe haben. Dennoch möchte ich Ihnen die AlternativVariante mit range nicht vorenthalten.

  • $grossbuchstaben = range('A','Z');
  • $kleinbuchstaben = range('a','z');
  • $zahlen = range(0,9);

Als Rückgabewert liefert die Funktion MakeAlphabet() ein Array mit allen Buchstaben und Zahlen.

041:
042:
043:
044:
045:
046:
047:
048:
049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
function MakeAlphabet(){
    
// Grossbuchstaben erzeugen
    
for ($x 65$x <= 90$x++) {
      if(
$x != 73 && $x != 76 && $x != 79)
          
$alphabet[] = chr($x);
    }

    
// Kleinbuchstaben erzeugen
    
for ($x 97$x <= 122$x++) {
       if(
$x != 105 && $x != 108 && $x != 111)
           
$alphabet[] = chr($x);
    }

    
// Zahlen erzeugen
    
for ($x 48$x <= 57$x++) {
    if(
$x != 48 && $x != 49)
        
$alphabet[] = chr($x);
    }
    
    return 
$alphabet;
}
Beispiel 3.6: captcha.php


function makeBorder($imgWidth,$imgHeight,$im,$color)
    @param   integer      $imgWidth
    @param   integer      $imgHeight
    @param   resource   $im
    @param   array        $color
    @return   void

Die Funktion makeBorder() setzt lediglich einen Außenrahmen um unser CaptchaBild. Als Parameter erwartet die Funktion die Bildbreite ($imgWidth), die Bildhöhe ($imgHeight), den Zeiger auf das Bild ($im) sowie die Farbe im RGBModus ($color).

Wir definieren als Erstes die Farbe und fangen danach an zu zeichnen. Dabei geben wir die Werte immer als X/YKoordinaten an. Der waagrechte Strich oben beginnt bei den Koordinaten 0/0 und endet bei Bildbreite/0 (74). Der untere Strich beginnt bei den Koordinaten 0/Bildhöhe1 (wichtig ist hier, die 1 abzuziehen, da man sonst die Linie nicht sehen würde) und Bildbreite/Bildhöhe1 (75).

Der linke senkrechte Strich beginnt bei den Koordinaten 0/0 und endet bei 0/Bildhöhe (76). Der rechte senkrechte Strich beginnt bei den Koordinaten Bildbreite1/ 0 und endet bei Bildbreite1/ Bildhöhe (77).

Damit haben wir erfolgreich einen Rahmen um die Grafik gezogen. Damit der Rahmen nachher wirklich vollkommen ist und nicht von Buchstaben oder Zahlen überlagert wird, rufen wir diese Funktion erst zum Schluss auf.

073:
074:
075:
076:
077:
078
function makeBorder($imgWidth,$imgHeight,$im,$color){
    
imageline($im,0,0,$imgWidth,0,$color); 
    
imageline($im,0,$imgHeight-1,$imgWidth,$imgHeight-1,$color);
    
imageline($im,0,0,0,$imgHeight,$color);  
    
imageline($im,$imgWidth-1,0,$imgWidth-1,$imgHeight,$color);
}
Beispiel 3.7: captcha.php


function makeGradient($fromRGB,$toRGB,$imgHeight)
    @param   array     $fromRGB
    @param   array     $toRGB
    @param   integer   $imgHeight
    @return   array     $color

Die Funktion makeGradient() sorgt für den Farbverlauf im CaptchaBild. Diese Funktion muss als Erstes aufgerufen werden, da die Buchstaben, Zahlen und der Außenrahmen auf ihr platziert werden sollen. Sie müssen sich die Grafikerstellung wie Ebenen vorstellen, also von hinten nach vorne denken.

Die Funktion erwartet als Parameter den RGBWert für den Start des Farbverlaufs ($fromRGB), den RGBWert für das Ende des Farbverlaufs ($toRGB) und als letzten Parameter die Bildhöhe ($imgHeight). Der Farbverlauf beginnt im oberen Teil des Bildes und verläuft dann nach unten.

Für den Farbverlauf müssen wir im Vorfeld einige Berechnungen durchführen. Damit Sie diese Berechnungen an einem Beispiel nachvollziehen können, sehen Sie nachfolgend, mit welchen Parametern die Funktion aufgerufen wurde.

132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
160:
161:
$imgHeight 80;//80

// Farbverlauf RGB-Wert Start und RGB-Wert Ende
$fromRGB = array(
    253
,
    214
,
    0

);
$toRGB = array(
    215
,
    81
,
    6

);

// Erstellt den Farbverlauf
$colorRGB makeGradient($fromRGB,$toRGB,$imgHeight);
Beispiel 3.8: captcha.php
Beispiel 3.9: captcha.php


Zuerst berechnen wir die Differenz der einzelnen RGBWerte von $fromRGB und $toRGB. Diese Differenz benötigen wir später für die Schrittbereiche der einzelnen Farblinien.

$diffR = 253 – 215 = 38
$diffG = 214 – 81 = 133
$diffB = 0 – 6 = 6

Diese Differenzbeträge dividieren wir im nächsten Schritt durch die Höhe des Bildes und erhalten dann die tatsächlichen Schrittbereiche.

$maxR = 38 / 80 = 0.475
$maxG = 133 / 80 = 1.6625
$maxB = 6 / 80 = 0.075

Somit ergeben sich z. B. für die Farbe Rot folgende Schrittwerte. Diese Schrittwerte werden nachher in der FORSchleife (103110) berechnet. Wir zeigen Ihnen hier nicht alle 80 Schritte, sondern nur einen Auszug:

253 , 252.525 , 252.05 , 251.575 . . . 215

Diese Schritte bestimmen wir für alle drei Farbwerte, also Rot, Grün und Blau. Wir speichern (99-101) diese Werte in einer Variablen zwischen, um die einzelnen Schrittwerte nachher innerhalb der FOR-Schleife addieren zu können.

Im letzten Schritt erstellen wir ein Array mit den einzelnen RGBWerten für den Verlauf. Da unsere Höhe hier 80 Pixel ist, müssen wir auch unsere Schleife (103) 80mal durchlaufen. Für jede Zeile (das Bild besteht aus 80 Zeilen) müssen wir jetzt den Wert, also R (104), G (105) und B (106) berechnen. Die einzelnen RGBWerte dürfen nur positiv sein, daher formatieren wir die Werte mit abs() in positive Werte um.

Wichtig ist, dass wir bei jedem Durchlauf den Schrittwert erhöhen. Für die Farbe Rot haben wir einen Schrittwert von 0.475. Somit ergibt sich beim zweiten Durchlauf ein Wert von 0.95, beim dritten Durchlauf ein Wert von 1.425 usw.

Diesen Wert ziehen wir dann jeweils von unserem Grundwert (im Beispiel Rot: 253) ab. Diese Berechnungen müssen wir für alle drei Farben machen und erhalten dann ein Array mit allen RGBWerten für die jeweiligen Zeilen.

089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
099:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
function makeGradient($fromRGB,$toRGB,$imgHeight){
    
    
$diffR = ($fromRGB[0]-$toRGB[0]); //38
    
$diffG = ($fromRGB[1]-$toRGB[1]); //133
    
$diffB = ($fromRGB[2]-$toRGB[2]); // -6

    
$maxR $diffR $imgHeight// 0.475
    
$maxG $diffG $imgHeight// 1,66
    
$maxB $diffB $imgHeight// 0.075

    
$maxNR $maxR;
    
$maxNG $maxG;
    
$maxNB $maxB;

    for(
$x=0;$x<$imgHeight;$x++){
        
$color['r'][$x] = abs($fromRGB[0] - $maxR);
        
$color['g'][$x] = abs($fromRGB[1] - $maxG);
        
$color['b'][$x] = abs($fromRGB[2] - $maxB);
        
$maxR += $maxNR;
        
$maxG += $maxNG;
        
$maxB += $maxNB;
    }
    
    return 
$color;
    
}
Beispiel 3.10: captcha.php


Wir haben nun alle notwendigen Funktionen erklärt. Jetzt müssen wir den Programmcode für die einzelnen Funktionen erläutern. Wie bei fast jedem Programm kommt auch dieses nicht ohne ein paar Konfigurationselemente aus.

Die Konfigurationsparameter bestehen aus dem Pfad (119) zu der TrueTypeSchrift (geben Sie hier den absoluten Pfad an, da die Schrift sonst eventuell nicht eingebunden werden kann), der Schriftgröße (128), der Bildbreite (131) und der Bildhöhe (132).

Weiterhin müssen Sie in einem Array (135) den RGBWert für den Farbverlauf angeben. Dabei handelt es sich um den Startwert. Den RGBWert für den Endwert müssen Sie ebenfalls in einem Array (140) definieren. Als letzten Parameter müssen Sie noch eine Borderfarbe (147) für Ihr CaptchaBild angeben, diese selbstverständlich auch als RGBWert.

Sehr wichtig ist die Variable $captchaDir (125)! Sie sollten hier ein Verzeichnis angeben, in dem die CaptchaDateien gespeichert werden. Vergewissern Sie sich, dass dieses Verzeichnis Schreibrechte besitzt und Sie in dieses Verzeichnis auch schreiben dürfen. Anhand der darin liegenden CaptchaDateien wird auch nachher geprüft, ob das Captcha gelöst wurde. Bei jedem Aufruf dieses Programms wird eine CaptchaDatei nach folgendem Muster gebildet.

116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
// TTF-Schrift
// Sie sollten hier unbedingt den absoluten Pfad angeben, da ansonsten
// eventuell die TTF-Datei nicht eingebunden werden kann!
$fileTTF =  '/homepages/29/d151852282/htdocs/kochbuch/bddavinc.ttf';

// Verzeichnis für die Captcha-Bilder (muss Schreibrechte besitzen!)
// Ausserdem sollten in diesem Ordner nur die Bilder gespeichert werden
// da das Programm in regelmaessigen Abstaenden dieses leert!
// Kein abschliessenden Slash benutzen!
$captchaDir 'captchadir';

// Schriftgröße
$size 30;

//Bildgroesse
$imgWidth 220;//200
$imgHeight 80;//80

// Farbverlauf RGB-Wert Start und RGB-Wert Ende
$fromRGB = array(
    253
,
    214
,
    0

);
$toRGB = array(
    215
,
    81
,
    6

);

// Randfarbe
$colorBorder = array(
    154
,
    53
,
    2

);
Beispiel 3.11: captcha.php


Sämtliche Parameter haben wir gesetzt. Nun können wir den Programmcode näher unter die Lupe nehmen. Zuerst definieren wir einen Header (1), der für die Auslieferung unseres PNGBild zuständig ist. Die Datei für den Aufbau des CaptchaBilds wird nicht direkt inkludiert, sondern über ein ImageTag angesprochen.

01: <img src="captcha.php?codeCaptcha=<?php echo $codeCaptcha?>">


Wir müssen im nächsten Schritt eine Arbeitsfläche (ein neues Bild) erzeugen (232), auf der wir nachher die einzelnen Ebenen platzieren. Sollte die Initialisierung fehlschlagen, wird eine Fehlermeldung zurückgegeben. Im Erfolgsfall erhalten wir einen Zeiger auf das neue Bild.

Diesen Zeiger müssen wir jetzt bei allen Bildmanipulationen mit angeben, da ansonsten die Aktion nicht ausgeführt wird. Mit den Werten aus unserem Array für die Borderfarbe erzeugen wir (235) eine Farb-ID, die wir später an unsere Funktion makeBorder($imgWidth,$imgHeight,$im,$colorB) übergeben müssen. Anhand dieser Farb-ID wird der Rahmen um das Bild gezogen.

Wie erwähnt, sollten Sie sich jede Aktion als Ebene vorstellen. Wir müssen also zunächst den Farbverlauf erzeugen, da über diesen die Buchstaben und Zahlen sowie der Rahmen gelegt werden sollen. Wir rufen daher unsere Funktion makeGradient() (238) auf und erhalten als Rückgabewert ein Array mit allen Farbwerten für jede Zeile (hier im Beispiel hat das Bild 80 Zeilen).

Wir durchlaufen (240) jetzt 80-mal die FOR-Schleife und zeichnen dabei immer eine Linie. Die einzelnen Farbwerte liegen sortiert in unserem Array (241243), sodass wir die jeweiligen RGB-Werte in eine Variable überführen können.

Anhand dieser Werte erzeugen wir wieder eine FarbID (244) für die zu zeichnende Linie (245). Sie erinnern sich sicherlich noch an die X/Y-Koordinaten. Die XKoordinate wird durch die FOR-Schleife immer um eins erhöht, somit füllen sich nach und nach die Linien. Die Breite ist fest und muss daher nicht weiter berücksichtigt werden.

Wenn Sie vorhaben, den Farbverlauf nicht von oben nach unten, sondern von links nach rechts zu zeichnen, ist auch das auch kein Problem. In diesem Fall müssen Sie lediglich die X/Y-Koordinaten anders bestimmen und die FOR-Schleife durch die Breitenangabe laufen lassen.

230:
231:
232:

233:
234:
235:

236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
header("Content-type: image/png");

$im = @imagecreate($imgWidth$imgHeight)
  or die(
"GD! Initialisierung fehlgeschlagen");

// Definiert die Farbe für den Border
$colorB imagecolorallocate($im,$colorBorder[0],$colorBorder[1],
$colorBorder
[2]);

// Erstellt den Farbverlauf
$colorRGB makeGradient($fromRGB,$toRGB,$imgHeight);

for(
$x=0;$x<$imgHeight;$x++){
    
$r $colorRGB['r'][$x];
    
$g $colorRGB['g'][$x];
    
$b $colorRGB['b'][$x];
    
$color imagecolorallocate($im,$r,$g,$b);
    
imageline($im,0,$x,$imgWidth,$x,$color);
}
Beispiel 3.12: captcha_math.php


Wir haben nun den Farbverlauf erstellt und müssen im nächsten Schritt die einzelnen Buchstaben und Zahlen auf das Bild platzieren. Wir lassen uns zuerst durch die Funktion MakeAlphabet() ein Array (172) aus Buchstaben und Zahlen erzeugen.

Damit der Inhalt des Arrays nicht so ordentlich sortiert bleibt und wir willkürliche Ausgaben erhalten, würfeln wir mit shuffle() (175) durch unser Array.

Die Buchstaben sollen nicht alle die gleiche Farbe haben, sondern verschiedenfarbig sein. Der Farbrahmen für RGBWerte liegt zwischen 0255, und wir erstellen mit range() (177) aus diesem Bereich ein Array (177), das wir im Anschluss daran noch durchwürfeln (178).

Da wir sechs Buchstaben haben, benötigen wir auch sechs verschiedene Farb-IDs (180-187). Vermutlich fragen Sie sich jetzt, weshalb hier keine FORSchleife herangezogen wurde. Der Grund: Beim Testen mit einer FORSchleife kam es vor, dass die letzten FarbIDs nicht gesetzt wurden und daher die letzten 34 Buchstaben alle die gleiche Farbe hatten.

171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
//Wortliste erstellen
$alphabet MakeAlphabet();

// Array des Alphabets durchwürfeln
shuffle($alphabet); 

$mix range(0,255);
shuffle($mix);

$colors=array(
    
imagecolorallocate($im,$mix[0],$mix[6],$mix[12]),
    
imagecolorallocate($im,$mix[1],$mix[7],$mix[13]),
    
imagecolorallocate($im,$mix[2],$mix[8],$mix[14]),
    
imagecolorallocate($im,$mix[3],$mix[9],$mix[15]),
    
imagecolorallocate($im,$mix[4],$mix[10],$mix[16]),
    
imagecolorallocate($im,$mix[5],$mix[11],$mix[17])
);
Beispiel 3.13: captcha.php


Da nun alle Farben für die Buchstaben und Zahlen gesetzt sind, können wir die einzelnen Zeichen auf das Bild platzieren. Wir setzen für jeden Durchlauf (188) den Neigungswinkel (190) von einem Buchstaben oder einer Zahl, damit diese entweder nach links oder rechts geneigt sind.

Weiterhin wollen wir erreichen, dass die Buchstaben und Zahlen nicht in einer Reihe, sondern nach oben und unten versetzt dargestellt werden. Wir ermitteln also auch hier für jedes Element eine Zufallszahl zwischen der Schriftgröße und der Bildhöhe20.

Wir haben nun alle Informationen gesammelt und können den Buchstaben oder die Zahl zeichnen (192). Mit dem Zeiger ($im), dem Neigungswinkel ($angel), der XPosition (also wie viele Pixel von links $ next) und der YPosition (also wie viele Pixel von oben $ y) haben wir eine wesentliche Grundlage für die Positionierung.

Wir müssen noch die Farbe bestimmen ($colors), den Pfad zur TrueTypeDatei ($fileTTF) angeben und zum Schluss den jeweiligen Buchstaben oder die Zahl ($alphabet) auswählen. Alle Informationen sorgen dafür, dass das Bild mit den Informationen beschrieben wird. Beim nächsten Durchlauf müssen wir allerdings darauf achten, dass das neu zu schreibende Zeichen in seiner XPosition nach rechts verschoben wird (193).

Dies erledigen wir mit einer kleinen mathematischen Aufgabe und erhalten danach den neuen Punkt für das Zeichen. Zum Schluss einer jeden FORSchleife müssen wir den jeweiligen Buchstaben oder die Zahl an eine Variable anhängen (194) – aus dieser erstellen wir später die CaptchaDatei für die Überprüfung.

Sie können Ihr Captcha an dieser Stelle noch ein wenig komplizierter machen. Statt einer TrueTypeDatei könnten Sie hier wahllos mehrere zufällig auswählen. Somit erreichen Sie nochmals einen höheren Schutz. Speichern Sie dafür einfach sechs verschiedene Pfadangaben in ein Array und lassen dieses vor der FORSchleife durchwürfeln. Innerhalb der FORSchleife greifen Sie dann mit $x auf das jeweilige Element zu.

187:
188:
189:
190:
191:
192:

193:
194:
195:
196:
// Zeichnet die Buchstaben und baut den Dateinamen auf
for($x=0;$x<6;$x++){ 

    
$angel rand(-25,25);
    
$y rand($size,$imgHeight-20);
    
imagettftext($im$size$angel$next$y$colors[$x], 
         $fileTTF
,$alphabet[$x]);
    
$next += $size + ($imgWidth/$size);
    
$fileName .= $alphabet[$x];

}
Beispiel 3.14: captcha.php


Wir sind jetzt fast am Ende und müssen nur noch ein paar Kleinigkeiten für das CaptchaBild erledigen. Wir rufen die Funktion makeBorder() (199) auf und lassen uns einen Rahmen um das Bild ziehen. Im nächsten Schritt überprüfen wir, ob die übermittelte HashSumme korrekt ist, also aus Buchstaben von a bis f und Zahlen von 0 bis 9 besteht.

Weiterhin muss die HashSumme 32 Zeichen lang sein. Sollte die Überprüfung (202) fehlschlagen, erstellen wir eine neue HashSumme (203). Das Captcha kann mit dieser HashSumme zwar nicht mehr gelöst werden, der Form halber erstellen wir diese aber.

Unser CaptchaBild ist jetzt fertig und muss nur noch in ein Verzeichnis gespeichert werden (206), da wir dieses Bild später für die Überprüfung benötigen. Den Dateinamen bilden wir aus der HashSumme und den sechs Buchstaben bzw. Zahlen. Als Dateiendung erhält das Bild die Endung .png. Wir können nun den Speicher für das Bild freigeben (208) und mit readfile() (211) das Bild letztendlich ausgeben.

198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
// Border erstellen
makeBorder($imgWidth,$imgHeight,$im,$colorB);

// Uebermittelter Hash-Wert ueberpruefen
if(!preg_match('/^[a-f0-9]{32}$/',$_GET['codeCaptcha']))
    
$_GET['codeCaptcha'] = md5(microtime());

// Image speichern    
imagepng($im,$captchaDir.'/'.$_GET['codeCaptcha'].'_'.$fileName.'.png');

imagedestroy($im);

// Bild ausgeben
readfile($captchaDir.'/'.$_GET['codeCaptcha'].'_'.$fileName.'.png');
Beispiel 3.15: captcha.php


Unser CaptchaBild ist fertig! Jetzt müssen wir uns noch den Aufruf der CaptchaDatei in unserem Formular und die Überprüfung eines jeden Captchas anschauen. Wir beginnen zuerst mit dem Formular.

Wie Sie sehen, können Sie mit ein paar wenigen Handgriffen das Captcha einbauen und der Besucher wird mit Ihrem Formular arbeiten. Wenn das Formular aufgerufen wird, erstellen wir zuerst eine HashSumme aus der aktuellen Zeit (27). Um wirklich eine fast eindeutige HashSumme zu generieren, werden nicht nur die Sekunden, sondern auch die Mikrosekunden für die HashSumme herangezogen.

Die Wahrscheinlichkeit, dass zwei Menschen zur gleichen Zeit dieses Captcha starten, ist sehr gering. Sie müssten nicht nur in der gleichen Sekunde, sondern auch zur gleichen Microsekunde das Formular starten – ein 6er im Lotto ist da schon wahrscheinlicher.

Anhand der HashSumme und des CaptchaBilds erstellen wir den Dateinamen für das Bild. Wie Sie sehen, beginnt der Dateiname mit der HashSumme, gefolgt von einem Unterstrich und den sechs Buchstaben oder Zahlen, die in diesem Bild angezeigt werden.

4b73f3081a465c95bb4d59108dc43eca_dVeUXh.png

Wir müssen nun in unserem Formular das CaptchaBild anzeigen. Dafür nutzen wir einen ImageTag (28) und geben als Ziel (normalerweise steht hier ein Bildname) die CaptchaDatei an. Zusätzlich übermitteln wir die HashSumme, aus der dann der Dateiname gebildet wird.

Irgendwie muss noch die HashSumme beim Senden des Formulars übermittelt werden. Dafür benutzen wir ein hiddenField (30) – jetzt haben wir alles, was wir brauchen, und das Formular kann gesendet werden.

Nach dem Senden des Formulars wird zuerst überprüft, ob der Besucher das Formularfeld für die CaptchaPrüfung ausgefüllt hat (8). Falls ja, wird die Datei für die CaptchaÜberprüfung inkludiert (10) und das Captcha geprüft. Sie erhalten als Rückgabewert der Überprüfung in der Variable $resultCaptcha entweder „TRUE“ oder „FALSE“. TRUE heißt in diesem Fall, dass die Aufgabe gelöst wurde, FALSE hingegen besagt, dass die Aufgabe falsch war. 86 3 Formulare

Egal, ob die Aufgabe richtig oder falsch war, es wird auf jedem Fall ein neues CaptchaBild mit einer neuen HashSumme erstellt.

01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:

31:
32:
33:
34:
35:
36:
<html>
<head>
<title>Demonstration - Captcha</title>
</head>
<body>
        <!-- Captcha Check Begin -->
        <?php 
        
if(!empty($_POST['stringCaptcha']))
        {
            include_once(
'captcha_check.php'); 
            
            if(
$resultCaptcha)
            {
                
// Alles OK, Daten koennen gespeichert werden
                
echo 'Eingabe korrekt!';
            }
            else
            {
                
// Captcha ist falsch - Fehler ausgeben
                
echo 'Eingabe falsch';
            }
        }
        
?>
        <!-- Captcha Check End -->
    <form name="CaptchaForm" method="post" action="">
       <!-- Captcha Begin -->
       <?php $codeCaptcha md5(microtime()); ?>
       <img src="captcha.php?codeCaptcha=<?php echo $codeCaptcha?>">
       <br>
       <input type="hidden" name="codeCaptcha" value="<?php echo 
              
$codeCaptcha?>">
       <input type="text" name="stringCaptcha">
       <!-- Captcha End -->
       <p><input type="submit" name="Submit" value="Wert prüfen"></p>
    </form>
</body>
</html>

Beispiel 3.16: captcha_demo.php


Sie sehen hier, wie Sie das Captcha z. B. in Ihr Formular einbinden können.




Wir müssen uns jetzt noch die Datei anschauen, die unsere CaptchaDatei überprüft. In dieser Datei müssen Sie ein paar Konfigurationsparameter anpassen. Sie müssen als Erstes das Verzeichnis angeben (82), in dem Ihre CaptchaBilder gespeichert werden.

Vergessen Sie nicht, am Ende den Slash (/) mit anzugeben. Als weiteren Parameter benötigen wir noch eine Zeit in Minuten (85), nachdem alte, nicht gebrauchte Bilder (weil das Formular z. B. nicht abgesendet wurde) wieder gelöscht werden können.

Das Formular inkludiert diese Datei und übermittelt uns dabei zum einen den HashWert und zum anderen das Feld mit den sechs Buchstaben oder Zahlen. Die Funktion CheckCaptcha wird mit diesen Parametern und den beiden Konfigurationsvariablen aufgerufen (88) und erhält als Rückgabewert entweder „TRUE“ oder „FALSE“.

function CheckCaptcha($codeCaptcha,$stringCaptcha,$dir,$delFile=5)
@param string   $codeCaptcha
@param string   $stringCaptcha
@param string   $dir
@param integer $delFile
@return bool

Nachdem die Funktion aufgerufen wurde, setzen wir zuerst unseren Rückgabewert auf „FALSE“ (39). Im nächsten Schritt überprüfen wir unsere HashSumme (42) auf Gültigkeit und im Anschluss daran noch die übermittelte Variable mit den eingegebenen Buchstaben oder Zahlen (42).

Sie fragen sich vermutlich, weshalb wir bei der Überprüfung der Buchstabenlänge (42) nicht auf sechs Stellen prüfen, sondern einen Wert zwischen 16 heranziehen. Im nächsten Beispiel wollen wir das Captcha ja auch Rechenaufgaben erstellen lassen.

Die Lösungen von Rechenaufgaben haben in der Regel aber nur eine oder zwei Stellen. Da wir keine andere Datei für die Überprüfung inkludieren wollen, haben wir uns für diesen Weg entschieden. Das macht die Überprüfungsdatei flexibler, da sie jetzt mit Mathematikaufgaben sowie Buchstaben/ Zahlenkombinationen umgehen kann.

Sollte einer der Parameter nicht unseren Kriterien entsprechen, beenden wir die Funktion und geben „FALSE“ zurück – somit wurde das Captcha nicht gelöst. War die Überprüfung erfolgreich, lesen wir das Verzeichnis mit den CaptchaBildern aus und durchlaufen jede einzelne Datei (50).

Jedes Verzeichnis beginnt mit einem Punkt und einem Doppelpunkt. Da wir hier keine Überprüfung vornehmen müssen, überspringen wir diese Einträge und beenden den aktuellen Durchlauf (51). Genauso verfahren wir mit eventuellen Unterverzeichnissen in diesem Ordner (55).

Falls es sich aber um eine Datei handelt (57), starten wir unsere Routinen für die Überprüfung. Als Erstes überprüfen wir, wie alt die jeweilige Datei ist (57). Wir rechnen die Zeit in Minuten um und erhalten dann die Differenz zur aktuellen Zeit. Ist diese Zeit größer als die von uns vorgegebene Zeit in Minuten, löschen wir die aktuelle Datei (66).

Achtung! Es findet hier keine Überprüfung der Dateiendungen statt. Falls Sie in diesem Ordner noch andere Dateien haben, die keine CaptchaDateien sind, werden diese ebenfalls gelöscht!

Ist die Datei jünger als unser Wert, springen wir in den elseZweig (76) und vergleichen den Dateinamen mit unserem Wert (der HashWert + eingegebenen Wert + Dateiendung) (62). War die Überprüfung erfolgreich, speichern wir den Wert „TRUE“ in unsere Variable (63) – das Captcha wurde gelöst.

Wir müssen aber noch eine andere Überprüfung (65) vornehmen. Falls das Captcha nicht gelöst wurde, müssen wir unbedingt die Datei löschen, die den HashWert beeinhaltet. Sie fragen sich jetzt sicherlich, warum das so sein muss? Die Antwort ist einfach. Wenn ein Bot Ihr Formular ausfüllt und an dem HashWert kommt, schlägt zwar die erste Überprüfung fehl. Der Bot könnte dann mit dem HashWert aber alle fehlenden Kombinationen der sechs Buchstaben oder Zahlen so lange ausprobieren, bis er das Captcha gelöst hat. Das möchten wir natürlich unterbinden und sorgen deshalb dafür, dass das CaptchaBild nur einmal geprüft und danach gelöscht (66) wird.

Wir schließen das VerzeichnisHandle (72) und geben unser Ergebnis (75 oder 77) an die aufgerufene Stelle wieder zurück.

037:
038:
039:
040:
041:
042:
043:
044:
045:
046:
047:
048:
049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:

063:
064:
065:
066:
067:
068:
069:
070:
071:
072:
073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
083:
084:
085:
086:
087:
088:
function CheckCaptcha($codeCaptcha,$stringCaptcha,$dir,$delFile=5) {
    
// Setzt den Check erst einmal auf FALSE
    
$captchaTrue FALSE;
    
    
// Übergebene Hash-Variable überprüfen
    
if(!preg_match('/^[a-f0-9]{32}$/',$codeCaptcha))
        return 
FALSE;
    
    
// Übergebene Captcha-Variable überprüfen
    
if(!preg_match('/^[a-zA-Z0-9]{1,6}$/',$stringCaptcha))
        return 
FALSE;
    
    
$handle = @opendir($dir);
    while (
false !== ($file readdir($handle))){
        if (
preg_match("=^\.{1,2}$="$file)){
       continue;
    }
    
    if (
is_dir($dir.$file)){
       continue;
    }else{
        
$lastTime ceil((time() - filemtime($dir.$file)) / 60);
        if(
$lastTime $delFile){
            
unlink($dir.$file);
        } else{
            if(
strtolower($file) == strtolower($codeCaptcha.'_'.
              
$stringCaptcha.'.png')){
                
$captchaTrue TRUE;
            }  
            if (
preg_match("=^$codeCaptcha=i"$file)){
                
unlink($dir.$file); 
            }
         }
    }
    }    

    @
closedir($handle);

    if (
$captchaTrue)
        return 
TRUE;
    else
        return 
FALSE;

}

// Temporäres Verzeichnis der Captcha-Bilder
$captchaDir 'captchadir/';

// Löschen der alten Captcha-Bilder nach wieviel Minuten
$delFile 10;

// Überprüfung starten
$resultCaptcha CheckCaptcha($_POST["codeCaptcha"],$_POST["stringCaptcha"],$captchaDir,$delFile);
Beispiel 3.17: captcha_check.php


Wie Sie gesehen haben, ist eine Überprüfung möglich. Sie können jetzt das Captcha einbinden oder erweitern. Möglich wäre die Kombination mit einer Rechenaufgabe. Im folgenden Beispiel sehen Sie ein solches Captcha. Es erzeugt wahllos entweder eine Rechenaufgabe oder eine Buchstaben/ Zahlenkombination.

 


Dieses Skript aus dem SELFPHP KOCHBUCH wurde von SELFPHP unter dem "Tarif Mc500" von McAc.net-Webhosting erfolgreich ausgeführt und getestet!

Auf der Übersichtseite unter "McAc.net – Webhosting zu diesem Buch" finden Sie weitere Informationen zu dem Webhostingpaket, dass durch SELFPHP getestet wurde.


 




:: Premium-Partner ::

Webhosting/Serverlösungen


Premium-Partner MECO Systemhaus GmbH & Co. KG
Premium-Partner PSW GROUP GmbH & Co. KG
Premium-Partner BPI-Systeme
Premium-Partner Pixel X
Premium-Partner
 

:: SELFPHP Sponsoren ::


Microsoft Deutschland GmbH
twosteps.net - ...Premium-Webhosting
Sedo - Bei uns wird PHP großgeschrieben
hostfactory.ch - OptimaNet Schweiz AG
ZEND - The PHP Company
Kaspersky Labs
HighText iBusiness
SELFPHP Sponsoren
 

Qozido


© 2001-2009 E-Mail SELFPHP OHG, info@selfphp.deImpressumKontakt