Für ein Projekt, an dem ich zurzeit im Betrieb arbeite, musste ich ein Captcha-System entwickeln, um zu verhindern, dass Bots Kommentare posten können.
In diesem Artikel zeige ich, wie ich dies umgesetzt habe.
Der Header:
<?php session_start(); $_SESSION['count'] = time(); $image; ?>
Im Header der Webseite wird eine Session definiert, welche später für das Captcha benötigt wird.
Das Formular:
echo' <form method="POST" action="'. $_SERVER["REQUEST_URI"] .'" class="kommentar" enctype="multipart/form-data"> <input type="text" name="user" placeholder="Name" id="user" required><br> <input type="email" name="email" placeholder="Mail" id="email" required> <br> <br> <textarea name="comments" id="text" placeholder="Kommentar" cols="30" rows="5" required></textarea> <br> <input type="file" size="50" name="meinBild" class="submit"> <br> <input id="website" name="website" type="hidden" value=""> <input type="hidden" value="1" name="sent" id="sent"> <input type="hidden" id="page_id" name="pageid" value="'. $id .'"> <input type="hidden" id="replyid" name="replyid" value="0"> <div class="capbox""> <img src="../image'. $_SESSION['count'] .'.png"> </div> <input type="text" name="input"> <input type="hidden" name="flag" value="1"/> <br> <input type="submit" value="Submit" name="submit" class="submit"> </form>';
Das Formular wird über ein PHP echo aufgerufen. Das Inputfeld mit der Id “website”, ist von der Sorte “hidden”. Dies ist die erste Stufe des Schutzes gegen Bots. In einer Funktion habe ich definiert, dass sobald dieses Feld ausgefüllt wird, wird der Post nicht in der Datenbank abgespeichert. Da Bots alle Felder ausfüllen, und “Hidden”-Inputfelder nicht sichtbar sind, kann es sich deshalb nur um einen Bot handeln, wenn dieses Feld ausgefüllt ist.
Die zweite Sicherheitsmassnahme befindet sich im “<div>” mit der Klasse “capbox”, und den dazugehörigen Inputfeldern mit den Namen “input” und “flag”.
Wie man sieht, wird der Name des Bildes von der, im Header definierten Session, benannt.
Die Captcha-Funktion:
function create_image()//captcha { global $image; $image = imagecreatetruecolor(200, 50) or die("Captcha Fehler"); $background_color = imagecolorallocate($image, 255, 255, 255); $text_color = imagecolorallocate($image, 0, 255, 255); $line_color = imagecolorallocate($image, 64, 64, 64); $pixel_color = imagecolorallocate($image, 64, 64, 64); imagefilledrectangle($image, 0, 0, 200, 50, $background_color); for ($i = 0; $i < 4; $i++) { imageline($image, 0, rand() % 50, 200, rand() % 50, $line_color); } for ($i = 0; $i < 1000; $i++) { imagesetpixel($image, rand() % 200, rand() % 50, $pixel_color); } $letters = array('Wort1','Wort2','Wort3', 'Noch mehr Wörter');//Words for Captcha //var_dump($lettersa); $letter = $letters[rand(0, count($letters) - 1)]; $text_color = imagecolorallocate($image, 0, 0, 0); $word = ""; for ($i = 0; $i < 1; $i++) { $lettersa = $letters[rand(0, count($letters) - 1)]; imagestring($image, 9, 20 + ($i * 30), 20, $letter, $text_color); $word .= $letter; } $_SESSION['captcha_string'] = $word; $images = glob("*.png"); foreach ($images as $image_to_delete) { @unlink($image_to_delete); } imagepng($image, "image" . $_SESSION['count'] . ".png"); }
Mit dieser PHP-Funktion wird das Captcha-Bild generiert.
Zuerst werden die Farben und Position der zufälligen Pixel und Linien definiert. Im Array “$letters” stehen die Wörter, welche später im Captcha-Bild stehen sollen. Man kann so viele Wörter einfügen, wie man will.
Mit dem For-Loop wird dann ein zufälliges Wort vom Array genommen.
Nach dem Loop wird wird aus dem zufälligen Wort, eine PNG-Datei mit dem Namen der Session, generiert, welches sich löscht und durch ein neues Wort ausgetauscht wird, sobald eine neue Session beginnt.
Das Testen des Captcha:
$headerMethod = $_POST; function test_input($data) { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); return $data; } $newfilename = ""; $flag = 5; if (isset($_POST["flag"])) { $input = $_POST["input"]; $flag = $_POST["flag"]; } if ($flag == 1) { if ($input == $_SESSION['captcha_string']) { if (isset($headerMethod['sent'])) { $filename = $_FILES['meinBild']['name']; $file_basename = substr($filename, 0, strripos($filename, '.')); // get file extention $ext = pathinfo($filename, PATHINFO_EXTENSION); echo $ext; $file_ext = substr($filename, strripos($filename, '.')); // get file name $filesize = $_FILES['meinBild']['size']; $allowed_file_types = array('.png','.gif','.jpg','.PNG','.GIF','.JPG'); $newfilename = 0; if (in_array($file_ext,$allowed_file_types) && ($filesize < 5000000)) { // Rename file $zufallb = md5(rand()); $zufallb = substr($zufallb, 0, -10); $datumb = date("d_n_y_h_i_s_u", time()); $nameb = $zufallb . $datumb; $umtauschb = array('_'); $ersetzb = array('','',''); $newfilename = str_replace($umtauschb, $ersetzb, $nameb); $newfilename = $newfilename . $ext; if (file_exists('./upload/' . $newfilename)) { // file already exists error //echo 'You have already uploaded this file.'; } else { move_uploaded_file($_FILES['meinBild']['tmp_name'], './upload/' . $newfilename); //echo 'File uploaded successfully.'; } } elseif (empty($file_basename)) { echo "Fehler ist aufgetreten"; $newfilename = ""; // file selection error //echo 'Please select a file to upload.'; } elseif ($filesize > 5000000) { // file size error //echo 'The file you are trying to upload is too large.'; echo "Bilddatei ist zu Gross"; $newfilename = ""; } /*else { // file type error echo 'Only these file typs are allowed for upload: ' . implode(', ',$allowed_file_types); unlink($_FILES['meinBild']['tmp_name']); }*/ if ($headerMethod["website"] !== "") {//if field website is filled -> user is bot (or hacker) echo "<h1>Du bist ein Bot!<br> You're a bot<br> Oe makou he Bot<br> Ты Bot<br> तुम एक बॉट कर रहे हैं </h1>"; } else{ $name = $headerMethod['user']; $mail = $headerMethod['email']; $text = $headerMethod['comments']; $page_id = $headerMethod['pageid']; $reply_id = $headerMethod['replyid']; $name = test_input($name); $mail = test_input($mail); $text = test_input($text); $commentController->create($name, $mail, $text, $page_id, $reply_id, $newfilename); $page = $_SERVER['REQUEST_URI']; $sec = "0"; header("Refresh: $sec; url=$page"); } } } else { ?> <div style="text-align:center;"> <h1>Captchacode ist falsch!<br>Bitte nochmals versuchen.</h1> </div> <?php create_image(); } } else { create_image(); }
Die Variable “$flag” wird zu Beginn den Wert 5 zugeschrieben.
Falls das Formular abgesendet, und das Inputfeld “flag” geschickt wird, dann wird “$flag” zum Wert 1 geändert und das eingegebene Captcha als “$input” gespeichert.
Wenn dann “$flag” den Wert 1 hat, wird dann die Funktion ausgeführt, welche dazu dient, den Kommentar in die Datenbank zu speichern und die gesendete Bilddatei zu überprüfen.
Während dieser Funktion Wird dann der Header aktualisiert, was zu einer neuen Session führt. Nach dem Beginn der neuen Session wird dann ein neues Captcha-Bild generiert.