AJAX-Community Wiki
   Wiki über "Asynchronous JavaScripting and XML" und Web 2.0    AJAX ForumAJAX WikiAJAX Bücher
 

Dies ist eine alte Version des Dokuments!


Live-Sicherheitscode basierend auf PHP, JS und MySQL

Ziel dieses Tutorial ist das erzeugen eines sogenannten CAPTCHAs. Das Captcha sollte dynamisch mit PHP erzeugt werden und noch bei der Eingabe soll überprüft werden ob der Code stimmt.

Voraussetzungen:

Kenntnisse: JS
Software: Webserver\PHP\MySQL
Zeitaufwand: kA Stunden
Vorausgesetzte Themen: erste-schritte


Das Backend

Zu allererst soll das Backend mit PHP programmiert werden.

Datenbank

Man benötigt dazu eine Datenbank die die verschiedenen aktuell verwendeten Codes abspeichert.

Dazu müssen wir folgende Datenbank erzeugen

id INT Erhöht sich automatisch
codeVARCHAR Dieser enthält den Code zur jeweiligen ID
TIMESTAMPVARCHARUm veraltete Codes löschen zu können

Dazu einfach folgenden SQL-Code in die Konsole oder PHPMyAdmin einfügen.

CREATE TABLE `sightcodes` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT ,
`code` VARCHAR( 5 ) NOT NULL ,
`TIMESTAMP` VARCHAR( 250 ) NOT NULL ,
PRIMARY KEY ( `id` )
);

Nachdem wir das abgeschlossen haben können wir uns nun dem PHP Script zuwenden.

PHP - Script

Die PHP - Scripts erzeugen nun das Bild und überprüfen auch den Code. Dazu erstellen wir zu allererst folgende Dateistruktur.

  • config.php
  • checkcode.php
  • sichtcode.gif → Das ist ein Ordner den wir sichtcode.gif benennen.
    • index.php
  • img → Ordner

Konfiguration

So nun beginnen wir mit der Datei config.php.
Config.php

<?php
 
//MYSQL Einstellungen
 
	define("HOST", "localhost");  //Hostname der MYSQL Datenbank.
	define("DATABASE", "test");	  //Datenbankname in der die Tabelle ist.
	define("USER", "test");		  //Der Benutzername für die Datenbank.
	define("PASS", "1234");		  //Das Passwort für den darüber angegebenen Benutzer	
 
//Ende MYSQL Einstellungen
 
?>

Das hier sollte eigentlich selbsterklärend sein.

So nun kommen wir zur Erzeugung des Bilds. Wir verwenden den Ordner um dem Browser vorzugaukeln es gäbe auch die richtige FileTyp-Extension (gif). Es würde auch bei direktem Aufruf funktionieren. Allerdings ergibt es so ein besseres Bild.

Bilderzeugung

Zu allererst benötigen wir in dem Ordner eine TTF - Schriftart. Aus dieser erzeugen wir dann das Bild. Verwenden Sie eine etwas verschnörkelte Schrift um ein einfaches Lesen durch eine Maschine unmöglich zu machen. Nennen Sie die Schrift font.ttf und legen Sie die Schriftart in den Ordner sichtcode.gif.

Dannach benötigen wir noch ein Hintergrundbild (200×70), dieses kann mit Streifen durchzogen sein oder einfach nur Weiß sein. Je komplizierter das Hintergrundbild desto schwerer wird es zu lesen. Hier muss ein Mittelweg gefunden werden. Wir nennen es bg.gif und legen es in den Ordner sichtcode.gif.

Nun wenden wir uns dem File index.php zu.

Zu allererst beginnen wir das File und fügen config.php ein.
sichtcode.gif/index.php

<?php
 
require ("../config.php");

Dannach setzen wir den Header für ein GIF Bild.

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

Nun beginnen wir mit dem Erzeugen des Bilds. Wir verwenden die PHP Funktion imagefromgif.

$image=imagecreatefromgif("bg.gif");

Wir laden dabei das Hintergrundbild in den Speicher. Auf diesem Bild können wir nun herummalen.

Nun erzeugen wir zwei Arrays mit all den Zeichen die für das Bild verwendet werden dürfen. Passen Sie auf das keine ähnlich aussehenden Buchstaben verwendet werden. Dazu müssen Sie ihr Font File ansehen.

$letters=array("A","a","B","b","D","d","E","e","F","f","G","g","H","h","I","i","J","j","L","l","M","m","N","n","Q","q","R","r","T","t");
$numbers=array(1,2,3,4,5,6,7,8,9,0);

Nun erzeugen wir das Bild mit einer for-Schleife und der Funktion imagettftext. Ausserdem lassen wir noch die Farbe zufällig ändern.

for($a=1; $a <= 5; $a++ ) {
	if( rand(0,1) == 0) {
		$c=$letters[array_rand($letters)];	
	}else{
		$c=$numbers[array_rand($numbers)];
	}
	imagettftext($image, rand(30,35), rand(-30,30), 30*$a+10, 50, imagecolorallocate($image,rand(50,250),rand(50,250),rand(50,250)), "./font.ttf", $c );
	$code.=$c;
}

Da nun auch wir den code nicht mehr lesen können müssen wir diesen umbedingt noch in die Datenbank schreiben. An den Client senden wäre sinnlos denn dann hätte er ja die Daten. Ausserdem setzen wir noch einen Cookie mit der id aus der Datenbank um später zurückzuprüfen.

mysql_connect( HOST, USER, PASS);
mysql_select_db(DATABASE);
 
 
mysql_query("insert into registrationcode (code,timestamp) values ('$code',".time().") ");
$d=mysql_fetch_assoc(mysql_query("select id from registrationcode where code='$code' "));
setcookie("regid",$d['id'],time()+60*30,"/");
mysql_query("delete from registrationcode where timestamp < '".(time()-60*30)."'");

Zu allerletzt müssen wir das Bild nun an den Client senden.

imagegif($image);
 
?>

Und fertig sind wir mit der Bilderzeugung.

Überprüfung

Wir wenden uns nun der Überprüfung zu. Dazu dient das File checkcode.php. Zuerst initialisieren wir alles und holen uns den COOKIE vom Benutzer.

<?php
 
	require("./config.php");
 
	//Variablen definition
	$status = "0";
	$sql = false;
	$query = false;
	$code = false;
	$id = false;
	//Ende Variablen definition
 
 
	$id = $_COOKIE[regid];

Nun müssen wir uns mit der MySQL Datenbank verbinden um den richtigen Code herauszufinden.

        mysql_connect(HOST,USER,PASS);
	mysql_select_db(DATABASE);	
 
	$sql = "Select code from registrationcode where id = '$id'";
 
	$code=mysql_fetch_assoc(mysql_query($sql));

In der Variable $code haben wir nun den aktuellen code.

Nun überprüfen wir das ganze und löschen den Code aus der Datenbank wenn er stimmt. Stimmt er nicht gibt das Script 0 zurück.

	if($_GET["code"]==$code["code"]){
		$status = 1;
		mysql_query("delete from registrationcode where id = '$id'");
	}
	else{
		$status = 0;
	}
	echo $status;

Nun haben wir auch die Überprüfung fertig. Kommen wir zum Frontend.

Frontend

Wir haben ein File das nennen wir sichtcode.js. Es enthält sämtliche JS - Logik. Zu allererst benötigen wir eine Funktion die das XMLHTTPRequest Objekt erzeugt. Wir nennen die Funktion request().

function request(){	
	try{return new ActiveXObject("Msxml2.XMLHTTP");}catch(e){}
	try{return new ActiveXObject("Microsoft.XMLHTTP");}catch(e){}
	try{return new XMLHttpRequest();}catch(e){}
	return false;
}

Nun machen wir eine Funktion die den Code überprüft.

function checkcode(){
	if(document.getElementById("codeinput").value.length==5){
	//document.getElementById("status").innerHTML =' <img alt="Lädt" src="./img/loader.gif" />';
	url = "./checkcode.php?code="+document.getElementById("codeinput").value;
	http_request = request();	
 
	if (http_request == false){
		alert("Achtung");
		}
	else{
             http_request.onreadystatechange = showanswer;
             http_request.open('GET', url, true);
             http_request.send(null);
		}
	}
}

Natürlich wollen wir auch einen neuen Code erzeugen wenn der User den Code nicht lesen kann.

function newSightCode(){
	cache = Math.random()*100;
	document.getElementById("image").src="./sichtcode.gif?cache="+cache;
}

Dann haben wir noch eine Funktion die die Antwort ausgibt.

function showanswer(){
	var antwort = http_request.responseText;
	if(antwort == 1){
		disable("codeinput",true);
		document.getElementById("status").innerHTML =' <img alt="Richtige Eingabe" height=16 width=16 src="./img/ok.png" />';
		document.getElementById("neu").innerHTML ="";
	} 
	else if(antwort == 0){
		document.getElementById("status").innerHTML = '<img alt="Falsche Eingabe" height=16 width=16 src="./img/false.png"  />';
		}
	else if(antwort == 2){
		disable("codeinput",true);
		document.getElementById("status").innerHTMl='Zu oft versucht bitte reloaden Sie die Site. <\ br> Sicher Sie bitte den Inhalt im Messagetextfeld indem Sie ihn kopieren.';
	}
	else{
			document.getElementById("status").innerHTMl=antwort;
	}
}

Schlussendlich habe ich mir noch eine einfache Funktion geschrieben um ein Element zu deaktivieren.

function disable(element, dis){
	document.getElementById(element).disabled= dis ;
}

Test Seite

Nun habe ich natürlich auch eine kurze Testseite für dich.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Live-Sichtcode</title>
<script type="text/javascript" src="./sichtcode.js"></script>
</head>
<body onLoad = 'disable("codeinput", false);'> 
 
<img id="image" src="./sichtcode.gif" alt="Sichtcode" />
<input type="text" id="codeinput" maxlength="5" onkeyup="checkcode()" />
<span id="status">Bitte gebe den Sichtcode ein.</span><br /> 
 
<a href="javascript: newSightCode()" id="neu">Neuen Sichtcode generieren</a>
 
 
</body>
</html>

Das wars dann einfach einmal ausprobieren.

Integration in ein Service

Um nun das ganze irgendwo zu integrieren muss man natürlich vor der Eintragung der Daten in die Datenbank das ganze nocheinmal überprüfen. Dafür einfach bei checkcode.php das Löschen aus der Datenbank entfernen und folgenden Codeschnippsel bei dir einbauen.

function code($securityid, $eingabe){
 
    //Datenbank öffnen
    $dblink = openDB();    
    //Tabelle öffnen
    $sql = "Select code from registrationcode where id = '$securityid'";
    $code=mysql_fetch_assoc(mysql_query($sql)) or die("Fehler mit der Datenbank");
 
       $sql = "delete from registrationcode where timestamp < '".(time()-60*30)."'";
    $code=mysql_query($sql) or die("Fehler beim Löschen der alten Codes");
 
    if($eingabe == $code['code']){
        $status = 1;
        mysql_query("delete from registrationcode where id = '$securityid'");
    }
    else {
        $status = 0;
    }
    return $status;
}

Auch hier wird wieder ein Status von der Funktion zurückgegeben. Die Funktion openDB muss durch ein Äquivalent ersetzt werden. Ausserdem werden bei diesem Snippet auch alle älteren Codes wieder aus der Datenbank gelöscht.

Erweiterung

Natürlich gibt es hier noch einige Modifikationen

  • Die Bilder die in der Funktion showanswer dargestellt werden in den Ordner img reinkopieren (OK.png, false.png)
  • Die Funktion disable zu verwenden und dein Formular nur dann abschicken lassen wenn der Code stimmt.
 
tutorial/live-sichtcode.1265157872.txt.gz · Zuletzt geändert: 2010/06/21 12:15 (Externe Bearbeitung)
 
Falls nicht anders bezeichnet, ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki